Log4j 的自定义 logger

来自姬鸿昌的知识库
Jihongchang讨论 | 贡献2023年2月25日 (六) 16:23的版本 →‎总结
跳到导航 跳到搜索

https://www.bilibili.com/video/BV1iJ411H74S?p=17

自定义 logger

log4j.properties

# 指定 RootLogger 顶级父元素默认配置信息
# 指定日志级别=trace,使用的 appender 为 console
log4j.rootLogger = trace,console

# 自定义 logger 对象设置
log4j.logger.io.github.jihch = info,file

# 指定控制台日志输出的 appender
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定消息格式 layout
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n

# 日志文件输出的 appender 对象
log4j.appender.file = org.apache.log4j.FileAppender
# 指定消息格式 layout
log4j.appender.file.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.file.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
# 指定日志文件的保存路径
log4j.appender.file.file = /logs/log4j.log
# 指定日志文件的字符集
log4j.appender.file.encoding = UTF-8

Log4jTest.java

import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;
import org.junit.Test;

public class Log4jTest {

    // 快速入门
    @Test
    public void testQuick() {

        // 开启 log4j 内置日志记录
        LogLog.setInternalDebugging(true);

        // 初始化配置信息,在入门案例中暂不使用配置文件
//        BasicConfigurator.configure();

        // 获取日志记录器对象
        Logger logger = Logger.getLogger(Log4jTest.class);

        // 日志记录输出
        logger.info("hello log4j");

        // 日志级别
        logger.fatal("fatal"); // 严重错误,一般会造成系统崩溃并终止运行

        logger.error("error"); // 错误信息,不会影响系统运行
        logger.warn("warn");   // 警告信息,可能会发生问题
        logger.info("info");   // 运行信息,数据连接、网络连接、IO 操作等等
        logger.debug("debug"); // 调试信息,一般在开发中使用,记录程序变量参数传递信息等等

        logger.debug("trace"); // 追踪信息,记录程序所有的流程信息

    }

}

控制台输出

