JVM Logging - Sip of Java

VM logging has long been part of the JDK. It can be an excellent tool for performing root cause analysis and figuring out performance quirks. In JDK 9, several changes were made to how VM logging is handled, making it more user-friendly and configurable. Let’s look at how to use VM logging in this article.

Enabling and Configuring Logging

VM logging can be enabled at the most basic level by adding -Xlog to your java command. This will enable VM logging with a default configuration of:

-Xlog:all=info:stdout:uptime,levels,tags

The above will turn VM logging on for all the different categories at the info level. It will print out VM logs to stdout, including the uptime of the JVM, the level of the log statement, and the tags associated with it. Here’s an example of a log statement:

[1.043s][info][methodhandles           ] lookup_polymorphic_method => intrinsic {method} {0x000000010a38c880}

In most scenarios, the default VM logging will be too noisy to be useful. Luckily VM logging can be configured to suit many needs.

Configuring Tags

A developer will often look into a specific issue when enabling VM logging. VM logging can be configured to only produce logs that match specific categories such as; garbage collection (gc), the just-in-time compiler (jit), CPU usage (cpu), and more. Limiting logging to specific categories can help to reduce noise and allow you to focus on the areas of concern:

-xlog:gc,heap

The above example will limit log output to log statements that only contain gc or heap tags. Alternatively, the following examples can be used to print out logs that contain both gc AND head, and * can be added so that any log containing either gc or heap tags will be printed:

-xlog:gc+heap
-xlog:gc*,heap*

Tags can be set to different levels of logging; off, trace, debug, info, warning, error; for example, if I wanted debug logging for heap but error for gc, it would look like this:

-Xlog:'gc*=error,heap*=debug'

Configuring Output Location

By default, VM logging will print to stdout; however, this might not often be the desired location for VM logging to be sent to; in many cases, it would be preferred for VM logging to be written to a separate file which can be done like so:

-Xlog:'gc*,heap*':vm-logging.log

It’s also valid to have multiple instances of -Xlog in a java command, which can be useful for writing VM logs to different locations based on type. In the below example, gc log statements are written to gc.log while heap log statements are written to heap.log.

-Xlog:'gc*':gc.log -Xlog:`heap*`:heap.log

Reducing Performance Overhead

VM logging can cause a non-trivial amount of overhead to a Java application. To help address this, consider enabling asynchronous logging -Xlog:async, which will write log statements to an in-memory buffer, which will be periodically flushed. The buffer size can be configured with -XX:AsyncLogBufferSize=<bytes>. Like in this example:

-Xlog:'gc*=trace':gc-trace.log -Xlog:async -XX:AsyncLogBufferSize=102400

Configuring Logging on a Running JVM

VM logging can be configured on a JVM with jcmd and VM.log. All configuration options available when configuring VM logging with the java command are available, but supplying the options is done through the output, output_options, what, and decorators arguments like in the below example:

jcmd <pid> VM.log output="file=heap.log" output_options="filecount=5,filesize=10m" what="heap=info" decorators="time,level"

Additional Reading

JEP 158: Unified JVM Logging

JEP 271: Unified GC Logging

Enable Logging with the JVM Unified Logging Framework

Configuring Logging with jcmd Example

Print out of -Xlog:help

Happy coding!