GhostWriter
About
Runtime implementation for ghostwriter-api that provides application flow tracing of your application. The traced data is sent to either the standard System.out (default) or to an SLF4J handler.
The primary goal of the tracer runtime is to help you preserve your sanity when it comes to figuring out production environments or in situations when you don’t have access to a debugger.
Overview
To summarize what it does, lets take the before/after output of a simple FizzBuzz implementation.
After
Using GhostWriter, the tracer runtime (ghostwriter-rt-tracer) and the SLF4J writer (ghostwriter-tracer-slf4j), with a TRACE level configuration for SLF4J.
As shown on the picture, the complete flow of your application is captured by just adding the dependencies.
Getting started
First, you need to compile your application with GhostWriter. For details on how to do that, check the README. With that step done, all that remains is to use the correct dependencies at runtime. To use the SLF4J or other custom handlers you need to put the corresponding implementation on the classpath and the GhostWriter API calls that get instrumented into you code will load it using a ServiceLoader.
The SLF4J implementation uses the TRACING level for outputting serialized events. The source of the LOG events will be the class that got called (and not a GhostWriter class), so you can rely on your application’s existing LOG configurations to set what to log and at which level.
Maven
The complete, working example describe in this section can be found here.
To add tracing to your application with Maven, you need to add a runtime dependency for ghostwriter-rt-tracer. With this single step, your application should dump the tracing information to the standard output (System.out).
<dependency>
<groupId>io.ghostwriter</groupId>
<artifactId>ghostwriter-rt-tracer</artifactId>
<version>0.5.0</version>
<scope>runtime</scope>
</dependency>
SLF4J writer
In order to use the SLF4J writer component of ghostwriter-rt-tracer, add the following dependency as well.
<dependency>
<groupId>io.ghostwriter</groupId>
<artifactId>ghostwriter-rt-tracer-slf4j</artifactId>
<version>0.5.0</version>
<scope>runtime</scope>
</dependency>
Don’t forget, to see the tracing output, you need to configure the appropriate SLF4J log level.
Gradle
The complete, working example describe in this section can be found here.
To add tracing to your application with Gradle, you need to add a runtime dependency for ghostwriter-rt-tracer. With this single step, your application should dump the tracing information to the standard output (System.out).
runtime "io.ghostwriter:ghostwriter-rt-tracer:0.5.0"
SLF4J writer
In order to use the SLF4J writer component of ghostwriter-rt-tracer, add the following dependency as well.
runtime "io.ghostwriter:ghostwriter-rt-tracer-slf4j:0.5.0"
Don’t forget, to see the tracing output, you need to configure the appropriate SLF4J log level.
Extending
The ghostwriter-rt-tracer module provides a default string serialization and output strategy. In order to override the default behaviour custom implementations of the relevant interfaces should be provided. The ghostwriter-rt-tracer uses the service loader pattern and will use the first implementation found on the classpath.
Custom serializer
To provide your own serialization logic for each specific trace event, just create an implementation for the TracerSerializer interface provided by the ghostwriter-rt-tracer JAR.
public interface TracerSerializer {
String entering(Object source, String method, Object... params);
String exiting(Object source, String method);
String valueChange(Object source, String method, String variable, Object value);
String returning(Object source, String method, Object returnValue);
String onError(Object source, String method, Throwable error);
}
To start using it, you need to package it into a standalone JAR, that conforms to the ServiceLoader requirements. A service provider is identified by placing a provider-configuration file in the resource directory META-INF/services.
In the current case this means providing a file called io.ghostwriter.rt.tracer.serializer.TracerSerializer in your src/main/META-INF/services folder, where the contents of the file correspond to the fully qualified name of your implementation.
Now that your JAR is ready, you just need to specify it as a runtime dependency for your application and the ghostwriter-rt-tracer component will use it.
Custom writer
This is the provided extension point in case you want to dump the tracing information in a different way, for example to a service instead of a log file. The ghostwriter-rt-tracer-slf4j module itself is a concrete example for providing a custom writer.
The first step is to provide an implementation of TracerWriter interface provided by the ghostwriter-rt-tracer JAR.
public interface TracerWriter {
void writeEntering(Object source, String method, Object... params);
void writeReturning(Object source, String method, Object returnValue);
void writeExiting(Object source, String method);
void writeValueChange(Object source, String method, String variable, Object value);
void writeError(Object source, String method, Throwable error);
}
From here on, you need to follow the same packaging steps/requirements outlined in the Custom serializer section, where the main difference being the service-provider configuration.
For a custom writer, you need to provide a file called io.ghostwriter.rt.tracer.writer.TracerWriter in your _src/main/META-INF/services folder, where the contents of the file correspond to the fully qualified name of your implementation.
You can start using your new custom writer by adding your JAR as a runtime dependency for your application and the ghostwriter-rt-tracer component will use it.