Make Your Logs Work for You

The days of logging in to servers and manually viewing log files are over. SolarWinds® Papertrail™ aggregates logs from applications, devices, and platforms to a central location.

View Technology Info

FEATURED TECHNOLOGY

Troubleshoot Fast and Enjoy It

SolarWinds® Papertrail™ provides cloud-based log management that seamlessly aggregates logs from applications, servers, network devices, services, platforms, and much more.

View Capabilities Info

FEATURED CAPABILITIES

Aggregate and Search Any Log

SolarWinds® Papertrail™ provides lightning-fast search, live tail, flexible system groups, team-wide access, and integration with popular communications platforms like PagerDuty and Slack to help you quickly track down customer problems, debug app requests, or troubleshoot slow database queries.

View Languages Info

FEATURED LANGUAGES

TBD - APM Integration Title

TBD - APM Integration Description

TBD Link

APM Integration Feature List

TBD - Built for Collaboration Title

TBD - Built for Collaboration Description

TBD Link

Built for Collaboration Feature List

Tips from the Team

Logging in Java – Best Practices and Tips

START FREE TRIAL

Fully Functional for 14 Days

Last updated: January 18, 2024

Robust application logging is central to any quality strategy. Unfortunately, many quality strategies fall short, implementing logging in a less-than-stellar way. Java application logging is no different. And since we’re talking about one of the most popular programming languages, investments in improving the overall Java logging strategy could pay off many dividends in the future. 

I wrote this to share what I have learned about logging in Java and how to do it better. I’ll walk you through a list of tips you can start applying today. Some of them will be specific to Java; others will also be applicable to other tech stacks. After reading, you should be ready to take your logging approach to the next level. 

Employ a Logging Framework 

I know it is obvious, but I had to put this on my list. The reason is simple: many people still roll out their homegrown Java logging solutions, and most regret it down the road. 

Even though logging might look like just a matter of recording some text to a destination, there’s much more to it than that. A robust logging approach includes: 

  • formatting log messages 
  • dealing with concurrent access to log files 
  • writing to alternate destinations, depending on log level or other criteria 
  • configuring all of this, and without having to alter the code 

When you adopt a logging library or framework, you get all of the above—and more—in a nicely packaged, ready-to-use unit, and most of the time it’s free. 

One of the most popular solutions for the Java world is the Apache Log4j2 framework. Maintained by the Apache Foundation, Log4j2 is an improvement on the original Log4j, which was the most popular logging framework in Java for many years. Log4j2 brings new features, fixes old problems, and offers an API detached from the implementation. That way, not only do they ensure the framework will always evolve in a compatible way, but they also allow use of other logging frameworks as long as they adhere to the contracts of the API. 

Use the Proper Log Levels 

Logging levels are labels you can attach to each log entry to indicate their severity. Logging in Java is facilitated by the use of logging frameworks which come with predefined levels like SEVERE, WARNING, INFO, CONFIG, FINE, FINER, and FINEST, each serving a specific logging verbosity need​. These are the standard log levels that have been defined by the Java framework. Adding adequate log levels to messages is essential if you want to be able to make sense of them. 

Log4j2, besides supporting standard log levels, offers custom ones too. Here are Log4j2 common log levels: 

LevelValueDescription
OFF0No logging
FATAL100The application is unusable. Action needs to be taken immediately.
ERROR200An error occurred in the application.
WARN300Something unexpected—though not necessarily an error—happened and needs to be watched.
INFO400A normal, expected, relevant event happened.
DEBUG500Used for debugging purposes
TRACE600Used for debugging purposes—includes the most detailed information

Below is a comparison of the Java standard log levels and Log4j2 log levels: 

Aspect Java Logging Levels Log4j2 Logging Levels 
Number of Levels 
Highest Severity SEVERE FATAL 
Lowest Severity FINEST TRACE 
Intermediate Levels WARNING, INFO, CONFIG, FINE, FINER ERROR, WARN, INFO, DEBUG 
Customizability No Yes, supports custom log levels 
System Integration Handlers for different outputs Appenders for different outputs 
Configuration Defined in logging.properties Defined in XML, JSON, or properties file 
Community Adoption Less commonly used Widely adopted in the Java community 
Performance Impact Generally lower performance Generally higher performance due to asynchronous logging 
Exception Handling Limited Rich, with support for stack trace filtering 

Key Differences: 

  1. Severity Levels: 
  • Java uses SEVERE as its highest severity level while Log4j2 uses FATAL. 
  • The lowest severity level in Java is FINEST whereas in Log4j2 it’s TRACE. 
  • The naming of intermediate levels also varies, and Log4j2 provides a custom log level feature which is not available in Java logging. 
  1. Configuration: 
  • Java logging configuration is typically done via a logging.properties file while Log4j2 supports XML, JSON, or properties file configurations. 
  1. Output Handling: 
  • Java logging uses Handlers to direct log messages to different outputs, whereas Log4j2 uses Appenders for this purpose. 
  1. Community Adoption: 
  • Log4j2 is widely adopted in the Java community due to its rich feature set and performance benefits, including asynchronous logging, which is not a native feature in Java logging. 
  1. Exception Handling: 
  • Log4j2 provides richer exception handling with support for stack trace filtering which is not as developed in Java logging. 
  1. Performance: 
  • Log4j2 generally offers higher performance, especially with asynchronous logging, as compared to Java logging. 

The most obvious benefit is levels allow you to search and filter your log entries according to their severity. That way, you can prevent a “needle in a haystack” kind of situation. Imagine having to find the one error entry among thousands of normal events. 

