- ⚠️ Without the right filters, log files take in too many high-severity logs, and make things messy.
- 🔍 The LevelRangeFilter lets you send logs to exact places by only letting logs in a certain severity range pass.
- 💻 Async appenders make logging much faster in busy programs.
- 🔐 Sensitive data should always be hidden to stop security problems from logs.
- 📁 RollingFileAppender stops log files from getting too big and makes sure old logs get saved well.
Java Log4j2 Setup: Do Your Log Levels Work?
If your INFO logs are ending up in your debug.log or trace.log, you are not alone. If Log4j2 is not set up right, logs can get messy. This makes debugging harder and log dashboards loud. This guide shows you how to set up Log4j2 with a properties file in Java. You will learn to write each log level to its own file. This keeps things clean and works well. We will look at ideas, filters, and a real example. This way, you can stop guessing and start logging better.
Why Log4j2 and Separating Log Levels Is Important
Apache Log4j2 is a good, fast logging library. It is a common choice for Java. It is better than the old version, Log4j 1.x, in speed and how you can set it up. It has features like async logging, filters to send logs, and good control over how logs are grouped. In modern microservice setups or big business systems, good log management is key. It helps you see what is happening, tune how things run, and react to problems.
When logs of different types go into one file, it is hard to see what is going on. Looking through many TRACE messages during a system crash to find a FATAL error wastes time and can lead to mistakes. But, if each log level has its own file, you can quickly see what is happening, what went wrong, and when.
Separating log levels helps many people:
- Developers can focus on DEBUG and TRACE while coding.
- QA teams can find WARN and ERROR to spot new problems fast.
- Ops teams can turn off low-level logs but keep FATAL and ERROR for warnings.
You can do all this with the right Java Log4j2 setup, along with filters for levels and property files.
Why INFO Shows Up in Your DEBUG or TRACE Logs
You might have wanted your logs to stay in their own files—INFO in info.log, DEBUG in debug.log, and so on. But, INFO statements are showing up in debug.log, and WARNs are appearing where they should not. This happens because of how Log4j2 log levels work. They are in an order and include higher levels.
Here is how it works:
-
Log4j2 handles levels in an order:
TRACE < DEBUG < INFO < WARN < ERROR < FATAL. -
If you use a
ThresholdFilterset atDEBUG, it includes everything from DEBUG and higher—so INFO, WARN, ERROR, and FATAL all get in too. -
Since there is no exclusive filter (like
LevelRangeFilter), these logs spill over.
This happens because most setups say a minimum severity, but they do not stop higher severity logs from getting in. If you do not use a full range filter, Log4j2 thinks you want to include all higher severities too. To fix this, we need to set up Log4j2 more carefully, using LevelRangeFilter.
Log4j2 Log Levels and How They Move Explained
Knowing Log4j2's log level order is key to stopping logs from mixing between files. Each log request is marked with a certain severity level. Here is what each level means and what it includes by default:
| Level | What it is for | What it covers |
|---|---|---|
| TRACE | Very detailed messages, usually for finding problems | All levels |
| DEBUG | For finding issues in code while building it | DEBUG and up |
| INFO | Shows normal program events | INFO, WARN, ERROR, FATAL |
| WARN | Marks events that might lead to errors later | WARN, ERROR, FATAL |
| ERROR | Shows errors that stop a feature from working | ERROR, FATAL |
| FATAL | Points to big failures, like program crashes | FATAL only |
Log levels usually move up. This means anything logged at TRACE will also be accepted by DEBUG, INFO, and so on. Loggers take on the log level from their parents, unless you say otherwise. This can put logs in the wrong files if you do not use filters to keep levels separate.
To keep logs separate and accurate:
- Use
LevelRangeFilterwhen sending logs. This will stop higher-severity logs from going into files meant for lower levels. - Turn off additivity if messages from child loggers are showing up when they should not (more on this later).
More About the log4j2.properties File Structure
The log4j2.properties file is an easy to read way to set things up. People often like it more than XML or YAML. It puts your logging plan into appenders, loggers, and filters. Each has clear settings.
A Simple Configuration Example
status = error
name = MyAppLogger
appender.console.type = Console
appender.console.name = ConsoleLogger
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}] [%t] %-5level %logger{36} - %msg%n
rootLogger.level = debug
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = ConsoleLogger
status: Sets Log4j2's own internal logging level.rootLogger.level: This is the main logging level. It ignores anything lower.appender.console.type: Types are Console, File, RollingFile, and more.layout: This controls how each line looks.
Knowing these basics makes sure your logging setup is solid before you look at filters for log levels.
Filters: ThresholdFilter Versus LevelRangeFilter
Filtering is what makes level-based log sending work. Log4j2 offers many filters, but these two are key for our goal:
ThresholdFilter
This filter allows everything at or above a set level.
appender.info.filter.threshold.type = ThresholdFilter
appender.info.filter.threshold.level = INFO
This is good if you want logs to get more severe as they go. For example, an alerts.log file might only have ERROR and FATAL messages if you use a ThresholdFilter.
Bad point: It does not stop higher levels. Setting level = DEBUG also brings in INFO, WARN, ERROR, and more.
LevelRangeFilter
This filter is great for keeping log levels separate. You set a minimum and maximum level. Only logs in that range get accepted.
appender.debug.filter.range.type = LevelRangeFilter
appender.debug.filter.range.minLevel = DEBUG
appender.debug.filter.range.maxLevel = DEBUG
When you set both a start and end level, the appender will only log DEBUG messages. It stops any logs below or above that range.
Apache Logging Services (n.d.) says filters give good control. They include or exclude certain events at the appender or logger level Source.
How to Make Separate Log Files for Each Level: Step-by-Step
To send logs to separate files without mixing them, follow these steps:
1. Set Up Your Folder
Make sure your project has a logs/ folder just for log files:
/my-java-app/logs/
2. Create Each Appender with its Filter
Add individual appenders and use LevelRangeFilter to keep them separate.
# TRACE Log Appender
appender.trace.type = File
appender.trace.name = TraceAppender
appender.trace.fileName = logs/trace.log
appender.trace.layout.type = PatternLayout
appender.trace.layout.pattern = [%d{ISO8601}] [%t] %-5level %logger - %msg%n
appender.trace.filter.range.type = LevelRangeFilter
appender.trace.filter.range.minLevel = TRACE
appender.trace.filter.range.maxLevel = TRACE
# DEBUG Log Appender
appender.debug.type = File
appender.debug.name = DebugAppender
appender.debug.fileName = logs/debug.log
appender.debug.layout.type = PatternLayout
appender.debug.layout.pattern = [%d{ISO8601}] [%t] %-5level %logger - %msg%n
appender.debug.filter.range.type = LevelRangeFilter
appender.debug.filter.range.minLevel = DEBUG
appender.debug.filter.range.maxLevel = DEBUG
Add more appenders for INFO, WARN, ERROR, and FATAL. Do this the same way.
3. Connect Loggers to Appenders
rootLogger.level = trace
rootLogger.appenderRefs = trace, debug
rootLogger.appenderRef.trace.ref = TraceAppender
rootLogger.appenderRef.debug.ref = DebugAppender
This connects the root logger to each appender. And it still follows each appender's filter rules.
4. Restart and Check
Run your program and send out logs at all levels you have set. Check that:
trace.loghas only TRACE entries.debug.loghas only DEBUG entries.- No log file has levels it should not based on its filter.
Fixing Common Log4j2 Setup Problems
Seeing problems you did not expect? Look at these things:
- Additivity is On by Default: Logs move up from child to parent loggers unless you turn off additivity.
logger.com.example.additivity = false - Wrong Filter Type: Swapping a
LevelRangeFilterfor aThresholdFiltercould let in too many higher-level messages. - Appender Not Linked: If you forget to link an appender, it will not work.
- Typos and Capitalization:
DEBUGis not the same asdebugin many setups. Always use uppercase for levels.
If these steps do not work, turn on internal status messages:
status = debug
Then look for problems in the console when the program starts.
How to Make Logging Faster for Busy Systems
Logging can slow down a program a lot if it logs many things. Try these ways to make it better:
- Asynchronous Logging: This separates log handling from how the program runs.
appender.async.type = Async - BufferedIO: It holds writes to disk in memory for a bit. This lowers the cost of saving right away.
- RollingFileAppender: It breaks up logs by size, date, or time. This helps manage how much disk space is used.
Apache says
RollingFileAppendermakes files smaller by regularly changing them out Source.
Use compression (.gz, .zip) and saving rules to keep archives small.
Log4j2 in Microservices and Automated Builds (CI/CD)
New systems make logs from many services. Here, separating logs by level lets you:
- Log Sending: Send only ERROR and FATAL logs to central systems like ELK or Splunk. This cuts down on the amount of data.
- Log Alerts: Watch ERROR and WARN logs only. This stops wrong alerts.
- Connect Events: Use logs with timestamps, separated by level, to find problems fast.
And, separating logs by level also makes compliance checks easier. It helps you keep only the logs you need.
Logging Advice for Live Systems
Here is a checklist for a strong Log4j2 setup in production:
- ✅ Use
RollingFileAppender. Set it to change files based on size and time. - ✅ Turn on JSON log format to work well with monitoring tools.
- ✅ Set log levels outside the code, using system settings or JVM options.
- ✅ Hide secret data using special filters or tools before logs are written.
- ✅ Regularly check your logging to make sure it does not leak personal or login details.
Oracle says a good log setup makes debugging better. It also filters out data you do not need Source.
How Log4j2 Works with Frameworks Like Spring Boot
To make Spring Boot use Log4j2:
-
Change logging libraries:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> -
Rename your setup file to
log4j2-spring.xmlorlog4j2.properties. Spring Boot looks for files with-springat the end. -
Change program settings in
application.propertiesto update Log4j2's behavior while the program runs.
Whether you use Spring, Quarkus, or Micronaut, Log4j2 offers a similar setup with outputs that can change.
Common Questions
Can many appenders write to the same file?
Yes, but we do not suggest it. This is unless you control how things access the file at the same time. This helps avoid corrupted data or errors.
Does Log4j2 work with JSON logs for each level?
Yes. Change PatternLayout to JsonLayout. And set up field names as you need.
How do I log only WARN and higher levels to one file?
Use a ThresholdFilter with level = WARN for that appender. Then use other filters for logs meant for lower severity files.
Is it safe to use TRACE logging on a live system?
No. TRACE makes the disk work much harder. It also risks showing too much internal info or sensitive data.
Main Points
- Use LevelRangeFilter to log levels exactly, without overlap.
- Check that every appender links to a logger or rootLogger.
- Turn off additivity to stop logs from showing up many times in the hierarchy.
- Use async logging and log rotation on live systems. This is to make things run better and be safer.
- Keep
log4j2.propertiesclean, checked, and kept safe with version control.
Resources and Further Reading
- Apache Logging Services. (n.d.). Filters. Retrieved from https://logging.apache.org/log4j/2.x/manual/filters.html
- Apache Logging Services. (n.d.). Appender Components. Retrieved from https://logging.apache.org/log4j/2.x/manual/appenders.html
- Apache Logging Services. (n.d.). Log Levels. Retrieved from https://logging.apache.org/log4j/2.x/manual/customlevels.html
- Oracle. (2023). Logging in Java using Log4j2. Retrieved from https://docs.oracle.com/en