当前位置: 首页 > 知识库问答 >
问题:

Log4j2:能够在多用户环境中记录具有不同日志级别的数据

茅星华
2023-03-14

我在oracle adf 12c应用程序中使用log4j2。

我们客户的需求之一是为不同的登录用户提供不同的日志级别,并且为用户动态地更改日志级别。此外,管理员应该有一个控制来停止所有的日志记录。

即假设“用户A”需要跟踪日志级别,“用户B”需要错误日志级别。如果两个用户同时登录,应用程序应该为“用户A”登录跟踪级别,为“用户B”登录错误级别。如果“用户B”想要登录FATAL级别,他应该能够动态更改配置。

以下是log4j2配置文件。

    <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace">
    <MapFilter onMatch="ACCEPT" operator="or">
        <KeyValuePair key="$${ctx:LOGLEVELYN}" value="Y"/>
    </MapFilter>
    <Appenders>
        <File name="file" fileName="./adfAppCustomLogs/TestLog4j2.log">
            <PatternLayout>
                <Pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} %-5level %class %L %M - %msg%xEx%n</Pattern>
            </PatternLayout>
        </File>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%m%n"/>
        </Console>
        <Routing name="AppRouting">
            <Routes pattern="$${ctx:LOGGEDSESSIONID}">
                <!-- This route is chosen if ThreadContext has no value for key ROUTINGKEY. -->
                <Route key="$${ctx:LOGGEDSESSIONID}">
                    <RollingFile name="Rolling-ALL" fileName="./adfAppCustomLogs/DefaultAll.log"
                                 filePattern="./adfAppCustomLogs/archive/${date:yyyy-MM}/DefaultAll-%d{MM-dd-yyyy}-%i.txt.gz">
                        <PatternLayout>
                            <Pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} %-5level %t %msg%xEx%n</Pattern>
                        </PatternLayout>
                        <Policies>
                            <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
                            <SizeBasedTriggeringPolicy size="10 MB"/>
                        </Policies>
                    </RollingFile>
                </Route>
                <!-- This route is chosen if ThreadContext has value 'user' for key ROUTINGKEY. -->
                <Route>
                    <RollingFile name="Rolling-OTHER-${ctx:LOGGEDSESSIONID}"
                                 fileName="./adfAppCustomLogs/${ctx:LOGINID}-${ctx:LOGGEDSESSIONID}.log"
                                 filePattern="./adfAppCustomLogs/archive/${date:yyyy-MM}/${ctx:LOGINID}-%d{MM-dd-yyyy}-%i.txt.gz">
                        <PatternLayout>
                            <Pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} %-5level %t %msg%xEx%n</Pattern>
                        </PatternLayout>
                        <Policies>
                            <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
                            <SizeBasedTriggeringPolicy size="10 MB"/>
                        </Policies>
                        <!-- <DefaultRolloverStrategy max="100"/> -->
                    </RollingFile>
                </Route>
            </Routes>
        </Routing>
        <Async name="async" bufferSize="1000" includeLocation="true">
            <AppenderRef ref="AppRouting"/>
        </Async>
    </Appenders>
    <Loggers>
        <Root level="trace">
            <!--<AppenderRef ref="file" level="DEBUG"/> -->
            <AppenderRef ref="async"/>
            <!-- Uncomment the following if you want the log to be printed in weblogic console -->
             <AppenderRef ref="STDOUT"/> 
        </Root>
    </Loggers>
</Configuration>

我试着创建多个日志记录器,每个都有不同的日志级别,但是没有成功。

如果你能给我一些指点或提示,那就太好了。

共有1个答案

郑博
2023-03-14

我们客户的要求之一是为不同的登录用户提供不同的日志级别,并为一个用户动态更改日志级别。管理员还应该控制停止所有日志记录。

这需要为每个用户设置一个单独的记录器,我假设这意味着每个Thread。显然,您不可能提前配置所有这些记录器,因为您不知道在运行时会有多少用户。因此,您需要在运行时动态创建记录器并调用log4j2 API。您可以参考log4j2手册了解完整的详细信息。

此外,您需要创建管理控件,以允许访问log4j2配置,并提供在运行时修改配置的能力。

以下是一个小示例,说明如何实现每个Thread拥有一个记录器的目标以及如何在运行时更改日志级别:

这是log4j2.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%m%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="example" level="trace">
            <AppenderRef ref="STDOUT" />
        </Logger>
        <Root level="WARN">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>
