Logging system
Karaf provides a powerful logging system based on OPS4j Pax Logging.
In addition to being a standard OSGi Log service, it supports the following APIs:
- Apache Commons Logging
- SLF4J
- Apache Log4j
- Java Util Logging
Karaf also comes with a set of console commands that can be used to display, view and change the log levels.
Configuration
Configuration file
The configuration of the logging system uses a standard Log4j configuration file at the following location:
[karaf_install_dir]/etc/org.ops4j.pax.logging.cfg
You can edit this file at runtime and any change will be reloaded and be effective immediately.
Configuring the appenders
The default logging configuration defines three appenders:
- the stdout console appender is disabled by default. If you plan to run Karaf in server mode only (i.e. with the locale console disabled), you can turn on this appender on by adding it to the list of configured appenders using the log4j.rootLogger property
- the out appender is the one enabled by default. It logs events to a number of rotating log files of a fixed size. You can easily change the parameters to control the number of files using maxBackupIndex and their size size maxFileSize
- the sift appender can be used instead to provide a per-bundle log file. The default configuration uses the bundle symbolic name as the file name to log to
Changing the log levels
The default logging configuration sets the logging levels so that the log file will provide enough information to monitor the behavior of the runtime and provide clues about what caused a problem. However, the default configuration will not provide enough information to debug most problems.
The most useful logger to change when trying to debug an issue with Karaf is the root logger. You will want to set its logging level to DEBUG in the org.ops4j.pax.logging.cfg file.
log4j.rootLogger=DEBUG, out, osgi:VmLogAppender
...
When debugging a problem in Karaf you may want to change the level of logging information that is displayed on the console. The example below shows how to set the root logger to DEBUG but limiting the information displayed on the console to WARN.
log4j.rootLogger=DEBUG, out, stdout, osgi:VmLogAppender
log4j.appender.stdout.threshold=WARN
...
Console Log Commands
The log subshell comes with the following commands:
- log:clear: clear the log
- log:display: display the last log entries
- log:display-exception: display the last exception from the log
- log:get: show the log levels. log:get ALL displays the level of all loggers.
- log:list: is an alias to log:get ALL.
- log:set: set the log levels. NB: this command doesn't update etc/org.ops4j.pax.logging.cfg file. You have to use config:edit to do so. It's possible to reload the log level from the configuration file using log:set DEFAULT.
- log:tail: continuous display of the log entries
For example, if you want to debug something, you might want to run the following commands:
> log:set DEBUG
... do something ...
> log:display
Note that the log levels set using the log:set commands are not persistent and will be lost upon restart.
To configure those in a persistent way, you should edit the configuration file mentioned above using the config commands or directly using a text editor of your choice.
The log commands has a separate configure file:
[karaf_install_dir]/etc/org.apache.karaf.log.cfg
Advanced configuration
The logging backend uses Log4j, but offer a number of additional features.
Nested filters, appenders and error handlers
Filters
Appender filters can be added using the following syntax:
log4j.appender.[appender-name].filter.[filter-name]=[filter-class]
log4j.appender.[appender-name].filter.[filter-name].[option]=[value]
Below is a real example:
log4j.appender.out.filter.f1=org.apache.log4j.varia.LevelRangeFilter
log4j.appender.out.filter.f1.LevelMax=FATAL
log4j.appender.out.filter.f1.LevelMin=DEBUG
Nested appenders
Nested appenders can be added using the following syntax:
log4j.appender.[appender-name].appenders=[comma-separated-list-of-appender-names]
Below is a real example:
log4j.appender.async=org.apache.log4j.AsyncAppender
log4j.appender.async.appenders=jms
log4j.appender.jms=org.apache.log4j.net.JMSAppender
...
Error handlers
Error handlers can be added using the following syntax:
log4j.appender.[appender-name].errorhandler=[error-handler-class]
log4j.appender.[appender-name].errorhandler.root-ref=[true|false]
log4j.appender.[appender-name].errorhandler.logger-ref=[logger-ref]
log4j.appender.[appender-name].errorhandler.appender-ref=[appender-ref]
OSGi specific MDC attributes
Pax-Logging provides the following attributes by default:
- bundle.id: the id of the bundle from which the class is loaded
- bundle.name: the symbolic-name of the bundle
- bundle.version: the version of the bundle
An MDC sifting appender is available to split the log events based on MDC attributes. Below is a configuration example for this appender:
log4j.appender.sift=org.apache.log4j.sift.MDCSiftingAppender
log4j.appender.sift.key=bundle.name
log4j.appender.sift.default=karaf
log4j.appender.sift.appender=org.apache.log4j.FileAppender
log4j.appender.sift.appender.layout=org.apache.log4j.PatternLayout
log4j.appender.sift.appender.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
log4j.appender.sift.appender.file=${karaf.data}/log/$\\{bundle.name\\}.log
log4j.appender.sift.appender.append=true
Enhanced OSGi stack trace renderer
This renderer is configured by default in Karaf and will give additional informations when printing stack traces.
For each line of the stack trace, it will display OSGi specific informations related to the class on that line: the bundle id, the bundle symbolic name and the bundle version. This information can greatly help diagnosing problems in some cases.
The information is appended at the end of each line in the following format id:name:version as shown below
java.lang.IllegalArgumentException: Command not found: *:foo
at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:225)[21:org.apache.karaf.shell.console:2.1.0]
at org.apache.felix.gogo.runtime.shell.Closure.executeStatement(Closure.java:162)[21:org.apache.karaf.shell.console:2.1.0]
at org.apache.felix.gogo.runtime.shell.Pipe.run(Pipe.java:101)[21:org.apache.karaf.shell.console:2.1.0]
at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:79)[21:org.apache.karaf.shell.console:2.1.0]
at org.apache.felix.gogo.runtime.shell.CommandSessionImpl.execute(CommandSessionImpl.java:71)[21:org.apache.karaf.shell.console:2.1.0]
at org.apache.karaf.shell.console.jline.Console.run(Console.java:169)[21:org.apache.karaf.shell.console:2.1.0]
at java.lang.Thread.run(Thread.java:637)[:1.6.0_20]
Using your own appenders
If you plan to use your own appenders, you need to create an OSGi bundle and attach it as a fragment to the bundle with a symbolic name of
org.ops4j.pax.logging.pax-logging-service. This way, the underlying logging system will be able to see and use your appenders.
So for example you write a log4j appender:
class MyAppender extends AppenderSkeleton {
...
}
Then you need to package the appender in a jar with a Manifest like this:
Manifest:
Bundle-SymbolicName: org.mydomain.myappender
Fragment-Host: org.ops4j.pax.logging.pax-logging-service
...
Copy the new appender fragment into the ${karaf.home}/system directory. Karaf uses a virtual maven repository to access resources in the system
directory, so the jar path should use the standard maven groupId/artifactId/version/ convention, where the groupId is a directory structure.
Edit ${karaf.home}/etc/startup.properties and add the new fragment bundle to the list before the pax-logging-service bundle.
Restart karaf with a clean run to reload the system bundles, and now you can use the appender in your log4j config file like shown in the config
examples above.