Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在运行时更改特定用户/线程的日志级别_Java_Multithreading_Logging_Logback_Log4j2 - Fatal编程技术网

Java 如何在运行时更改特定用户/线程的日志级别

Java 如何在运行时更改特定用户/线程的日志级别,java,multithreading,logging,logback,log4j2,Java,Multithreading,Logging,Logback,Log4j2,我使用带有log4j2.0或logback的slf4j作为实现。例如,我的servlet有一个带有级别错误的记录器,我的服务器生成了100个servlet线程。我将在运行时获得一个特殊用户列表。当我检测到一些连接到的特殊用户时。我想更改那些要调试的特殊用户/线程的日志级别,并保持其他线程的日志级别不受影响(仍然是错误) 我知道logback中的TurboFilter和log4j2.0中的DynamicThresholdFilter,但由于我在运行时只获取特殊用户列表,因此无法使用它们 这是我的申

我使用带有log4j2.0或logback的slf4j作为实现。例如,我的servlet有一个带有级别错误的记录器,我的服务器生成了100个servlet线程。我将在运行时获得一个特殊用户列表。当我检测到一些连接到的特殊用户时。我想更改那些要调试的特殊用户/线程的日志级别,并保持其他线程的日志级别不受影响(仍然是错误)

我知道logback中的TurboFilter和log4j2.0中的DynamicThresholdFilter,但由于我在运行时只获取特殊用户列表,因此无法使用它们

这是我的申请表:

package com.example.logging;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServlet;

import org.slf4j.*;

public class App extends HttpServlet {

    private final Logger Logger = LoggerFactory.getLogger(App.class);
    Map<String, String> map = new HashMap<String, String>();

    public App() {
        map.put("user1", "DEBUG");
        map.put("user2", "DEBUG");
        map.put("user3", "ERROR");
    }

    public void writeToLogFile(String userName) {

        if (map.containsKey(userName)) {
            // do something so that I can change the logger to the corresponding log level
        }

        Logger.error(userName + " error message");

        // the logger is of level ERROR, so by default, this log event will not happen
        // but I want it to happen for special users
        if (Logger.isDebugEnabled()) {
            Logger.debug(userName + " debug message");
        }
    }
}
package com.example.logging;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServlet;

import org.slf4j.*;

public class App extends HttpServlet {

    private final Logger Logger = LoggerFactory.getLogger(App.class);
    Map<String, String> map = new HashMap<String, String>();

    public App() {
        map.put("user1", "Debug");
        map.put("user2", "Debug");
        map.put("user3", "Error");
    }

    public void writeToLogFile(String userName) {
        // if the user is in the map, we put it into ThreadConext for filtering
        if (map.containsKey(userName)) {
            MDC.put("level", map.get(userName));
        }

        Logger.error(userName + " error message");

        if (Logger.isDebugEnabled()) {
            Logger.debug(userName + " debug message");
        }

            // remember to remove it
        MDC.remove("level");
    }

}
预期产出应为:

ERROR com.example.logging.App writeToLogFile - user1 error message
DEBUG com.example.logging.App writeToLogFile - user1 debug message
ERROR com.example.logging.App writeToLogFile - user2 error message
DEBUG com.example.logging.App writeToLogFile - user2 debug message
ERROR com.example.logging.App writeToLogFile - user3 error message
ERROR com.example.logging.App writeToLogFile - user4 error message

我遇到了同样的问题,我最终使用了自己的过滤器,对

对应用程序的更改:

package com.example.logging;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServlet;

import org.slf4j.*;

public class App extends HttpServlet {

    private final Logger Logger = LoggerFactory.getLogger(App.class);
    Map<String, String> map = new HashMap<String, String>();

    public App() {
        map.put("user1", "DEBUG");
        map.put("user2", "DEBUG");
        map.put("user3", "ERROR");
    }

    public void writeToLogFile(String userName) {

        if (map.containsKey(userName)) {
            // do something so that I can change the logger to the corresponding log level
        }

        Logger.error(userName + " error message");

        // the logger is of level ERROR, so by default, this log event will not happen
        // but I want it to happen for special users
        if (Logger.isDebugEnabled()) {
            Logger.debug(userName + " debug message");
        }
    }
}
package com.example.logging;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServlet;

import org.slf4j.*;

public class App extends HttpServlet {

    private final Logger Logger = LoggerFactory.getLogger(App.class);
    Map<String, String> map = new HashMap<String, String>();

    public App() {
        map.put("user1", "Debug");
        map.put("user2", "Debug");
        map.put("user3", "Error");
    }

    public void writeToLogFile(String userName) {
        // if the user is in the map, we put it into ThreadConext for filtering
        if (map.containsKey(userName)) {
            MDC.put("level", map.get(userName));
        }

        Logger.error(userName + " error message");

        if (Logger.isDebugEnabled()) {
            Logger.debug(userName + " debug message");
        }

            // remember to remove it
        MDC.remove("level");
    }

}
将DynamicThresholdUserFilter和包名称添加到配置文件中

<?xml version="1.0" encoding="UTF-8"?>
<!-- add the package name of the filter-->
<Configuration status="ERROR" packages="com.example.logging.plugin">
    <!-- configuration of the new defined filter -->
    <DynamicThresholdUserFilter key="level" defaultThreshold="ERROR" onMatch="ACCEPT" onMismatch="NEUTRAL" />
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%-5level %class{36} %M %msg%xEx%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="com.example.logging.App" level="ERROR" additivity="false">
            <AppenderRef ref="Console" />
        </Logger>
        <Root level="debug">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>


新定义的过滤器与DynamicThresholdFilter非常相似。不同之处在于DynamicThresholdFilter使用配置文件中预定义的级别作为动态阈值,而此筛选器使用在映射中以编程方式定义的级别,而在密集搜索后,现有答案可能会起作用(未亲自尝试),我发现了一个非常简单而巧妙的方法来满足你的要求

可以使用条件在运行时切换日志级别。这与log4j2相结合,您可以做相当漂亮的事情

在服务器调用处理开始时(在
HttpServlet
类的
doFilter
方法中的某个地方),必须根据自定义的用户名逻辑在ThreadContext中填充特定的键。这看起来像:

ThreadContext.put("customLogLevel", "debug");
然后在log4j2.xml文件中,将其作为一个全局过滤器,放在根
配置
标记的正下方:

<DynamicThresholdFilter key="customLogLevel" onMatch="ACCEPT" onMismatch="NEUTRAL">
    <KeyValuePair key="debug" value="DEBUG"/>
    <KeyValuePair key="error" value="ERROR"/>
    <KeyValuePair key="info" value="INFO"/>
</DynamicThresholdFilter>


现在,根据您在调用开始时设置的
ThreadContext
中的key
customLogLevel
值,该线程中的所有日志调用将具有与匹配的
KeyValuePair
行对应的日志级别。因此,在上面的示例中,线程中的所有日志调用都将具有级别为
DEBUG

是否有帮助?我不确定,我知道ThreadContext可以用于区分日志消息和线程,但我不知道它是否可以用于更改单个线程的日志级别。您如何创建日志记录器?如果您想配置每个线程的设置,那么您可能在运行前不知道该线程是什么(即,您没有在某些属性文件或其他文件中进行配置)。您不能为您正在使用的对象的每个实例配置它吗?或者将其设为本地线程,以便对其所做的更改只影响当前线程?实际上,该类用于服务客户端,因此我可以从当前线程了解客户端信息,因此对于一个或两个特定客户端,如果它们连接到我的servlet并且不影响其他人,我希望能够动态地更改它们的日志级别。我以前的注释应该可以工作。这种方法在以这种方式使用时似乎会覆盖任何包的日志级别。我认为这是因为它不会改变根记录器的日志级别。是否有一种方法可以在更改默认根日志级别时执行此操作?非常感谢您的回答。你知道如何用Logback实现同样的效果吗?
<DynamicThresholdFilter key="customLogLevel" onMatch="ACCEPT" onMismatch="NEUTRAL">
    <KeyValuePair key="debug" value="DEBUG"/>
    <KeyValuePair key="error" value="ERROR"/>
    <KeyValuePair key="info" value="INFO"/>
</DynamicThresholdFilter>