Giter VIP home page Giter VIP logo

echopraxia's Introduction

mvnrepository License Apache

Echopraxia

Echopraxia is a Java logging API designed around structured logging.

What this means is that all arguments in a logging statement have a name and a value, for example:

logger.info("arg1 is {} and arg2 is {}", fb -> fb.list(
  fb.string("name", "value"),
  fb.number("age", 13)
));

writes out in logfmt as:

INFO 13.232 arg1 is name=value and arg2 is age=13

and in a JSON format as:

{
  "message": "arg1 is name=value and arg2 is age=13",
  "name": "value",
  "age": 13
}

What makes Echopraxia effective -- especially in debugging -- is that you can define your own mappings, and then pass in your own objects and render complex objects. For example, we can render a Person object:

Logger<PersonFieldBuilder> logger = LoggerFactory.getLogger(getClass(), PersonFieldBuilder.instance());

Person abe = new Person("Abe", 1, "yodelling");
abe.setFather(new Person("Bert", 35, "keyboards"));
abe.setMother(new Person("Candace", 30, "iceskating"));

logger.info("{}", fb -> fb.person("abe", abe));

And print out the internal state of the Person in both logfmt and JSON.

INFO 13.223 abe={Abe, 1, father={Bert, 35, father=null, mother=null, interests=[keyboards]}, mother={Candace, 30, father=null, mother=null, interests=[iceskating]}, interests=[yodelling]}

Echopraxia also has a "contextual" logging feature that renders fields in JSON:

var fooLogger = logger.withFields(fb -> fb.string("foo", "bar"));
fooLogger.info("This logs the 'foo' field automatically in JSON");

And has conditional logging based on fields and exceptions using JSONPath:

Condition c = (level, ctx) ->
    ctx.findString("$.exception.stackTrace[0].methodName")
        .filter(s -> s.endsWith("Foo"))
        .isPresent();
logger.error(c, "Only render this error if method name ends in Foo", e);

There is also a feature to change logging conditions dynamically using scripts.

Migration to 3.0

There are some changes in 3.0.x which require migration:

  • Logger<?> is no longer valid -- you must now specify Logger<SomeFieldBuilder> as there is no lower bound on wildcards.
  • You must add Logback or Log4J2 library dependencies explicitly (Echopraxia no longer pulls in Logback 1.2 or Log4J2 for you). Please see the installation page for details.
  • If you are extending or implementing a logger, the classes for abstract loggers and logger support have been moved to the spi package.
  • The default for all primitive (string, number, boolean) methods in FieldBuilder is now keyValue, you can override in your own field builder with fb.value as appropriate.
  • There is no Field.ValueField or Field.KeyValueField class any more, only Field interface.

Documentation

Please see the online documentation.

Examples

For the fastest possible way to try out Echopraxia, download and run the JBang script.

Simple examples and integrations with dropwizard metrics and OSHI are available at echopraxia-examples.

For a web application example, see this Spring Boot Project.

Scala API

There is a Scala API available at https://github.com/tersesystems/echopraxia-plusscala.

Benchmarks

Benchmarks are available at BENCHMARKS.md.

echopraxia's People

Contributors

wsargent avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

wsargent

echopraxia's Issues

Add a test for script compilation thread safety

Somehow a call can have a void return type, which means that calling call.bool() can fail. Need to check for the return type and not call bool() if it doesn't have the right return type.

str.starts_with?(fields[:request_remote_addr], "127")

Better Value API

Using Value<List<Field>> etc rather than using ArrayValue is obscure and doesn't really help anything.

Also, Field.Valuerather than just Value is a bit odd.

Async processing

Executing conditions could be arbitrarily expensive.

Especially for statement logging which is a side effect, there's no reason we can't make this async and take the load off the rendering thread.

Either use CompletionStage API:

AsyncCondition asyncCondition = (level, context) -> CompletableFuture.completedFuture(true);
logger.info(asyncCondition, "Message {}", fb -> ...);

or offload it using an executor:

logger.withExecutor(executor).withCondition(condition).info("Message {}", fb -> ...);

Obviously predicates wouldn't work in this model:

if (logger.isDebugEnabled(condition)) {
   ???
}

Instead you'd need to do something like:

logger.isDebugEnabled(condition).thenRun(() -> logger.debug("foo")); // rendering thread
logger.isDebugEnabled(condition).thenRunAsync(() -> logger.debug("foo")); // condition's thread

Might need a special logger to do this if we extend it to predicates and builders.

Obviously the logging statement itself would occur in a different thread at this point, as it would be post condition. Also anything involving thread-local storage / servlets would need special handling. This would require special-case MDC/NDC handling as well. :-(

UserFunction through scripts is slow

If the find methods go through a script, something is making it much slower than if being called directly.

Benchmark                                      Mode  Cnt     Score     Error  Units
ScriptingBenchmarks.testFileConditionFail      avgt    5  4379.959 ± 579.831  ns/op
ScriptingBenchmarks.testFileConditionMatch     avgt    5  4610.075 ± 147.281  ns/op
ScriptingBenchmarks.testStringConditionFail    avgt    5  4649.784 ±  87.629  ns/op
ScriptingBenchmarks.testStringConditionMatch   avgt    5  4262.437 ± 191.742  ns/op
ScriptingBenchmarks.testWatchedConditionFail   avgt    5  5242.896 ±  93.665  ns/op
ScriptingBenchmarks.testWatchedConditionMatch  avgt    5  4700.055 ±  87.745  ns/op

See #129

Structured arguments in MDC

Hey,

would it be possible to put structured arguments optionally into the MDC?

Maybe my use case is a bit special: I am using Quarkus and there you cannot easily replace jboss-logmanager with logstash, which makes everything a bit of a pain. Additionally, I want to post log entries via gelf/fluent to elastic and there is a gelf plugin for Quarkus, which includes everything put into the MDC.

I know I can write my own wrapper or interceptor, but really would like to keep the nice field builders from Echopraxia.

Make extending Logger<> easier

  • Account for NeverLogger, including defaults for null ops
  • Provide better defaults for the with methods
  • Provide a single constructor method for instantiating new MyLogger

compatibility issue when upgrade to 2.3.0

There was a problem when upgrading to version 2.3.0. Initially, version 2.2.4 was used and the system was working fine. However, after upgrading to version 2.3.0, the system could not start and an error message appeared stating "java.lang.ClassNotFoundException: org.slf4j.impl.StaticLoggerBinder". Upon investigation, it was discovered that version 1.4.6 of logback was being used in the system, and this version does not have the class "org.slf4j.impl.StaticLoggerBinder". Is this a compatibility issue introduced by version 2.3.0? Can it be fixed?

Allow conditions on statement to use statement fields

It's worth the cost of evaluating a field builder function if the condition is explicitly on the statement. Running through fields isn't the same as actually logging it, and the implication is that the condition is important enough to carry through.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.