Without log rotation, a long-running Java application will eventually fill your disk with a single ever-growing log file. Logback’s RollingFileAppender solves this by automatically creating a new log file when a threshold is crossed and optionally compressing or deleting old files. In this guide you will learn every rolling policy Logback provides, understand each configuration attribute, and walk away with production-ready logback.xml examples you can drop into your Spring Boot or plain Java application today.
Prerequisites
Add Logback Classic to your project. If you use Spring Boot, Logback is already on the classpath:
<!-- For non-Spring-Boot projects -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.6</version>
</dependency>
How RollingFileAppender Works
A RollingFileAppender composes two cooperating objects:
- RollingPolicy — decides when to roll and how to name the archived files.
- TriggeringPolicy — decides what event triggers a roll (time elapsed, file size reached).
Some policies (like SizeAndTimeBasedRollingPolicy) implement both interfaces, so you only need to configure one element.
Rolling Policy 1 — Time-Based Rolling (Daily Logs)
Roll the log file once per day and keep the last 30 days automatically. This is the most common production configuration.
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Roll daily; .gz extension enables automatic gzip compression -->
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<!-- Keep at most 30 archived files -->
<maxHistory>30</maxHistory>
<!-- Delete archives once the total size exceeds 3 GB -->
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</configuration>
Key Attributes Explained
| Attribute | Description |
|---|---|
file | Path of the active log file that is written during the current period. |
fileNamePattern | Pattern for archived files. The %d{} token drives the roll schedule. Use %d{yyyy-MM-dd} for daily, %d{yyyy-MM} for monthly. |
maxHistory | Maximum number of archive files to keep. Older files are deleted automatically. |
totalSizeCap | Hard cap on the total size of all archive files combined. Oldest files are removed first. |
Rolling Policy 2 — Size-and-Time Based (Most Flexible)
Roll when a file reaches a maximum size or when the day changes — whichever comes first. Each day gets its own numbered sequence of files.
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- %i is the index within each day (0, 1, 2 ...) -->
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<!-- Roll when the active file reaches 50 MB -->
<maxFileSize>50MB</maxFileSize>
<!-- Keep archives for 14 days -->
<maxHistory>14</maxHistory>
<!-- Absolute total cap for all archives -->
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</configuration>
Rolling Policy 3 — Fixed Window (Size-Based Only)
Keep a fixed window of numbered archives. When the window fills up, the oldest is discarded. Less common than time-based policies but useful for short-lived or test environments.
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>logs/app-%i.log.gz</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>5</maxIndex><!-- keeps app-1.log through app-5.log -->
</rollingPolicy>
<!-- Trigger a roll when the active file exceeds 10 MB -->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>10MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE"/>
</root>
</configuration>
Combining Console and Rolling File Appenders
A production application typically logs INFO and above to a rolling file and outputs everything (including DEBUG) to the console in development. Use profiles or Spring Boot’s application.properties to switch, but the base logback.xml structure looks like this:
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Async wrapper reduces I/O overhead in high-throughput apps -->
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>512</queueSize>
<discardingThreshold>0</discardingThreshold>
<appender-ref ref="FILE"/>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="ASYNC_FILE"/>
</root>
</configuration>
Spring Boot Integration
Spring Boot auto-configures Logback, but you can override it completely by placing a logback-spring.xml file in src/main/resources. Using logback-spring.xml instead of logback.xml lets you use Spring Boot’s <springProfile> extension:
<configuration>
<springProfile name="prod">
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/myapp/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/var/log/myapp/application-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="WARN">
<appender-ref ref="FILE"/>
</root>
</springProfile>
<springProfile name="dev,test">
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
</configuration>
Frequently Asked Questions
Does Logback compress logs automatically?
Yes. Appending .gz or .zip to fileNamePattern instructs Logback to compress archives asynchronously on a background thread, so logging performance is not impacted.
What happens to the active log file at application startup?
If <file> is set, Logback appends to it. If no <file> element is present, Logback derives the active file name from fileNamePattern for the current period. Set <cleanHistoryOnStart>true</cleanHistoryOnStart> inside the rolling policy to purge old archives on restart.
How do I roll logs on a per-hour basis?
Change the date format in fileNamePattern to include the hour: %d{yyyy-MM-dd_HH}. Logback infers the roll period from the finest date token present.
See Also
Conclusion
Logback’s RollingFileAppender offers a rich set of policies to manage log files in any environment. For most production applications, SizeAndTimeBasedRollingPolicy strikes the best balance: daily rotation keeps files organised, a per-file size cap prevents sudden disk spikes, and maxHistory plus totalSizeCap together ensure predictable disk usage. Wrap it in an AsyncAppender and your logging will impose virtually zero latency overhead on your application threads.