The API has changed (e.g. setMaxFileSize no longer exists) and many of the above functions don't seem to work, but I have something that works for me against logback 1.1.8 (the latter currently).
I wanted to start at startup and rolls in size, but not the time. It does:
public class RollOnStartupAndSizeTriggeringPolicy<E> extends SizeBasedTriggeringPolicy<E> { private final AtomicBoolean firstTime = new AtomicBoolean(); public boolean isTriggeringEvent(final File activeFile, final E event) { if (firstTime.compareAndSet(false, true) && activeFile != null && activeFile.length() > 0) { return true; } return super.isTriggeringEvent(activeFile, event); } }
With this, you also need a rolling policy. FixedWindowRollingPolicy will probably do, but I do not like it because I want to store a large number of files, and for this it is very inefficient. Something that the number is gradually increasing (instead of sliding like FixedWindow) will work, but this does not exist. While I write myself, I decided to use time instead of counting. I would like to extend the current registration code, but for time-based material, driving and launch policies are often combined into one class, and there are nesting and circular logs and fields without getters, so I found this pretty impossible. So I had to do a lot from scratch. I support it simply and do not implement features such as compression - I would like to use them, but I'm just trying to keep it simple.
public class TimestampRollingPolicy<E> extends RollingPolicyBase { private final RenameUtil renameUtil = new RenameUtil(); private String activeFileName; private String fileNamePatternStr; private FileNamePattern fileNamePattern; @Override public void start() { super.start(); renameUtil.setContext(this.context); activeFileName = getParentsRawFileProperty(); if (activeFileName == null || activeFileName.isEmpty()) { addError("No file set on appender"); } if (fileNamePatternStr == null || fileNamePatternStr.isEmpty()) { addError("fileNamePattern not set"); fileNamePattern = null; } else { fileNamePattern = new FileNamePattern(fileNamePatternStr, this.context); } addInfo("Will use the pattern " + fileNamePattern + " to archive files"); } @Override public void rollover() throws RolloverFailure { File f = new File(activeFileName); if (!f.exists()) { return; } if (f.length() <= 0) { return; } try { String archiveFileName = fileNamePattern.convert(new Date(f.lastModified())); renameUtil.rename(activeFileName, archiveFileName); } catch (RolloverFailure e) { throw e; } catch (Exception e) { throw new RolloverFailure(e.toString(), e); } } @Override public String getActiveFileName() { return activeFileName; } public void setFileNamePattern(String fnp) { fileNamePatternStr = fnp; } }
And then the config looks like
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> <file>/tmp/monitor.log</file> <rollingPolicy class="my.log.TimestampRollingPolicy"> <fileNamePattern>/tmp/monitor.%d{yyyyMMdd-HHmmss}.log</fileNamePattern> </rollingPolicy> <triggeringPolicy class="my.log.RollOnStartupAndSizeTriggeringPolicy"> <maxFileSize>1gb</maxFileSize> </triggeringPolicy> </appender>
If you are upset, this is not decided initially, vote for him at
http://jira.qos.ch/browse/LOGBACK-204
http://jira.qos.ch/browse/LOGBACK-215
(these were years, and for me this is absolutely important functionality, although I know that many other frameworks also fail)