原文: https://howtodoinjava.com/log4j/how-to-reload-log4j-levels-on-runtime/

过多的日志记录是导致应用性能下降的常见原因。 它是最佳实践之一,可确保 Java EE 应用实现中的正确日志记录。 但是,请注意在生产环境中启用的日志记录级别。 过多的日志记录将触发服务器上的高 IO,并增加 CPU 使用率。 对于使用较旧硬件的较旧环境或处理大量并发卷的环境而言,这尤其可能成为问题。

  1. A balanced approach is to implement a "reloadable logging level" facility to turn extra logging ON / OFF
  2. when required in your day to day production support.

让我们看看如何使用 Java 7 提供的WatchService完成此操作。

步骤 1)实现一个WatchService,它将监听给定 log4j 文件中的更改

下面的给定代码初始化了一个线程,该线程连续监视给定 log4j 文件(StandardWatchEventKinds.ENTRY_MODIFY)中的修改。 一旦观察到文件更改,就会调用configurationChanged()方法,并使用 DOMConfigurator.configure()方法再次重新加载 log4j 配置。

Log4jChangeWatcherService.java

  1. package com.howtodoinjava.demo;
  2. import java.io.IOException;
  3. import java.nio.file.FileSystems;
  4. import java.nio.file.Path;
  5. import java.nio.file.Paths;
  6. import java.nio.file.StandardWatchEventKinds;
  7. import java.nio.file.WatchEvent;
  8. import java.nio.file.WatchKey;
  9. import java.nio.file.WatchService;
  10. import org.apache.log4j.xml.DOMConfigurator;
  11. public class Log4jChangeWatcherService implements Runnable
  12. {
  13. private String configFileName = null;
  14. private String fullFilePath = null;
  15. public Log4jChangeWatcherService(final String filePath) {
  16. this.fullFilePath = filePath;
  17. }
  18. //This method will be called each time the log4j configuration is changed
  19. public void configurationChanged(final String file)
  20. {
  21. System.out.println("Log4j configuration file changed. Reloading logging levels !!");
  22. DOMConfigurator.configure(file);
  23. }
  24. public void run() {
  25. try {
  26. register(this.fullFilePath);
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. private void register(final String file) throws IOException {
  32. final int lastIndex = file.lastIndexOf("/");
  33. String dirPath = file.substring(0, lastIndex + 1);
  34. String fileName = file.substring(lastIndex + 1, file.length());
  35. this.configFileName = fileName;
  36. configurationChanged(file);
  37. startWatcher(dirPath, fileName);
  38. }
  39. private void startWatcher(String dirPath, String file) throws IOException {
  40. final WatchService watchService = FileSystems.getDefault().newWatchService();
  41. //Define the file and type of events which the watch service should handle
  42. Path path = Paths.get(dirPath);
  43. path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
  44. Runtime.getRuntime().addShutdownHook(new Thread() {
  45. public void run() {
  46. try {
  47. watchService.close();
  48. } catch (IOException e) {
  49. e.printStackTrace();
  50. }
  51. }
  52. });
  53. WatchKey key = null;
  54. while (true) {
  55. try {
  56. key = watchService.take();
  57. for (WatchEvent< ?> event : key.pollEvents()) {
  58. if (event.context().toString().equals(configFileName)) {
  59. //From here the configuration change callback is triggered
  60. configurationChanged(dirPath + file);
  61. }
  62. }
  63. boolean reset = key.reset();
  64. if (!reset) {
  65. System.out.println("Could not reset the watch key.");
  66. break;
  67. }
  68. } catch (Exception e) {
  69. System.out.println("InterruptedException: " + e.getMessage());
  70. }
  71. }
  72. }
  73. }

2)添加Log4jConfigurator,这是您的应用与 log4j 协作的接口

此类是一个工具类,它将 log4j 初始化代码和重载策略与应用代码分开。

Log4jConfigurator.java

  1. package com.howtodoinjava.demo;
  2. public class Log4jConfigurator
  3. {
  4. //This ensures singleton instance of configurator
  5. private final static Log4jConfigurator INSTANCE = new Log4jConfigurator();
  6. public static Log4jConfigurator getInstance()
  7. {
  8. return INSTANCE;
  9. }
  10. //This method will start the watcher service of log4j.xml file and also configure the loggers
  11. public void initilize(final String file) {
  12. try
  13. {
  14. //Create the watch service thread and start it.
  15. //I will suggest to use some logic here which will check if this thread is still alive;
  16. //If thread is killed then restart the thread
  17. Log4jChangeWatcherService listner = new Log4jChangeWatcherService(file);
  18. //Start the thread
  19. new Thread(listner).start();
  20. }
  21. catch (Exception e)
  22. {
  23. e.printStackTrace();
  24. }
  25. }
  26. }

3)测试 log4j 重载事件

为了测试代码,我记录了两个两个语句:一个调试级别和一个信息级别。 两个语句在循环 2 秒后都被记录。 我将在一些日志语句之后更改日志记录级别,并且应该重新加载 log4j。

log4j-config.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
  3. <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
  4. <appender name="console" class="org.apache.log4j.ConsoleAppender">
  5. <param name="Target" value="System.out"/>
  6. <layout class="org.apache.log4j.PatternLayout">
  7. <param name="ConversionPattern" value="[%t] %-5p %c %x - %m%n"/>
  8. </layout>
  9. </appender>
  10. <root>
  11. <priority value ="info" />
  12. <appender-ref ref="console" />
  13. </root>
  14. </log4j:configuration>

Log4jConfigReloadExample.java

  1. package com.howtodoinjava.demo;
  2. import org.apache.log4j.Logger;
  3. public class Log4jConfigReloadExample
  4. {
  5. private static final String LOG_FILE_PATH = "C:/Lokesh/Setup/workspace/Log4jReloadExample/log4j-config.xml";
  6. public static void main(String[] args) throws InterruptedException
  7. {
  8. //Configure logger service
  9. Log4jConfigurator.getInstance().initilize(LOG_FILE_PATH);
  10. //Get logger instance
  11. Logger LOGGER = Logger.getLogger(Log4jConfigReloadExample.class);
  12. //Print the log messages and wait for log4j changes
  13. while(true)
  14. {
  15. //Debug level log message
  16. LOGGER.debug("A debug message !!");
  17. //Info level log message
  18. LOGGER.info("A info message !!");
  19. //Wait between log messages
  20. Thread.sleep(2000);
  21. }
  22. }
  23. }
  24. Output:
  25. [main] INFO com.howtodoinjava.demo.Log4jConfigReloadExample - A info message !!
  26. [main] INFO com.howtodoinjava.demo.Log4jConfigReloadExample - A info message !!
  27. [main] INFO com.howtodoinjava.demo.Log4jConfigReloadExample - A info message !!
  28. [main] INFO com.howtodoinjava.demo.Log4jConfigReloadExample - A info message !!
  29. [main] INFO com.howtodoinjava.demo.Log4jConfigReloadExample - A info message !!
  30. Log4j configuration file changed. Reloading logging levels !!
  31. [main] DEBUG com.howtodoinjava.demo.Log4jConfigReloadExample - A debug message !!
  32. [main] INFO com.howtodoinjava.demo.Log4jConfigReloadExample - A info message !!
  33. [main] DEBUG com.howtodoinjava.demo.Log4jConfigReloadExample - A debug message !!
  34. [main] INFO com.howtodoinjava.demo.Log4jConfigReloadExample - A info message !!

祝您学习愉快!