Logging and Tracing in Timoni
Overview
Logging and tracing are essential practices in software development for monitoring, debugging, and understanding the behavior of applications. In the Timoni project (https://github.com/stefanprodan/timoni), logging and tracing mechanisms are employed to provide valuable insights into the application’s execution.
Logging
Logging Formats
Timoni uses the popular Logback library (https://logback.qos.ch/) for logging, which supports various formats, including:
- Simple: A plain text format with a minimal set of information.
- Pattern: A customizable format using placeholders and patterns.
Log Levels
Log levels help categorize the importance and severity of log messages. Timoni supports the following log levels (in descending order of severity):
- ERROR: Indicates an error or exception.
- WARN: Warns about potential issues or non-critical errors.
- INFO: Provides informational messages about the application’s state.
- DEBUG: Contains detailed debugging information.
- TRACE: Includes fine-grained, low-level debugging information.
Example Logging Configuration
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.encoder.ConsoleEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
public class LoggingConfig {
public static void main(String[] args) {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
// Set up the console appender
ConsoleEncoder encoder = new ConsoleEncoder();
encoder.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
PatternLayout layout = new PatternLayout(encoder.getPattern());
ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<>();
consoleAppender.setEncoder(encoder);
consoleAppender.setLayout(layout);
// Set up the root logger
Logger rootLogger = context.getLogger(LoggingConfig.class);
rootLogger.setLevel(Level.INFO);
rootLogger.addAppender(consoleAppender);
// Set up the application logger
Logger appLogger = context.getLogger("com.example.myapp");
appLogger.setLevel(Level.DEBUG);
appLogger.addAppender(consoleAppender);
context.start();
}
}
Tracing
Tracing Tools
Timoni uses the Micrometer library (https://micrometer.io/) for tracing, which supports various tracing backends, including:
- Jaeger: A distributed tracing system.
- Zipkin: Another distributed tracing system.
Example Tracing Configuration
import io.micrometer.tracing.Tracing;
import io.micrometer.tracing.Trace;
import io.micrometer.tracing.propagation.TraceContext;
public class TracingConfig {
public static void main(String[] args) {
// Initialize Micrometer and set up the Jaeger tracing backend
Tracing.getTracer("com.example.myapp");
// Create a new trace
Trace trace = Tracing.getTracer("com.example.myapp").trace("example-trace");
try (Trace.Span span = trace.startSpan("example-span")) {
// Perform some work here
// Set a custom tag
span.tag("example-tag", "example-value");
// Log an event
span.logEvent("example-event", new Object[]{"example-key", "example-value"});
// Add a child span
Trace.Span childSpan = trace.trace("example-child-trace").startSpan("example-child-span");
childSpan.close();
// Complete the parent span
span.close();
}
}
}
Conclusion
Logging and tracing are crucial practices for monitoring, debugging, and understanding the behavior of applications. In the Timoni project, Logback is used for logging, and Micrometer is used for tracing, providing various formats, log levels, and tracing backends.