Java - 一篇带你解决 JDK Logger 日志配置失效问题

Posted 程序员牧码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java - 一篇带你解决 JDK Logger 日志配置失效问题相关的知识,希望对你有一定的参考价值。

问题描述

我一个项目在自己项目里面打印日志是生效的,但是一旦把这个项目 install 成 jar 包时,提供给其他项目引入 jar 使用后,再次触发打印这个 jar 里的日志时,原来的配置失效,这里特别指出的是时间格式化配置失效,因为后面通过日志 Level 能确定是生效的,但是时间格式化配置始终不生效。 

Jar 代码 

package com.jite.flow.engine;

import java.io.IOException;
import java.util.logging.LogManager;
import java.util.logging.Logger;

/**
 * @author Lux Sun
 * @date 2021/10/19
 */
public class LoggerBuilder {

    public static final Logger LOG = Logger.getLogger(LoggerBuilder.class.getName());

    static {
        if (System.getProperty("java.util.logging.config.file") == null &&
                System.getProperty("java.util.logging.config.class") == null) {
            try {
                LogManager.getLogManager().readConfiguration(LoggerBuilder.class.getResourceAsStream("/log.properties"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void build() {
        LOG.info("Load the Logger successfully");
    }
}
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=%1$tF %tT.%1$tL %4$s [%2$s] - %5$s %6$s%n

分析原因

默认情况下,JDK的LogManager会在JRE目录下的"lib/logging.properties"这个文件中读取配置。

除此之外,LogManager还可以根据两个系统属性来允许用户控制日志的配置

  • "java.util.logging.config.class"
  • "java.util.logging.config.file"

其中,class这个属性优先有效,如果设置,会忽略file这个属性。

而且关于 JAVA 代码中的日志级别的设置,在JDK中实际上是有默认的日志级别的。

在配置文件:%JAVA_HOME%\\jre\\lib\\logging.properties中;如果JAVA设置的级别比配置文件中配置的还要低,则以配置文件中配置的为准,如果比配置文件中的高,则以程序中配置的为准。

解决方案

Java中设置属性也有两种方法

  • Preferences API
  • 启动的时候,命令行参数

使用Preferences API设置如下

System.setProperty("java.util.logging.config.class", "Your class");

System.setProperty("java.util.logging.config.file", "Your properties file");

设置之后需要调用以下代码方可生效:

LogManager.getLogManager().readConfiguration();

命令行参数是指,启动的时候用 -D<name>=<value>的方式指定属性,具体到这里,我们就可以用

java -Djava.util.logging.config.file=abc.properties YourMainClass

指定使用 abc.properties 这个文件作为配置文件。如果需要,可以加上文件的路径名。

Tomcat 指定日志配置文件就是使用的命令行参数,用记事本打开 ${tomcat_home}/bin/catalina.bat 文件,可以看到如下内容

if not "%LOGGING_CONFIG%" == "" goto noJuliConfig
set LOGGING_CONFIG=-Dnop
if not exist "%CATALINA_BASE%\\conf\\logging.properties" goto noJuliConfig
set LOGGING_CONFIG=-Djava.util.logging.config.file="%CATALINA_BASE%\\conf\\logging.properties"
:noJuliConfig
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%

一个简单的自定义配置文件如下

############################################################
#  	Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.  
# For example java -Djava.util.logging.config.file=myfile
############################################################

############################################################
#  	Global properties
############################################################

# "handlers" specifies a comma separated list of log Handler 
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler

# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

# default file output is in user's home directory.
#java.util.logging.FileHandler.pattern = %h/java%u.log
#java.util.logging.FileHandler.pattern = ..\\\\logs\\\\logger.log
java.util.logging.FileHandler.pattern = C:\\\\zzj\\\\logger.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
#java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
#java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.formatter = java.util.logging.XMLFormatter


############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################

# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE

在默认配置文件的基础上添加了FileHandler,并且指定日志文件路径为C:\\\\zzj\\\\logger.log,使用SimpleFormatter格式化输出。

注意:日志文件路径不能直接在盘符下,例如不能指定日志文件路径为C:\\\\logger.log。

当然,这里还引发另一个问题

我试图在我的应用程序启动时加载自定义log.properties文件。

我的属性文件和我的主类在同一个包中,所以我认为如下命令行参数应该加载属性文件。

-Djava.util.logging.config.file=log.properties

但是,只有当我指定属性文件的完整绝对路径时才加载属性。任何建议如何使用相对路径?

Java日志记录不会搜索整个硬盘中的文件;有很简单的规则如何查找文件。你希望Java能够看到这两个文件是属于彼此的,但是你没有在任何地方说过。由于Java认为属性文件和类之间没有连接,除非它们位于磁盘上的相同文件夹中,所以它找不到该文件。

-Djava.util.logging.config.file=log.properties

仅适用于文件log.properties位于Java进程的当前目录中(可能非常随机)。所以你应该在这里使用绝对路径。

另一种解决方案是将文件logging.properties移动到$JAVA_HOME/lib/(或编辑应该在那里的文件)。在这种情况下,您不需要设置系统属性。

util logging不从类路径加载,它需要一个绝对路径,这就是为什么其他日志包如log4j更容易配置,并且更适合web应用程序,这对于获取abs路径是一件痛苦的事情。

这在java.util.logging.LogManager doco中根本没有解释。

以上是关于Java - 一篇带你解决 JDK Logger 日志配置失效问题的主要内容,如果未能解决你的问题,请参考以下文章

Java - 一篇带你了解类成员(基本数据类型/包装类/对象/数组)默认值

Java - 一篇带你了解类成员(基本数据类型/包装类/对象/数组)默认值

MyBatis-Plus - 一篇带你解决自定义 SQL 注入器失效必杀技

一篇带你搞懂 java 集合

一篇带你搞懂 java 集合

Javaの一篇带你吃透接口