User Manual

Default behavior

When you place @Log annotation on a class, aspect4log will log execution of every method and constructor in it. When you place @Log annotation on a method or constructor you override all parameters of @Log annotation on this class. Default behavior is the following:

  • Indent logging is on.
  • Log level for method/constructor enter and successful return is DEBUG.
  • Log level for checked exceptions is WARN, stack trace is not printed.
  • Log level for unchecked exceptions is ERROR, stack trace is printed.
  • All arguments are logged. All argument objects are converted to string by calling a toString() method, ',' is used as a separator.
  • Result object is logged. It is converted to string by calling toString() method.
  • Thrown exception is logged. It is converted to string by calling toString() method.
  • MDC key and template are not set.
@Log
public class OrderService {
...
}

Controlling Indent

By default indent logging is on and each nested method call is logged with an indent.

An example of how log might look like with indent on:

21:24:16 DEBUG r.Robot : ↓start()
21:24:16 DEBUG r.Robot : ↓      readConfiguration(/path/to/configuration)
21:24:16 DEBUG r.Robot : ↑      readConfiguration(/path/to/configuration) → Configuration(ttl=4000,numbersOfCpuToUse=1)
21:24:16 DEBUG r.Robot : ↓      launch(Configuration(ttl=4000,numbersOfCpuToUse=1))
21:24:16 DEBUG r.Robot : ↑      launch(Configuration(ttl=4000,numbersOfCpuToUse=1))
21:24:16 DEBUG r.Robot : ↑start()

To control it use indent attribute of @Log annotation. In case you want to log a method which is using recursion you may consider to disable indent.

@Log(indent=false)
public List<Item> recursiveItemSearch(Item itemExample){
        //... seach code goes here ...
        return recursiveItemSearch(itemExample);
}

In case use you want to use a Logger to add additional messages to the log with current indent level, instantiate logger via LoggerFactory.

Method enter and exit log levels

There are cases when you want to switch a log level for a method/constructor enter/exit from the default DEBUG level. Some of these cases are:

  • Method is often executed and the details of execution are interesting only during tracing. In this case set enter and the log levels to TRACE.
  • Method invocation is important, e.g user authentication. In this case we set enter and exit log levels to INFO.
  • Recursive method invocation. In this case you may prefer to set enter, exit, and exception log levels to NONE.

Here is an example of how to set log levels of the particular method to NONE:

@Log(enterLevel=Level.NONE, exitLevel=Level.NONE, on=@Exceptions(level=Level.NONE))
public List<Item> recursiveItemSearch(Item itemExample){
        //... here could be search code ...
        return recursiveItemSearch(itemExample);
}

Exception log levels

There are cases when you want to switch from the default exception log levels, some of such cases are:

  • An exception is a part of business logic. In this case you might want to log this exception with INFO level.
  • An exception is checked but it is an error and you might like to log it with ERROR level.
  • An exception is runtime but it is not an error case (e.g authentication or authorization exceptions), you might want to log it with WARN level.
@Log(on = {@Exceptions(exceptions = {RuntimeException.class}),
                  @Exceptions(exceptions = {PaymentException.class,SecurityException.class}, level=Level.WARN)})
public void pay(Customer customer, Order order, String cardNumber) throws SecurityException, PaymentException {
...
}

Stack trace

Stack trace printing is very useful when something unexpected happens. By default a stack trace is printed for runtime exceptions and not printed for checked exceptions. To change this behavior use stackTrace attribute of @Exceptions annotation.

@Log(on = {@Exceptions(exceptions = {RuntimeException.class}, stackTrace = true),
          @Exceptions(exceptions = {PaymentException.class,SecurityException.class}, level=Level.WARN, stackTrace = false)})
public void pay(Customer customer, Order order, String cardNumber) throws SecurityException, PaymentException {
...
}

Customizing arguments and result templates

By default all arguments and result are logged by calling toString() method. There are cases when you may want to customize what is logged. Some of these cases are:

  • The information should not appear in a log. E.g. credit card number or user's password should never be logged.
  • The string representation of an object is too long. E.g. toString() of a very large array, collection or StringBuffer are rare candidates for logging.
  • In some cases you may want to add comments to a arguments.

