log4j2

Using Marker Name in Log4j2 RollingFileAppender


I am attempting to use the name of the marker as the filename of a RollingFileAppender, defined inside a RoutingAppender, similar to this example except with <RolingFile> instead of <File>. The eventual purpose of this is per-user logging in the application. The marker is the username.

Unfortunately, this doesn't work. I get this error:

2024-12-20T14:59:14.322023700Z userTaskScheduler-2 ERROR Unable to create file \app\logs/${event:Marker}.log java.io.IOException: The filename, directory name, or volume label syntax is incorrect
        at java.base/java.io.WinNTFileSystem.canonicalize0(Native Method)
        at java.base/java.io.WinNTFileSystem.canonicalize(WinNTFileSystem.java:463)
        at java.base/java.io.File.getCanonicalPath(File.java:626)
        at java.base/java.io.File.getCanonicalFile(File.java:651)
        at org.apache.logging.log4j.core.util.FileUtils.makeParentDirs(FileUtils.java:141)
        at org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory.createManager(RollingFileManager.java:863)

Here's the log4j2 setup:

<Properties>
    <Property name="basePath" value="\app\logs" />
</Properties>
<Appenders>
    <Routing name="ROUTING">
        <Routes pattern="$${event:Marker}">
            <!--<Route key="DEFAULT" ref="FILE"/>-->
            <Route>
                <RollingFile
                    name="${event:Marker}"
                    fileName="${basePath}/${event:Marker}.log"
                    filePattern="${basePath}/${event:Marker}_%d{yyyyMMdd}.log.gz" 
                    append="true">


                    <PatternLayout pattern="%-5p | %d{yyyy-MM-dd HH:mm:ss} | %X{username} | [%marker] | [%t] %C{2} (%F:%L) - %m%n" />
                    <Policies>
                        <TimeBasedTriggeringPolicy />
                        <SizeBasedTriggeringPolicy size="10 MB" />
                    </Policies>
                </RollingFile>
            </Route>
        </Routes>
    </Routing>
</Appenders>

Here's the Java code:

public class LoggingServiceImpl implements LoggingService {
    
    private Map<String, Marker> monitoredUsersMarkers;
    private Marker DEFAULT = MarkerFactory.getMarker("DEFAULT");

    // code to populate markers map

    @Override
    public Marker getMarker(String userId) {
        
        Marker result = monitoredUsersMarkers.getOrDefault(userId, DEFAULT);
        return result;
    }

I've researched and looked at previous questions but they didn't solve my problem.


Solution

  • You configuration doesn't cover the case, when a log event has no marker. If no marker is present the ${event:Marker} placeholder is not expanded and causes the error you are seeing.

    To prevent this problem the example you are citing uses a placeholder with a default value ${event:Marker:-main}, which expands to "main" if no marker is present. See Property Substitution for more details.

    To solve your problem you can either: