动态更改 log4j 日志级别

发布于 2024-10-10 16:27:35 字数 65 浏览 7 评论 0 原文

动态更改 log4j 日志级别有哪些不同的方法,这样我就不必重新部署应用程序。在这些情况下,这些变化会是永久性的吗?

What are the different approaches for changing the log4j log level dynamically, so that I will not have to redeploy the application. Will the changes be permanent in those cases?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

无可置疑 2024-10-17 16:27:37

如果您想更改所有记录器的日志记录级别,请使用以下方法。这将枚举所有记录器并将日志记录级别更改为给定级别。请确保您没有log4j.properties 文件中设置了 log4j.appender.loggerName.Threshold=DEBUG 属性。

public static void changeLogLevel(Level level) {
    Enumeration<?> loggers = LogManager.getCurrentLoggers();
    while(loggers.hasMoreElements()) {
        Logger logger = (Logger) loggers.nextElement();
        logger.setLevel(level);
    }
}

If you would want to change the logging level of all the loggers use the below method. This will enumerate over all the loggers and change the logging level to given level. Please make sure that you DO NOT have log4j.appender.loggerName.Threshold=DEBUG property set in your log4j.properties file.

public static void changeLogLevel(Level level) {
    Enumeration<?> loggers = LogManager.getCurrentLoggers();
    while(loggers.hasMoreElements()) {
        Logger logger = (Logger) loggers.nextElement();
        logger.setLevel(level);
    }
}
追我者格杀勿论 2024-10-17 16:27:37

我已成功使用此方法来减少“org.apache.http”日志的冗长性:

ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("org.apache.http");
logger.setLevel(Level.TRACE);
logger.setAdditive(false);

I have used this method with success to reduce the verbosity of the "org.apache.http" logs:

ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("org.apache.http");
logger.setLevel(Level.TRACE);
logger.setAdditive(false);
隔纱相望 2024-10-17 16:27:37

您可以使用以下代码片段

((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(packageName)).setLevel(ch.qos.logback.classic.Level.toLevel(logLevel));

You can use following code snippet

((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(packageName)).setLevel(ch.qos.logback.classic.Level.toLevel(logLevel));
茶花眉 2024-10-17 16:27:36

文件看门狗

Log4j 能够监视 log4j.xml 文件中的配置更改。如果您更改了log4j文件,log4j将根据您的更改自动刷新日志级别。有关详细信息,请参阅 org.apache.log4j.xml.DOMConfigurator.configureAndWatch(String,long) 的文档。检查之间的默认等待时间为 60 秒。这些更改将是持久的,因为您直接更改文件系统上的配置文件。您所需要做的就是调用 DOMConfigurator.configureAndWatch() 一次。

警告:由于线程泄漏,configureAndWatch 方法在 J2EE 环境中使用不安全

JMX

设置日志级别(或一般重新配置)log4j 的另一种方法是使用 JMX。 Log4j 将其记录器注册为 JMX MBean。使用应用程序服务器 MBeanServer 控制台(或 JDK 的 jconsole.exe),您可以重新配置每个单独的记录器。这些更改不是持久性的,并且会在您重新启动应用程序(服务器)后重置为配置文件中设置的配置。

自制

正如 Aaron 所描述的,您可以通过编程方式设置日志级别。您可以按照您希望的方式在应用程序中实现它。例如,您可以有一个 GUI,用户或管理员可以在其中更改日志级别,然后在记录器上调用 setLevel() 方法。是否将设置保留在某处取决于您。

File Watchdog

Log4j is able to watch the log4j.xml file for configuration changes. If you change the log4j file, log4j will automatically refresh the log levels according to your changes. See the documentation of org.apache.log4j.xml.DOMConfigurator.configureAndWatch(String,long) for details. The default wait time between checks is 60 seconds. These changes would be persistent, since you directly change the configuration file on the filesystem. All you need to do is to invoke DOMConfigurator.configureAndWatch() once.

Caution: configureAndWatch method is unsafe for use in J2EE environments due to a Thread leak

JMX

Another way to set the log level (or reconfiguring in general) log4j is by using JMX. Log4j registers its loggers as JMX MBeans. Using the application servers MBeanServer consoles (or JDK's jconsole.exe) you can reconfigure each individual loggers. These changes are not persistent and would be reset to the config as set in the configuration file after you restart your application (server).

Self-Made

As described by Aaron, you can set the log level programmatically. You can implement it in your application in the way you would like it to happen. For example, you could have a GUI where the user or admin changes the log level and then call the setLevel() methods on the logger. Whether you persist the settings somewhere or not is up to you.

耳根太软 2024-10-17 16:27:36

更改日志级别很简单;修改配置的其他部分将构成更深入的方法。

LogManager.getRootLogger().setLevel(Level.DEBUG);

这些更改在 Logger 的整个生命周期中都是永久性的。重新初始化时,将读取并使用配置,因为在运行时设置级别不会保留级别更改。

更新:如果您使用的是 Log4j 2,则应根据 setLevel 的调用。 x/manual/migration.html">文档,因为这可以通过实现类来实现。

不支持调用 logger.setLevel() 或类似方法
API。应用程序应该删除这些。等效功能是
Log4j 2 实现类中提供,但可能会留下
应用程序容易受到 Log4j 2 内部变化的影响。

Changing the log level is simple; modifying other portions of the configuration will pose a more in depth approach.

LogManager.getRootLogger().setLevel(Level.DEBUG);

The changes are permanent through the life cyle of the Logger. On reinitialization the configuration will be read and used as setting the level at runtime does not persist the level change.

UPDATE: If you are using Log4j 2 you should remove the calls to setLevel per the documentation as this can be achieved via implementation classes.

Calls to logger.setLevel() or similar methods are not supported in the
API. Applications should remove these. Equivalent functionality is
provided in the Log4j 2 implementation classes but may leave the
application susceptible to changes in Log4j 2 internals.

夜访吸血鬼 2024-10-17 16:27:36

可以将 Log4j2 配置为通过按给定时间间隔扫描 log4j2.xml 文件(或等效文件)来刷新其配置。只需将“monitorInterval”参数添加到您的配置标记中即可。请参阅示例 log4j2.xml 文件的第 2 行,该文件告诉 log4j 如果自上次日志事件以来已经过去超过 5 秒,则重新扫描其配置。

<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="warn" monitorInterval="5" name="tryItApp" packages="">

    <Appenders>
        <RollingFile name="MY_TRY_IT"
                     fileName="/var/log/tryIt.log"
                     filePattern="/var/log/tryIt-%i.log.gz">
            <Policies>
                <SizeBasedTriggeringPolicy size="25 MB"/>
            </Policies>
            ...
        </RollingFile>
    </Appenders>


    <Loggers>
        <Root level="error">
            <AppenderRef ref="MY_TRY_IT"/>
        </Root>
    </Loggers>

</Configuration>

如果您要部署到 Tomcat 实例、IDE 内或使用 Spring Boot,则需要执行额外的步骤才能完成这项工作。这似乎有点超出了这里的范围,可能值得一个单独的问题。

Log4j2 can be configured to refresh its configuration by scanning the log4j2.xml file (or equivalent) at given intervals. Just add the "monitorInterval" parameter to your configuration tag. See line 2 of the sample log4j2.xml file, which tells log4j to to re-scan its configuration if more than 5 seconds have passed since the last log event.

<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="warn" monitorInterval="5" name="tryItApp" packages="">

    <Appenders>
        <RollingFile name="MY_TRY_IT"
                     fileName="/var/log/tryIt.log"
                     filePattern="/var/log/tryIt-%i.log.gz">
            <Policies>
                <SizeBasedTriggeringPolicy size="25 MB"/>
            </Policies>
            ...
        </RollingFile>
    </Appenders>


    <Loggers>
        <Root level="error">
            <AppenderRef ref="MY_TRY_IT"/>
        </Root>
    </Loggers>

</Configuration>

There are extra steps to make this work if you are deploying to a tomcat instance, inside an IDE, or when using spring boot. That seems somewhat out of scope here and probably merits a separate question.

云朵有点甜 2024-10-17 16:27:36

对于 log4j 2 API ,您可以使用

Logger logger = LogManager.getRootLogger();
Configurator.setAllLevels(logger.getName(), Level.getLevel(level));

For log4j 2 API , you can use

Logger logger = LogManager.getRootLogger();
Configurator.setAllLevels(logger.getName(), Level.getLevel(level));

哆兒滾 2024-10-17 16:27:36

这个答案不会帮助您动态更改日志记录级别,您需要重新启动服务,如果您可以重新启动服务
服务,请使用以下解决方案

我这样做是为了更改 log4j 日志级别,它对我有用,我没有引用任何文档。我使用此系统属性值来设置我的日志文件名称。我也使用相同的技术来设置日志记录级别,并且将

其作为 JVM 参数传递(我使用 Java 1.7)

抱歉,这不会动态更改日志记录级别,它需要重新启动服务

java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java

在 log4j.properties 文件中,我添加了此条目,

log4j.rootLogger=${logging.level},file,stdout

我尝试了

 java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=INFO-cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=OFF -cp xxxxxx.jar  xxxxx.java

一切都有效。希望这有帮助!

我的 pom.xml 中有以下依赖项

<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
</dependency>

<dependency>
    <groupId>log4j</groupId>
    <artifactId>apache-log4j-extras</artifactId>
    <version>1.2.17</version>
</dependency>

This answer won't help you to change the logging level dynamically, you need to restart the service, if you are fine restarting the
service, please use the below solution

I did this to Change log4j log level and it worked for me, I have n't referred any document. I used this system property value to set my logfile name. I used the same technique to set logging level as well, and it worked

passed this as JVM parameter (I use Java 1.7)

Sorry this won't dynamically change the logging level, it requires a restart of the service

java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java

in the log4j.properties file, I added this entry

log4j.rootLogger=${logging.level},file,stdout

I tried

 java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=INFO-cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=OFF -cp xxxxxx.jar  xxxxx.java

It all worked. hope this helps!

I have these following dependencies in my pom.xml

<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
</dependency>

<dependency>
    <groupId>log4j</groupId>
    <artifactId>apache-log4j-extras</artifactId>
    <version>1.2.17</version>
</dependency>
触ぅ动初心 2024-10-17 16:27:36

对于 log4j 1.x,我发现最好的方法是使用 DOMConfigurator 提交一组预定义的 XML 日志配置之一(例如,一个用于正常使用,一个用于调试)。

使用这些可以通过以下方式完成:

  public static void reconfigurePredefined(String newLoggerConfigName) {
    String name = newLoggerConfigName.toLowerCase();
    if ("default".equals(name)) {
      name = "log4j.xml";
    } else {
      name = "log4j-" + name + ".xml";
    }

    if (Log4jReconfigurator.class.getResource("/" + name) != null) {
      String logConfigPath = Log4jReconfigurator.class.getResource("/" + name).getPath();
      logger.warn("Using log4j configuration: " + logConfigPath);
      try (InputStream defaultIs = Log4jReconfigurator.class.getResourceAsStream("/" + name)) {
        new DOMConfigurator().doConfigure(defaultIs, LogManager.getLoggerRepository());
      } catch (IOException e) {
        logger.error("Failed to reconfigure log4j configuration, could not find file " + logConfigPath + " on the classpath", e);
      } catch (FactoryConfigurationError e) {
        logger.error("Failed to reconfigure log4j configuration, could not load file " + logConfigPath, e);
      }
    } else {
      logger.error("Could not find log4j configuration file " + name + ".xml on classpath");
    }
  }

只需使用适当的配置名称调用它,并确保将模板放在类路径上。

With log4j 1.x I find the best way is to use a DOMConfigurator to submit one of a predefined set of XML log configurations (say, one for normal use and one for debugging).

Making use of these can be done with something like this:

  public static void reconfigurePredefined(String newLoggerConfigName) {
    String name = newLoggerConfigName.toLowerCase();
    if ("default".equals(name)) {
      name = "log4j.xml";
    } else {
      name = "log4j-" + name + ".xml";
    }

    if (Log4jReconfigurator.class.getResource("/" + name) != null) {
      String logConfigPath = Log4jReconfigurator.class.getResource("/" + name).getPath();
      logger.warn("Using log4j configuration: " + logConfigPath);
      try (InputStream defaultIs = Log4jReconfigurator.class.getResourceAsStream("/" + name)) {
        new DOMConfigurator().doConfigure(defaultIs, LogManager.getLoggerRepository());
      } catch (IOException e) {
        logger.error("Failed to reconfigure log4j configuration, could not find file " + logConfigPath + " on the classpath", e);
      } catch (FactoryConfigurationError e) {
        logger.error("Failed to reconfigure log4j configuration, could not load file " + logConfigPath, e);
      }
    } else {
      logger.error("Could not find log4j configuration file " + name + ".xml on classpath");
    }
  }

Just call this with the appropriate config name, and make sure that you put the templates on the classpath.

独孤求败 2024-10-17 16:27:36

问题分为两部分:

  1. 用户在哪里输入记录器和级别?即如何捕获更改日志级别的意图?
  2. 如何向所有相关服务广播此意图信息?

收集用户意图有以下几种方式:

  • 更改级别的 API 请求,例如 POST /log-levels?logger=com.example.FooClass&level=DEBUG
  • JMX 请求
  • 共享文件
  • 集中式UI(例如 DIY、SpringBoot、Prefab)

传播更改可以通过以下方式完成:

  • 配置扫描/轮询和配置NFS 或远程 URI
  • 服务发现并推送更改
  • Pub/Sub (Redis / SSE)
  • 日志过滤器,在动态配置中查找以获取日志级别(动态配置系统然后使用 pub sub 之类的东西)。

更详细的文章请参见 https://www.prefab。 cloud/blog/dynamically-change-java-log-level/ 包含过滤器方法的示例以及集中式 UI 的外观。

至于这些变化是否是永久性的,这取决于你采取哪种方法。如果您使用 PubSub 或 ServiceDiscovery,则更改只会在重新启动之前生效,因为新服务不会收到消息。如果您希望应用程序的新实例能够获取日志级别的当前值,您将需要更像 Kafka / Redis Streams 的东西。这基本上是动态配置选项。

The question breaks down into 2 parts:

  1. Where does the user input the logger and level? ie How do you capture the intent to change the log level?
  2. How do you broadcast this intent information to all relevant services?

Collecting the user intent comes in a few flavors:

  • An API request to change the levels eg POST /log-levels?logger=com.example.FooClass&level=DEBUG
  • A JMX Request
  • A Shared File
  • A Centralized UI (eg DIY, SpringBoot, Prefab)

Propagating the change can be done by:

  • Configuring scan / polling & NFS or remote URI
  • Service discovery and pushing out the change
  • Pub/Sub (Redis / SSE)
  • A log filter that looks in dynamic configuration to get the log level (the dynamic config system then uses something like pub sub).

A more detailed write-up in https://www.prefab.cloud/blog/dynamically-changing-java-log-level/ with an example of the filter approach and a look at centralized UIs.

As far as whether the changes will be permanent, that depends on which approach you take. If you PubSub or ServiceDiscovery, the change will only take effect until something restarts, because the new service won't get the message. You'll want something more like Kafka / Redis Streams if you want to be able to have new instance of your application get the current value of the log level. That's basically the dynamic configuration option.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文