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.
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:
${event:Marker}
expansions:
<RollingFile name="${event:Marker}"
fileName="${basePath}/${event:Marker:-main}.log"
filePattern="${basePath}/${event:Marker:-main}_%d{yyyyMMdd}.log.gz">
...
</RollingFile>
$$
to prevent expansion:
<!--
~ If no marker is present use the appender named `FILE`
~ from the `<Appenders>` container
-->
<Route key="$${event:Marker}" ref="FILE"/>
<!-- Default route -->
<Route>
<RollingFile name="${event:Marker}"
fileName="${basePath}/${event:Marker}.log"
filePattern="${basePath}/${event:Marker}_%d{yyyyMMdd}.log.gz">
...
</RollingFile>
</Route>