You can go a step further and configure your logging so log entries are written to different destinations according to their levels, which can make it even easier to find the messages you’re looking for. 

Additionally, you can use levels to control the granularity of your logging. In the development environment, you could set the application’s level to the minimum level, so everything is logged. On the other hand, in the production environment, you typically wouldn’t want to record everything, so you’d set the level as INFO. 

Write Meaningful Log Entries 

There’s nothing more frustrating than trying to troubleshoot unexpected application behavior, opening the logs… only to find they contain meaningless, contextless messages. 

Don’t do this to your fellow developers. Create meaningful log messages, rich with context, so they have enough information to understand the event and resolve the issue.  Instead of a generic “Operation failed” message, be more specific, such as “Data export to .csv format failed.” You should also include relevant metadata in your event messages. At a minimum, you should include: 

  • A timestamp. It’s not much use knowing something happened but not when. Add a timestamp to your log files. Spare your fellow devs the pain of trying to figure out time zones by logging in UTC (or local time plus offset). While you’re at it, use the ISO-8601 format for the timestamp. 
  • The ID of the thread. This is priceless when logging from a multi-threaded application. It is also critical if you are thinking about deploying an Application Performance Monitoring tool, like SolarWinds Observability SaaS (formerly known as SolarWinds Observability)
  • The name of the class from which the event originated. 
  • And of course, include the appropriate log level

Beware of Performance Impacts

Over 10 years ago, Jeff Atwood said performance is a feature. He was right then, and he’s still right now. 

Make no mistake: you should expect a performance hit due to logging. But there are steps you can take to minimize performance impacts. Consider the following piece of code: 

logger.info(String.format("The result is %d.", superExpensiveMethod()));

As you can see, to construct the log message, we call an extensive method. Now suppose the current logging level set for the application is WARN. This means the message above won’t get logged. However, the call to superExpensiveMethod() will still be made. The advice here is simple: before doing expensive computations, check whether the application’s configured logging level will allow your message to be written. In the case of log4j2, you can easily do it this way: 

if (logger.isEnabled(Level.INFO))
    logger.info(String.format("The result is %d.", superExpensiveMethod()));

By performing the check above, you can prevent an unnecessary call to a very expensive method. 

Another thing you can do to mitigate the impact of logging on your app’s performance is to avoid logging in the hot path. “Hot path” here means a portion of the application critical for performance and executed frequently. If you can avoid logging in this area, you prevent a large number of performance-impacting logging calls. Another option is to leverage asynchronous logging, so the main thread of the application doesn’t get stuck because of expensive logging calls. 

Frustration-free log management. (It’s a thing.)

Aggregate, organize, and manage your logs with Papertrail

Beware of Sensitive Data 

Many applications handle some sort of sensitive data. When it comes to logging, you have to be careful not to log the data. Besides the obvious security implications, if you fail to correctly handle sensitive data, you might find yourself with serious financial and legal consequences. 

Here is a non-exhaustive list of data you should not include in logs: 

  • financial information, such as account numbers and credit card numbers 
  • security-sensitive data, such as encryption keys or passwords 
  • PII (Personal Identifiable Information), such as full names, email addresses, birth dates, driver’s license numbers, and Social Security numbers 

If you do have a legitimate need to log sensitive information, don’t log them in plain text. Rather, use anonymization and/or pseudonymization techniques, so an eventual attacker can’t read the true data. 

Include the Stack Trace When Logging Exceptions 

The advice here is short: When logging exceptions, include the whole stack trace. This will make it easier for other developers or IT pros to troubleshoot problems. They’ll be able to track the problem to its root cause and fix it. 

Make Your Logs Machine Parsable 

Last but not least, don’t forget to make your log entries machine parsable. 

Many of the tips on this list could be summarized in one sentence: make your logs human-readable. This makes sense since, most of the time, humans are the intended target audience for logs. 

However, it’s becoming increasingly common to use tools to perform analysis on log files, extracting information from the logs to help with decision-making. Parsing plain text logs is doable, but it often requires complex, regular expressions to locate and extract the relevant pieces of data. 

So, instead of logging in plain text, leverage structured logging—for instance, outputting your log events as JSON. This will allow you to use off-the-shelf tools to parse and extract the information you need. 

Java Logging: Do It Properly and Profit 

Good logging is one of the most valuable investments you can make in your application if you want to achieve high-quality software. Unfortunately, it’s easy to get logging in Java—and in other languages—wrong. I wanted to share what I learned so you can avoid these common traps. 

On a last note, if you are looking for a cloud-based logging tool that is easy to setup and use, check out SolarWinds® Papertrail.  Papertrail aggregates all your logs, including Java, into a single location and lets you search and filter events in real time. 

Now that you have the basics, the next step is to make your approach to Java logs more efficient and easier to manage. 

I shared some pointers on how to approach logs with minimal impact on performance, most of them related to making the messages in the log files easily readable and understandable. To sum it up: be considerate of the devs who will be relying on your logs. One of them might even be you. 


This post was written by Carlos Schults. Carlos is a .NET software developer with experience in both desktop and web development, and he’s now trying his hand at mobile. He has a passion for writing clean and concise code, and he’s interested in practices that help you improve app health, such as code review, automated testing, and continuous build.

Aggregate, organize, and manage your logs

  • Collect real-time log data from your applications, servers, cloud services, and more
  • Search log messages to analyze and troubleshoot incidents, identify trends, and set alerts
  • Create comprehensive per-user access control policies, automated backups, and archives of up to a year of historical data
Start Free Trial

Fully Functional for 30 Days

Let's talk it over

Contact our team, anytime.