log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@18b4aac2.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@18b4aac2.
log4j: Using URL [file:/E:/record/2023/2/19/log4j-demo/target/classes/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/E:/record/2023/2/19/log4j-demo/target/classes/log4j.properties
log4j: Parsing for [root] with value=[trace,console].
log4j: Level token is [trace].
log4j: Category root set to TRACE
log4j: Parsing appender named "console".
log4j: Parsing layout options for "console".
log4j: Setting property [conversionPattern] to [[%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n].
log4j: End of parsing for "console".
log4j: Parsed "console" options.
log4j: Parsing for [io.github.jihch] with value=[info,file].
log4j: Level token is [info].
log4j: Category io.github.jihch set to INFO
log4j: Parsing appender named "file".
log4j: Parsing layout options for "file".
log4j: Setting property [conversionPattern] to [[%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n].
log4j: End of parsing for "file".
log4j: Setting property [file] to [/logs/log4j.log].
log4j: Setting property [encoding] to [UTF-8].
log4j: setFile called: /logs/log4j.log, true
log4j: setFile ended
log4j: Parsed "file" options.
log4j: Handling log4j.additivity.io.github.jihch=[null]
log4j: Finished configuring.
[INFO      ]0 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:23) 2023-02-25 23:30:38.202 hello log4j
[FATAL     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:27) 2023-02-25 23:30:38.204 fatal
[ERROR     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:29) 2023-02-25 23:30:38.204 error
[WARN      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:30) 2023-02-25 23:30:38.204 warn
[INFO      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:31) 2023-02-25 23:30:38.204 info

Process finished with exit code 0

log4j.log

[INFO      ]0 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:23) 2023-02-25 23:30:38.202 hello log4j
[FATAL     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:27) 2023-02-25 23:30:38.204 fatal
[ERROR     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:29) 2023-02-25 23:30:38.204 error
[WARN      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:30) 2023-02-25 23:30:38.204 warn
[INFO      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:31) 2023-02-25 23:30:38.204 info

总结

log4j.properties 中 log4j.logger.io.github.jihch = info,file 中声明了 name 为“io.github.jihch”的一个自定义 logger,日志级别是 info,使用的 appender 是 file;

又因为 Logger logger = Logger.getLogger(Log4jTest.class); 获取 logger 对象时用的是 Log4jTest 的全限定类名 io.github.jihch.Log4jTest,所以得到的 logger 对象默认继承 name 为“io.github.jihch”的 logger,会使用 name 为“io.github.jihch”的 logger 的日志级别(info);又因为所有 logger 默认都会继承 RootLogger,同时也会使用 RootLogger 绑定的 appender 记录日志;

因为继承、使用了 RootLogger 绑定的 name 为 console 的 org.apache.log4j.ConsoleAppender,所以控制台中就记录了日志;

又因为继承了 name 为“io.github.jihch”的 logger 的日志级别(info),所以控制台中没有记录日志级别低于 info 的日志;

又因为继承了 name 为“io.github.jihch”的 name 为 file 的 org.apache.log4j.FileAppender,所以外部日志文件“/logs/log4j.log”中也会有响应的日志记录


自定义 logger 使用 additivity 禁用继承

对上面的场景,有时候我们不希望一条日志记录多个 appender,就可以使用 additivity 来配置禁用继承来的 appender

log4j.properties

# 指定 RootLogger 顶级父元素默认配置信息
# 指定日志级别=trace,使用的 appender 为 console
log4j.rootLogger = trace,console

# 自定义 logger 对象设置
log4j.additivity.io.github.jihch = false
log4j.logger.io.github.jihch = info,file

# 指定控制台日志输出的 appender
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定消息格式 layout
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n


# 日志文件输出的 appender 对象
log4j.appender.file = org.apache.log4j.FileAppender
# 指定消息格式 layout
log4j.appender.file.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.file.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
# 指定日志文件的保存路径
log4j.appender.file.file = /logs/log4j.log
# 指定日志文件的字符集
log4j.appender.file.encoding = UTF-8

Log4jTest.java

同上,不变

控制台输出

log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@18b4aac2.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@18b4aac2.
log4j: Using URL [file:/E:/record/2023/2/19/log4j-demo/target/classes/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/E:/record/2023/2/19/log4j-demo/target/classes/log4j.properties
log4j: Parsing for [root] with value=[trace,console].
log4j: Level token is [trace].
log4j: Category root set to TRACE
log4j: Parsing appender named "console".
log4j: Parsing layout options for "console".
log4j: Setting property [conversionPattern] to [[%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n].
log4j: End of parsing for "console".
log4j: Parsed "console" options.
log4j: Parsing for [io.github.jihch] with value=[info,file].
log4j: Level token is [info].
log4j: Category io.github.jihch set to INFO
log4j: Parsing appender named "file".
log4j: Parsing layout options for "file".
log4j: Setting property [conversionPattern] to [[%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n].
log4j: End of parsing for "file".
log4j: Setting property [file] to [/logs/log4j.log].
log4j: Setting property [encoding] to [UTF-8].
log4j: setFile called: /logs/log4j.log, true
log4j: setFile ended
log4j: Parsed "file" options.
log4j: Handling log4j.additivity.io.github.jihch=[false]
log4j: Setting additivity for "io.github.jihch" to false
log4j: Finished configuring.

Process finished with exit code 0

log4j.log

[INFO      ]0 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:23) 2023-02-25 23:30:38.202 hello log4j
[FATAL     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:27) 2023-02-25 23:30:38.204 fatal
[ERROR     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:29) 2023-02-25 23:30:38.204 error
[WARN      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:30) 2023-02-25 23:30:38.204 warn
[INFO      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:31) 2023-02-25 23:30:38.204 info
[INFO      ]0 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:23) 2023-02-25 23:59:19.342 hello log4j
[FATAL     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:26) 2023-02-25 23:59:19.344 fatal
[ERROR     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:28) 2023-02-25 23:59:19.344 error
[WARN      ]3 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:29) 2023-02-25 23:59:19.345 warn
[INFO      ]3 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:30) 2023-02-25 23:59:19.345 info

总结

可以发现,配置了 log4j.additivity.io.github.jihch = false 之后,控制台不再记录日志了


自定义 logger 示例2

log4j.properties

# 指定 RootLogger 顶级父元素默认配置信息
# 指定日志级别=trace,使用的 appender 为 console
log4j.rootLogger = trace,console

# 自定义 logger 对象设置
log4j.logger.io.github.jihch = info,file
log4j.logger.org.apache = error


# 指定控制台日志输出的 appender
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定消息格式 layout
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n


# 日志文件输出的 appender 对象
log4j.appender.file = org.apache.log4j.FileAppender
# 指定消息格式 layout
log4j.appender.file.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.file.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
# 指定日志文件的保存路径
log4j.appender.file.file = /logs/log4j.log
# 指定日志文件的字符集
log4j.appender.file.encoding = UTF-8

Log4jTest.java

import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;
import org.junit.Test;

public class Log4jTest {

    // 快速入门
    @Test
    public void testQuick() {

        // 开启 log4j 内置日志记录
        LogLog.setInternalDebugging(true);

        // 初始化配置信息,在入门案例中暂不使用配置文件
//        BasicConfigurator.configure();

        // 获取日志记录器对象
        Logger logger = Logger.getLogger(Log4jTest.class);

        // 日志记录输出
        logger.info("hello log4j");

        // 日志级别
        logger.fatal("fatal"); // 严重错误,一般会造成系统崩溃并终止运行

        logger.error("error"); // 错误信息,不会影响系统运行
        logger.warn("warn");   // 警告信息,可能会发生问题
        logger.info("info");   // 运行信息,数据连接、网络连接、IO 操作等等
        logger.debug("debug"); // 调试信息,一般在开发中使用,记录程序变量参数传递信息等等

        logger.debug("trace"); // 追踪信息,记录程序所有的流程信息

        // 再创建一个日志记录器对象
        Logger logger1 = Logger.getLogger(Logger.class);
        logger1.fatal("fatal"); // 严重错误,一般会造成系统崩溃并终止运行

        logger1.error("error"); // 错误信息,不会影响系统运行
        logger1.warn("warn");   // 警告信息,可能会发生问题
        logger1.info("info");   // 运行信息,数据连接、网络连接、IO 操作等等
        logger1.debug("debug"); // 调试信息,一般在开发中使用,记录程序变量参数传递信息等等

        logger1.debug("trace"); // 追踪信息,记录程序所有的流程信息

    }

}