</Configuration>

以下是java代码:

package example;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;

public class LogLvlByThreadMain {

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable(){

            public void run() {
                addLogger(Thread.currentThread().getName());

                Logger log = LogManager.getLogger(Thread.currentThread().getName());
                log.info("here's the first thread");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.debug("some debug in first thread");
                log.info("finishing first thread");
            }}, "Thread1");

        Thread t2 = new Thread(new Runnable(){

            public void run() {
                addLogger(Thread.currentThread().getName());

                Logger log = LogManager.getLogger(Thread.currentThread().getName());
                log.info("here's the second thread");

                changeLogLevel(Thread.currentThread().getName(), Level.DEBUG);

                log.debug("some debug in second thread");
            }}, "Thread2");

        t1.start();
        t2.start();
    }

    public static synchronized void addLogger(String name){
        AppenderRef ref = AppenderRef.createAppenderRef("STDOUT", null, null);
        AppenderRef[] refs = new AppenderRef[] {ref};

        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        LoggerConfig loggerConfig = LoggerConfig.createLogger("false", Level.INFO, name,
                "true", refs, null, config, null );

        loggerConfig.addAppender(config.getAppender("STDOUT"), null, null);
        config.addLogger(name, loggerConfig);
        ctx.updateLoggers();
    }

    public static synchronized void changeLogLevel(String loggerName, Level lvl){
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        LoggerConfig loggerCfg = config.getLoggerConfig(loggerName);
        loggerCfg.setLevel(lvl);
        ctx.updateLoggers();
    }

}

请注意,您将不得不考虑多个线程动态更改日志配置的同步问题-请注意上面更改配置的两个方法是如何同步的

上述代码的输出:

here's the second thread
here's the first thread
some debug in second thread
finishing first thread

这证明这两个线程具有不同的日志级别,因为如果我们同时更改了它们,我们将看到两个“调试”日志,而不仅仅是第二个线程中的日志。

 类似资料:
  • 我想做的很直截了当: 我只希望在控制台追加器上显示重要的消息,而我希望将详细的消息路由到文件追加器。 我还尝试向添加一个ThresholdFilter,但这也不能过滤它。

  • 在log4j2文档log4j2 java配置中,默认配置为: 根本就不在那里。它仍将只打印出错误日志。 问题 是否有其他人遇到此问题? 有人能复制它吗? 有人知道怎么修吗?我几乎要给别人一块钱。不过,我肯定会把他们的答案标成绿色。 我的最终目标是让特定的记录器发送SMTP请求。我很确定我知道怎么做,我只是在和这个小问题作斗争

  • SLF4J具有以下日志级别 JDK日志记录具有以下日志级别 如果我想将日志级别设置为DEBUG,那么该级别在JDK日志中不可用。谁能解释一下在这种情况下我们如何获得调试级别的日志记录。对于这种情况,我们需要做什么额外的配置吗? 已更新 这是我的属性文件配置 请让我知道我哪里错了。

  • 是的,我已经阅读了所有相关的问题。我正在使用log4j2(尝试了2.4版和更新到最新的2.6.2版)。 我有一个面向客户的小型实用程序。我渴望将暴露的配置保持在最低限度。但对于有问题的情况,我还想添加一个标志,以便在运行时启用调试日志。 这是我启用调试日志记录的代码 但它实际上并不适用于这些情况: 实用程序通常在30秒内完成,因此更改应该是即时的。这是log4j2。xml 使用AppenderRe

  • 我正在尝试创建基于不同级别的“不同”附加器,但到目前为止,我找不到一种隔离日志级别的方法。。。。 我需要一种方法,能够土地只有INFO优先排序的日志被追加。因为INFO级别的日志记录也会显示DEBUG标记的日志记录器...这对我没有帮助。 另一件事是,对于“相同”包,我无法定义不同的日志附加器: 在这里,我得到了如下错误:

  • 现在,问题是,当我以以下方式进行日志记录时: 尽管根记录器级别被设置为“错误”,但日志条目仍然存在于两个日志文件中。然而,当我去掉“it.pkg.testpkg.service”记录器(通过注释或删除它)时,条目停止进入根记录器。我不太清楚这是怎么回事。 目前,我已经找到了一个临时解决方案,方法是在“root_file_appender”中添加以下条目: 谢了。