Last updated: 18-December-2023
Tracelogger

Keywords

  • Thread-Local Variables
  • Concurrency APIs
  • JUnit 5
  • Maven (Surefire Plugin)
  • Java Microbenchmark Harness (JMH)
  • Java API for XML Processing (JAXP)
  • W3C Document Object Model (DOM) API
  • Generics
  • LogBack
  • Log4j2
  • Java Logging API
  • Java I/O API

Brief Overview

Where advisable, the library uses thread-local variables to store relevant state specific to a particular thread. E.g. a QueueTracer which has been retrieved using takeTracer() is subsequently available via getCurrentQueueTracer() by the calling thread. Under the hood getCurrentQueueTracer() uses a thread-local variable to provide the QueueTracer until the last pop enqueues it again. Alternatively, instances of ConcurrentMap<Long,​V> have been applied for similar use cases where the use of thread-local variables is not sufficient. Here the type parameter Long represents the thread id. A Reentrant mutual exclusion Lock is used to synchronize access to the underlying TracePrintStream. Read-Write locks are employed to facilitate configuration changes on-the-fly (experimental feature).
The unit tests are implemented by using JUnit5 and are executed during the build by the Maven Surefire Plugin. A certain unit test class is dedicated to perform benchmarks using JMH. Several test cases are using thread pools created by the factory methods of the Executors class to generate load.
The Java API for XML Processing is used to evaluate the XML tracing-configuration by obtaining a DOM instance. The DOM instance will be validated against a XML schema.
QueueTracers may come in different flavors, e.g. QueueFileTracers or QueueNullTracers. In order to avoid code duplication and simultaneously providing a uniform interface to all the different tracers the QueueTracers are declared as follows:
class QueueTracer<T extends AbstractTracer> extends AbstractTracer {...}
class QueueFileTracer extends QueueTracer<FileTracer> {...}
class QueueNetTracer extends QueueTracer<NetTracer> {...}
class QueueNullTracer extends QueueTracer<NullTracer> {...}
That is a QueueTracer is a AbstractTracer and delegates calls to the exposed interface to a member of type T extends AbstractTracer.
The library provides adapters to external logging libraries, e.g. LogBack and Log4j2.
An important feature is the usage of polymorphic IndentablePrintStreams. An IndentablePrintStream itself is a derived PrintStream with some additional (abstract) methods required for indented prints (and synchronization). The classes TracePrintStream and NullPrintStream are both implementing IndentablePrintStream's abstract methods. Whereas instances of TracePrintStream are used for cases where actual output is required, instances of NullPrintStream are used when the given prints should be discarded, e.g. if the stack size exceeds the configured limit. The NullPrintStream overwrites all inherited methods with empty method bodies. That is the Java Virtual Machine is able to optimize calls to those empty methods away by inlining them. The overall performance impact of tracing statements in the case of disabled tracing should therefore be minimal.
imprint