Log4j2:如何为每个用户将日志写入单独的文件?

Posted

技术标签:

【中文标题】Log4j2:如何为每个用户将日志写入单独的文件?【英文标题】:Log4j2: How to write logs to separate files for each user? 【发布时间】:2014-09-26 16:21:30 【问题描述】:

这是我面临的挑战:

我有一个 servlet 程序。我需要将每个用户的日志写入以该用户命名的文件夹。 像这样的:

    // stores message to David folder
    // /root_path/David/logfile.log
    logger.error(MarkerManager.getMarker("David"), "Error happened");

    // stores message to Mark folder
    // /root_path/Mark/logfile.log                 
    logger.error(MarkerManager.getMarker("Mark"), "Something is broken");

在我的示例中,我使用了标记。但我真的不知道标记是否适合这项任务。

一般来说,我的 appender 应该表现得像 RollingRandomAccessFile appender。 我猜 appender 的配置必须是这样的:

     <RollingRandomAccessFile name="rollingFile"
                 fileName="logs/markerName ?????/movie-db.log"
                 filePattern="logs/log-%dyyyy-MM-dd-%i.log.zip"
                 append="false"
                 immediateFlush="false"
                 ignoreExceptions="true">
        <PatternLayout pattern="%dISO8601 %levellength=5 [%thread] %logger - %msg%n"/>
        <Policies>
            <SizeBasedTriggeringPolicy size="25 MB"/>
            <TimeBasedTriggeringPolicy />
        </Policies>
        <DefaultRolloverStrategy max="10"/>
    </RollingRandomAccessFile>

有什么想法吗?

【问题讨论】:

【参考方案1】:

感谢@Remko Popma 的回答,我明白了。以下是解决方案示例:

package com.bondarenko.tmp;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

public class TestRouting 

private final static Logger log = LogManager.getLogger(TestRouting.class);

public static void main(String[] args) 
    ThreadContext.put("logFileName", "David");
    log.info("Error happened");

    ThreadContext.put("logFileName", "Mark");
    log.info("Something is broken");

    ThreadContext.remove("logFileName");


还有log4j.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">

<Appenders>
    <Console name="consoleAppender" target="SYSTEM_OUT">
        <!--SHORT PATTERN-->
        <PatternLayout pattern="%dABSOLUTE %levellength=5 [%thread] %logger1 - %msg%n"/>
        <!--ROBUST PATTERN
        <PatternLayout pattern="%dISO8601 %levellength=5 [%thread] %logger - %msg%n"/>-->
    </Console>

    <Routing name="RoutingAppender">
        <Routes pattern="$ctx:logFileName">
            <Route>
                <RollingFile name="Rolling-$ctx:logFileName"
                             fileName="logs/$ctx:logFileName"
                             filePattern="logs/$ctx:logFileName.%i.log.gz">
                    <PatternLayout pattern="%dABSOLUTE %levellength=5 [%thread] %logger1 - %msg%n"/>
                    <SizeBasedTriggeringPolicy size="512" />
                </RollingFile>
            </Route>

            <!-- By having this set to $ctx:logFileName it will match when filename
                 is not set in the context -->
            <Route ref="consoleAppender" key="$ctx:logFileName"/>
        </Routes>
    </Routing>

</Appenders>

<Loggers>
    <Logger name="com.bondarenko.tmp" level="info" additivity="false">
        <AppenderRef ref="RoutingAppender"/>
    </Logger>
</Loggers>

【讨论】:

谢谢!你太棒了! :) 将您的示例与常见问题解答页面 (logging.apache.org/log4j/2.0/faq.html#separate_log_files) 进行比较,您似乎需要 而不是 ,对吗? 绝招: 警告:“Route”、“ThreadContext”和朋友是 Log4j 2.0 的特性。如果您遇到像 Log4j 1.2 这样的旧版本,您将无法使用它们 :( 我收到一个错误:- Unable to create file /var/lib/tomcat8/logs/business_system/$ctx:userId/log.log java.io.IOException: The filename, directory name, or volume label syntax is incorrect 当使用 rollingFile 名称时 - /var/lib/tomcat8/logs/business_system/$$ctx:userId/log.log【参考方案2】:

Log4j2 FAQ page 有一个使用 RoutingAppender 实现此目的的示例。

【讨论】:

谢谢。而已。虽然,仍然存在几个问题:我使用 tomcat 作为我的 servlet 容器,所以: - 我应该何时何地调用 ThreadContext.remove("logFileName")? - 如何确保调用上述方法? - 我应该为此烦恼吗? 在您的请求过滤器中 我总是对示例中的双 $$ 和单 $ 感到困惑,使用哪一个? 只是在模式中我们将 $ 转义为​​ $? 这是一个单独的 *** 问题的好候选人!

以上是关于Log4j2:如何为每个用户将日志写入单独的文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何为crontab日志创建文件夹(如果不存在),并根据日期将日志写入特定文件夹?

Filebeat/ELK中如何为不同的日志定义单独的索引?

如何为单个模型保存多个单独的记录

如何为每个用户提供 Firebase 存储中的特定文件夹

如何为 icarousel 中的每个按钮创建单独的操作?

如何监控 Log4j2 异步日志遇到写入瓶颈