In order to control arguments and result log representation you may change @Log.argumentsTemplate @Log.resultTemplate and @Exceptions.template default values. For each of those attributes the corresponding context variables are available:

  • $args is available at @Log.argumentsTemplate. It represents arguments array and allows access arguments by index. E.g. $args[0],$args[2] will print first and third arguments separated ','.
  • $result representing the returned value is available at @Log.resultTemplate. E.g. $result.name will print a value of the property 'name' of the resulting object.
  • $exception is available to @Exceptions.template. E.g. $exception.message will print a value of property 'message' of a thrown exception.
@Log(argumentsTemplate = "customerId=${args[0].id}", resultTemplate = "orderId=${result.id}")
public Order createOrder(Customer customer, String address, Item... items){
...
}

Mapped Diagnostic Context

Mapped Diagnostic Context aka MDC support is a very important feature of slf4j and underlying logging systems such as logback and log4j. During concurrent program execution there maybe several threads executing the same method simultaneously. The log will be written in the order of execution in time, to distinguish one thread from another you can place an MDC key to a thread specific value. To analyze log use utility like unix grep to extract log lines with the specific MDC key value. E.g. customerId is a reasonable candidate for the MDC key.

@Log( mdcKey = "customerId", mdcTemplate = "${args[0].id}")
public Order createOrder(Customer customer, String address, Item... items){
...
}

Customizing Logging Decoration

Log decorations are can be configured via aspect4log.xml and aspect4log-test.xml placed in root of a classpath. If aspect4log-test.xml is found in classpath, it is used instead of aspect4log.xml. Usually you will place aspect4log-test.xml in to maven src/test/resources folder, while aspect4log.xml is placed to src/main/resources.

The parameters that may be changed are:

  • useIndent - defines if the indent logging is ON globally, the default value is true
  • indentText - defines the indent text, tab symbol is default value
  • methodEnterSymbol - defines the method enter symbol, the default value is ↓
  • methodSuccessfulExitSymbol - defines the method successful exit symbol, the default value is ↑
  • methodThrownExceptionExitSymbol - defines the method thrown exception exit symbol, the default value is ↑
  • returnedValueSeparator - defines the returned value separator, the default value is →
  • thrownExceptionSeparator - defines the thrown exceptions separator, the default value is ⇒
  • elementsDelitmiter - defines the collection and array elements delimiter, the default value is ,
  • mapKeyValueDelimiter - defines the map key value delimiter, the default value is =
  • arrayBeginsBracket - defines the array opening bracket, the default value is [
  • arrayEndsBracket - defines the array closing bracket , the default value is ]
  • iterableBeginsBracket - defines the iterable begins bracket, the default value is {
  • iterableEndsBracket - defines the iterable ends bracket, the default value is }
  • undefindedToStringMethodSymbol - defines what to print in case toString() is undefined, the default value is not set, in this case the default toString() will value will be printed. Some peoples prefer to use "¿" symbol to have cleaner logs. Note: there are cases when it is needed to use default toString(). When you need to see if two logged objects refer the same object it is better to leave undefindedToStringMethodSymbol undefined.
  • errorEvaluatingToStringSymbol - defines a symbol indicating that an exception was thrown during toString() evaluation. The default value is a biohazard symbol "☣" (the symbol hints that a runtime exception in a toString() method may be a sign of an error in the genetic code of a programmer).
  • nullSymbol - defines how to print null value. The default value is not set, and the null will be printed as null. However many prefer to use Ø symbol.

Make sure that your logging framework uses UTF8, see how it is done with logback in our sample project in the quick start sections.

In case you want to alter default settings, download file aspect4log.xml , change required values and place it to your classpath.

It is worth mentioning that some old operating system do not support UTF8 in console or even IDE (i.e. they don't have unicode fonts). In this case it is recommend to use an alternative aspect4log.xml that do not use unicode symbols.