Log4j appender that logs event meta data such as the timestamp, the logger name, the exception stacktrace, ThreadContext (aka MDC) or the Java thread name to fields in systemd journal (aka "the Journal") .
Read Lennart Poettering's blog post systemd for Developers III if you are not familar with systemd journal.
Add the following Maven dependency to your project:
<dependency>
<groupId>de.bwaldvogel</groupId>
<artifactId>log4j-systemd-journal-appender</artifactId>
<version>2.2.2</version>
<scope>runtime</scope>
</dependency>
See the 1.x
branch of this project.
- Linux with systemd-journal
- Log4j 2.x
The appender can be configured with the following properties
Property name | Default | Type | Description
--------------------- | ----------------- | ------- | -----------
`logSource` | false | boolean | Determines whether the log locations are logged. Note that there is a performance overhead when switched on. The data is logged in standard systemd journal fields `CODE_FILE`, `CODE_LINE` and `CODE_FUNC`.
`logStacktrace` | true | boolean | Determines whether the full exception stack trace is logged. This data is logged in the user field `STACKTRACE`.
`logThreadName` | true | boolean | Determines whether the thread name is logged. This data is logged in the user field `THREAD_NAME`.
`logLoggerName` | true | boolean | Determines whether the logger name is logged. This data is logged in the user field `LOG4J_LOGGER`.
`logAppenderName` | true | boolean | Determines whether the appender name is logged. This data is logged in the user field `LOG4J_APPENDER`.
`logThreadContext` | true | boolean | Determines whether the [thread context][thread-context] is logged. Each key/value pair is logged as user field with the `threadContextPrefix` prefix.
`threadContextPrefix` | `THREAD_CONTEXT_` | String | Determines how [thread context][thread-context] keys should be prefixed when `logThreadContext` is set to true. Note that keys need to match the regex pattern `[A-Z0-9_]+` and are normalized otherwise.
`syslogIdentifier` | null | String | This data is logged in the user field `SYSLOG_IDENTIFIER`. If this is not set, the underlying system will use the command name (usually `java`) instead.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO" packages="de.bwaldvogel.log4j">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<SystemdJournal name="journal" logStacktrace="true" logSource="false" />
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="console" />
<AppenderRef ref="journal" />
</Root>
</Loggers>
</Configuration>
This will tell Log4j to log to systemd journal as well as to stdout (console).
Note that a layout is optional for SystemdJournal
.
This is because meta data of a log event such as the timestamp, the logger name or the Java thread name are mapped to systemd-journal fields and need not be rendered into a string that loses all the semantic information.
import org.apache.logging.log4j.*;
class YourExample {
private static Logger logger = LogManager.getLogger(YourExample.class);
public static void main(String[] args) {
ThreadContext.put("MY_KEY", "some value");
logger.info("this is an example");
}
}
Running this sample class will log a message to journald:
# journalctl -n
Okt 13 21:26:00 myhost java[2370]: this is an example
Use journalctl -o verbose
to show all fields:
# journalctl -o verbose -n
Di 2015-09-29 21:07:05.850017 CEST [s=45e0…;i=984;b=c257…;m=1833…;t=520e…;x=3e1e…]
PRIORITY=6
_TRANSPORT=journal
_UID=1000
_GID=1000
_CAP_EFFECTIVE=0
_SYSTEMD_OWNER_UID=1000
_SYSTEMD_SLICE=user-1000.slice
_MACHINE_ID=4abc6d…
_HOSTNAME=myhost
_SYSTEMD_CGROUP=/user.slice/user-1000.slice/session-2.scope
_SYSTEMD_SESSION=2
_SYSTEMD_UNIT=session-2.scope
_BOOT_ID=c257f8…
THREAD_NAME=main
LOG4J_LOGGER=de.bwaldvogel.log4j.SystemdJournalAppenderIntegrationTest
_COMM=java
_EXE=/opt/oracle-jdk-bin-1.7.0.80/bin/java
MESSAGE=this is a test message with a MDC
CODE_FILE=SystemdJournalAppenderIntegrationTest.java
CODE_FUNC=testMessageWithMDC
CODE_LINE=36
THREAD_CONTEXT_SOME_KEY1=some value %d
THREAD_CONTEXT_SOME_KEY2=some other value with unicode: →←üöß
SYSLOG_IDENTIFIER=log4j2-test
LOG4J_APPENDER=Journal
_PID=8224
_CMDLINE=/opt/oracle-jdk-bin-1.7.0.80/bin/java …
_SOURCE_REALTIME_TIMESTAMP=1443553625850017
Note that the ThreadContext key-value pair {"MY_KEY": "some value"}
is automatically added as field with prefix THREAD_CONTEXT
.
You can use the power of systemd journal to filter for interesting messages. Example:
journalctl CODE_FUNC=testMessageWithMDC THREAD_NAME=main
will only show messages that are logged from the Java main thread in a method called testMessageWithMDC
.
- logback-journal
- Systemd Journal appender for Logback