Skip to content

Freqently Asked Questions

Is this a replacement for SLF4J and/or Log4J?

Echopraxia is not a replacement for SLF4J. It is not an attempt to compete with Log4J2 API, JUL, commons-logging for the title of "one true logging API" and restart the logging mess. SLF4J won that fight a long time ago.

Echopraxia is a structured logging API -- it gives the user the ability to provide structured input directly from the application. It is an appropriate solution when you control the logging implementation and have decided you're going to do structured logging output, e.g. a web application where you've decided to use logstash-logback-encoder.

SLF4J is an appropriate solution when you do not control the logging output, e.g. in an open-source library that could be used in arbitrary situations by anybody.


Echopraxia is best described as a specialization or augmentation for application code -- as you're building framework support code for your application and build up your domain objects, you can write custom field builders, then log everywhere in your application with a consistent schema.

Why Structured Logging?

Structured logging enables logs to be queried as semi-structured data. There are other structured logging frameworks, like Structlog (Python), Ruby-Cabin (Ruby), Logrus (Go), and Serilog (C#).

Ruby-Cabin has the best take on this:

Structured data means you don't need crazy regular expression skills to make sense of logs.

From a logging API perspective, structured logging is interesting because it is composable -- structured data can be added to a logger and build up context. You can read more about structured logging here.

Why Conditions?

Conditions address the challenge of "whether-to-log", which concerns with dynamically adjusting the degree of logging in response to the runtime requirements. A statement is only logged if it passes the condition associated with it.

Conditions can leverage the data exposed by structured logging. For example, here's a debug statement that only logs if the remote address is localhost:

Condition isLocalhost = (level, ctx) -> ctx
    .map(s -> Objects.equals(s, ""))
logger.debug(isLocalhost, "address is {}", fb -> fb.string("request_remote_addr", addr));

This makes targeted logging far more powerful, because diagnostic logging is no longer an "all or nothing" proposition -- conditions can dynamically filter what is logged, creating a "control plane" for logging. A proof of concept of dynamic debug logging using Echopraxia is here .

A Comprehensive Survey of Logging in Software and The Bones of the System: A Study of Logging and Telemetry at Microsoft are great discussions of the implication of being able to adjust logging conditions at runtime.