-
Notifications
You must be signed in to change notification settings - Fork 1
Home
Table of contents generated with markdown-toc
BlackBox
is a Groovy
AST transformation that adds logging code into annotated methods.
@BlackBox
Annotation adds logging code into annotated Groovy methods/constructors.
Detalization is controlled using level
annotation parameter:
-
BlackBoxLevel.METHOD
- to log each method call with its arguments -
BlackBoxLevel.ERROR
- only to log unhandled method exceptions (including associated method arguments as well).
Logging is one of the most important parts of modern applications.
Its significance only increases in case of:
- Financial environments (consider
PCI-DSS
and sensitive data logging) - Cloud environments (consider logging to
Logstash
) - GDPR
Some scenarios when logging is useful include:
- Network data exchange (TCP, HTTP, SOAP, REST)
- Periphery communication (Bluetooth, serial port, USB, etc)
- IOT (I2C, SPI)
- Automotive communication (Canbus and its implementations)
Historically there exists a methodological gap in terms of approach and best practices for logging integration into User code as well as its automation.
In short there is no set of rules helping programmers to understand:
- What to log
- How to structure the log data
- When to log
- Where to place logging code in the application
- How log can be used on Test and Production environments
- Why spend time writing logging code
When it comes to automation of logging in Java and Groovy, there are not too many features:
-
Groovy
provides annotations (@Slf4j
, etc) to inject log variable declaration and initialization - Same applies to
Lombok
That saves just a couple of lines of code. But there is no real way to inject the actual logging code into the application. Programmers have to manually place lines with logging leading to unwanted results:
- Cluttering the real code base with logging code
- Unstructured and verbose log output
- Chances of misplacing the logging code and missing important output
- Increase of development time and costs
BlackBox
helps to address the key questions:
- What to log:
- 2 levels of injected logging code:
- Method exceptions (with arguments causing exception)
- Method execution (with method arguments, result and exceptions)
- Compile-time metadata:
- Line numbers in debug messages
- 2 levels of injected logging code:
- How to structure the log data
- Log data is automatically structured into text files according to BlackBox format
- Where to place logging code in the application
- Simply add
@BlackBox
annotation to the method or class - and the job is done. No need to clutter the actual code with logging lines.
- Simply add
- How log can be used on Test and Production environments
- Issue investigation & debugging
- Performance profiling and optimization
- Statistics
- Analytics
- Monitoring
- Telemetry
- Journaling
- Why spend time writing logging code
- No more time need to be spent!
Logging
is a process of saving structured data on a permanent storage with assumption that it may be used in future.
However it is neither known how and when this data will be used neither it is guaranteed that this data is useful.
Loggers
is a library that provides an API to save log data.
BlackBox
is using Slf4j
Logger API.
Logger
does not define neither the structure itself nor API of structuring the log data.Logger
defines only the output format of log record (such as timestamp, message and thread information), while the input data comes in its final form from outside of the logger.
Example Loggers
are:
- Log4J
- Logback
- Others
Check out Bobbin - an
Slf4j
logger great for its simplicity and performance.
@BlackBox
annotation is applicable to:
- Classes (has same effect as when all methods and constructors in the class are annotated with same annotation)
- Methods (allows to override
BlackBox
Class level on individual methods) - Constructors
There are scenarios when it is needed to log exception but suppress (ignore) it without re-throwing. For example when when using User Scripts or in Thread body methods.
In these scenarios @BlackBox
annotation supports parameter suppressExceptions
that automatically prevents re-throwing of the exception:
@BlackBox(level = BlackBoxLevel.METHOD, suppressExceptions = true)
String foobar(String foo) {
String bar = "bar"
String foobar = foo + bar
return foobar
}
Above example will be equivalent to:
@io.infinite.blackbox.BlackBox(level = io.infinite.blackbox.BlackBoxLevel.METHOD, suppressExceptions = true)
public java.lang.String foobar(java.lang.String foo) {
java.lang.Object resultPlaceHolder
blackBoxRuntime.methodBegin(new io.infinite.blackbox.MethodMetaData('Foobar', 'foobar', 8, 13, 1, 2), ['foo': foo ])
try {
java.lang.String bar = 'bar'
java.lang.String foobar = foo + bar
return resultPlaceHolder = foobar
}
catch (java.lang.Exception automaticException) {
blackBoxRuntime.methodException(new io.infinite.blackbox.MethodMetaData('Foobar', 'foobar', 8, 13, 1, 2), ['foo': foo ], automaticException)
}
finally {
blackBoxRuntime.methodResult(new io.infinite.blackbox.MethodMetaData('Foobar', 'foobar', 8, 13, 1, 2), resultPlaceHolder)
blackBoxRuntime.methodEnd(new io.infinite.blackbox.MethodMetaData('Foobar', 'foobar', 8, 13, 1, 2))
}
}
BlackBox is hosted in JCenter via Bintray:
...
repositories {
jcenter()
}
...
compile 'io.infinite:blackbox:2.2.0'
...
BlackBox annotation is applicable to Classes, Methods and Constructors:
@Grab('io.i-t:blackbox:2.2.0')
@Grab('io.i-t:bobbin:4.0.4')
import io.infinite.blackbox.BlackBox
import io.infinite.blackbox.BlackBoxLevel
class Foobar {
@BlackBox(level = BlackBoxLevel.METHOD, suppressExceptions = true)
String foobar(String foo) {
String bar = "bar"
String foobar = foo + bar
return foobar
}
}
new Foobar()