控制台

log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@18b4aac2.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@18b4aac2.
log4j: Using URL [file:/E:/record/2023/2/19/log4j-demo/target/classes/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/E:/record/2023/2/19/log4j-demo/target/classes/log4j.properties
log4j: Parsing for [root] with value=[trace,console].
log4j: Level token is [trace].
log4j: Category root set to TRACE
log4j: Parsing appender named "console".
log4j: Parsing layout options for "console".
log4j: Setting property [conversionPattern] to [[%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n].
log4j: End of parsing for "console".
log4j: Parsed "console" options.
log4j: Parsing for [io.github.jihch] with value=[info,file].
log4j: Level token is [info].
log4j: Category io.github.jihch set to INFO
log4j: Parsing appender named "file".
log4j: Parsing layout options for "file".
log4j: Setting property [conversionPattern] to [[%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n].
log4j: End of parsing for "file".
log4j: Setting property [file] to [/logs/log4j.log].
log4j: Setting property [encoding] to [UTF-8].
log4j: setFile called: /logs/log4j.log, true
log4j: setFile ended
log4j: Parsed "file" options.
log4j: Handling log4j.additivity.io.github.jihch=[null]
log4j: Parsing for [org.apache] with value=[error].
log4j: Level token is [error].
log4j: Category org.apache set to ERROR
log4j: Handling log4j.additivity.org.apache=[null]
log4j: Finished configuring.
[INFO      ]0 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:23) 2023-02-26 00:14:37.192 hello log4j
[FATAL     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:26) 2023-02-26 00:14:37.194 fatal
[ERROR     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:28) 2023-02-26 00:14:37.194 error
[WARN      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:29) 2023-02-26 00:14:37.194 warn
[INFO      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:30) 2023-02-26 00:14:37.194 info
[FATAL     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:37) 2023-02-26 00:14:37.194 fatal
[ERROR     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:39) 2023-02-26 00:14:37.194 error

Process finished with exit code 0

/logs/log4j.log

[INFO      ]0 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:23) 2023-02-25 23:30:38.202 hello log4j
[FATAL     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:27) 2023-02-25 23:30:38.204 fatal
[ERROR     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:29) 2023-02-25 23:30:38.204 error
[WARN      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:30) 2023-02-25 23:30:38.204 warn
[INFO      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:31) 2023-02-25 23:30:38.204 info
[INFO      ]0 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:23) 2023-02-25 23:59:19.342 hello log4j
[FATAL     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:26) 2023-02-25 23:59:19.344 fatal
[ERROR     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:28) 2023-02-25 23:59:19.344 error
[WARN      ]3 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:29) 2023-02-25 23:59:19.345 warn
[INFO      ]3 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:30) 2023-02-25 23:59:19.345 info
[INFO      ]0 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:23) 2023-02-26 00:14:37.192 hello log4j
[FATAL     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:26) 2023-02-26 00:14:37.194 fatal
[ERROR     ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:28) 2023-02-26 00:14:37.194 error
[WARN      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:29) 2023-02-26 00:14:37.194 warn
[INFO      ]2 io.github.jihch.Log4jTest.testQuick(Log4jTest.java:30) 2023-02-26 00:14:37.194 info

总结

log4j.properties 中新增加了 logger 对象的配置 log4j.logger.org.apache = error,未声明 appender,则仅使用继承的 appender,也就是 RootLogger 的 name 为“console”、类型是 “org.apache.log4j.ConsoleAppender”的 appender,将会记录日志到控制台;

Log4jTest.java 中新增了 logger 对象和使用:

        // 再创建一个日志记录器对象
        Logger logger1 = Logger.getLogger(Logger.class);
        logger1.fatal("fatal"); // 严重错误,一般会造成系统崩溃并终止运行

        logger1.error("error"); // 错误信息,不会影响系统运行
        logger1.warn("warn");   // 警告信息,可能会发生问题
        logger1.info("info");   // 运行信息,数据连接、网络连接、IO 操作等等
        logger1.debug("debug"); // 调试信息,一般在开发中使用,记录程序变量参数传递信息等等

        logger1.debug("trace"); // 追踪信息,记录程序所有的流程信息

因为 Logger.class 的全限定名为“org.apache.log4j.Logger”,所以就应用了继承自 name 为“org.apache”的 logger 的日志级别和 appender,所以日志记录到了控制台中;

且没有记录日志级别低于 error 的日志;