Log4j - 配置
NOTE
日志能记录项目运行的一点一滴,生产上,我们也能通过日志快速定位和处理问题。本内容介绍 log4j 的一些基本使用,以及在 JS、SpringBoot 下的配置模板。
2021-12-24 @Young Kbt
什么是日志框架
我们在系统中对于记录日志的需求并不单纯。首先,我们希望日志要能持久化到磁盘,最基本的就是要能够保存到文件中;其次,我们希望在开发和生产环境中记录的日志并不相同,明显开发环境的日志记录会更多方便调试,但放到生产环境下大量的日志很容易会撑爆服务器,因此在生产环境我们希望只记录重要信息。
基于不单纯的目的,System.out.println 是直接不能满足我们的要求,因此抛弃它,选择功能更强的日志框架。而 log4j 是 apache 下一款著名的开源日志框架,log4j 满足上面的一切需求。
记录日志的框架并不仅仅只有 log4j,比较有名的还有 logback 等,现在比较火的 Spring Boot 默认集成的日志就是 logback。不管哪种日志框架,一般都能够实现日志的持久化功能。
日志框架介绍
Log4j 是 Apache 下的一款开源的日志框架,能够满足我们在项目中对于日志记录的需求。一般来讲,在项目中,我们会结合 slf4j 和 log4j 一起使用。Log4j 提供了简单的 API 调用,强大的日志格式定义以及灵活的扩展性。我们可以自己定义 Appender 来满足我们对于日志输出的需求。
Log4j 由三个重要的组件构成:日志信息的优先级(Logger),日志信息的输出目的地(Appender),日志信息的输出格式(Layout)。
日志信息的优先级别分为四级,优先级从低到高有 DEBUG、INFO、WARN、ERROR,用来指定这条日志信息的重要程度
日志信息的输出目的地指定了日志将打印到控制台还是文件中,官方已经默认给我们提供了大量的 Appender,基本上可以满足我们的日常需求,当然如果你的需求比较特殊,可以自己实现 Appender,也是非常简单的
日志信息的输出格式则控制了日志信息的显示内容
注意:从源码知道,Log4j 日志级别是定义在
org.apache.log4j.Level类中。Log4j 只建议使用 4 个级别,优先级从高到低分别是 ERROR、WARN、INFO、DEBUG。
off 最高等级,用于关闭所有日志记录。
fatal 指出每个严重的错误事件将会导致应用程序的退出。
error 指出虽然发生错误事件,但仍然不影响系统的继续运行。
warm 表明会出现潜在的错误情形。
info 一般和在粗粒度级别上,强调应用程序的运行全程。
debug 一般用于细粒度级别上,对调试应用程序非常有帮助。
TRACE 一般用于更细粒度级别上,比 debug 级别更低
all 最低等级,用于打开所有日志记录。
日志的输出格式配置如下:
%p:输出日志信息的优先级,即 DEBUG,INFO,WARN,ERROR,FATAL。
%d:输出日志时间点的日期或时间,默认格式为 ISO8601,也可以在其后指定格式,如:%d{yyyy/MM/dd HH:mm:ss,SSS}。
%r:输出自应用程序启动到输出该 log 信息耗费的毫秒数。
%t:输出产生该日志事件的线程名。
%l:输出日志事件的发生位置,相当于 %c.%M(%F:%L) 的组合,包括类全名、方法、文件名以及在代码中的行数。例如:test.TestLog4j.main(TestLog4j.java:10)。
%c:输出日志信息所属的类目,通常就是所在类的全名。
%M:输出产生日志信息的方法名。
%F:输出日志消息产生时所在的文件名称。
%L::输出代码中的行号。
%m::输出代码中指定的具体日志信息。
%n:输出一个回车换行符,Windows平台为 "/r/n" ,Unix平台为 "/n"。
%x:输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像 java servlets 这样的多客户多线程的应用中。
%%:输出一个 "%" 字符。
另外,还可以在%与格式字符之间加上修饰符来控制其最小长度、最大长度、和文本的对齐方式。如:
%20c:指定输出 category 的名称,最小的长度是 20,如果 category 的名称长度小于 20 的话,默认的情况下右对齐。
%-20c:"-" 号表示左对齐。
%.30c:指定输出 category 的名称,最大的长度是 30,如果 category 的名称长度大于 30 的话,就会将左边多出的字符截掉,但小于 30 的话也不会补空格。SpringBoot 配置
log4j 的配置文件分为两种,log4j.xml 和 log4j.properties,推荐使用 log4j.xml。
引入依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>依赖、版本不唯一,请自行选择。
如何进行测试呢?首先在类上面加上 @Slf4j 注解,然后使用 log 对象即可,因为该注解自动创建了 log 全局对象,如下:
@Slf4j
public class Log4jTest {
public void test() {
log.debug("现在是早上六点,开始自动签到");
log.info("现在是早上六点,开始自动签到");
log.error("现在是早上六点,开始自动签到");
log.warn("现在是早上六点,开始自动签到");
}
}这样运行项目后,就可以输出到控制台,如果您不单单想要输出到控制台,也想要输出到文件里,请看下面。
log4j.xml 详解
首先配置在 application.properties 或 application.yml 引用 log4j.xml,路径在 resource 下。
logging:
config: classpath:log4j.xmllog4j.xml 内容:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为 TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为 WARN,则低于 WARN 的信息都不会输出 -->
<!-- scan:当此属性设置为 true 时,配置文档如果发生改变,将会被重新加载,默认值为 true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
当 scan 为 true 时,此属性生效。默认的时间间隔为 1 分钟。 -->
<!-- debug:当此属性设置为 true 时,将打印出 logback 内部日志信息,实时查看 logback 运行状态。默认值为 false -->
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback-spring</contextName>
<!-- name 的值是变量的名称,value 的值时变量定义的值。通过定义的值会被插入到 logger 上下文中。定义后,可以使 ${} 来使用变量。 -->
<!-- 如果是 Windows,则 value="D:/logs" 类似 -->
<property name="logging.path" value="/ROOT/logs" />
<!-- 当天日志的文件名 -->
<property name="logFile.name" value="bx" />
<!-- 时间归档日志的文件名 -->
<property name="logDateFile.name" value="bx" />
<!-- 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.CTT}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--1. 输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志 appender 是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--2. 输出到文档-->
<!-- 2.1 level 为 DEBUG 日志,按时间滚动输出 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${logging.path}/${logFile.name}_debug.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.CTT} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${logging.path}/${logDateFile.name}_debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是 10MB -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录 DEBUG 级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.2 level 为 INFO 日志,时间滚动输出 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${logging.path}/${logFile.name}_info.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.CTT} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${logging.path}/${logDateFile.name}_info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是 10MB -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录 INFO 级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.3 level为 WARN 日志,时间滚动输出 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${logging.path}/${logFile.name}_warn.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.CTT} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logging.path}/${logDateFile.name}_warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是 10MB -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录 WARN 级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.4 level为 ERROR 日志,时间滚动输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${logging.path}/${logFile.name}_error.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.CTT} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logging.path}/${logDateFile.name}_error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是 10MB -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录 ERROR 级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--
File 标签是日志文件的输出地址:必须要为 ${LOG_PATH}/${LOG_FILE}。
level 标签:如果设置了 level 为 info,只会输出 info 的日志信息,其他日志级别的日志就会过滤掉,
appender 的 level 标签优先级最高,如果指定了,则其他标签的 level 将会失效。
-->
<!--
<logger> 用来设置某一个包或者具体的某一个类的日志打印级别,以及指定 <appender>。
<logger> 仅有一个 name 属性,一个可选的 level 和一个可选的 addtivity 属性。
name:用来指定受此 logger 约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
还有一个特俗值 INHERITED 或者同义词 NULL,代表强制执行上级的级别。
如果未设置此属性,那么当前 logger 将会继承上级的级别(appender 里指定的),
优先级高于 root 的 level,低于 appender 的 level。
addtivity:是否传递打印信息给上级的其他的 logger 或者 root 节点。默认是 true。
为 ture,意思是日志级别高的其他 logger 或 root 都会捕获到该 looger 的日志信息,并「给自己」进行日志输出。
例子:
<logger name="org.springframework.web" level="info"/>
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
<logger name="你的 controller 包路径" level="debug"/>
注意 logger 里的 level 是一个下限,比其日志级别高的日志信息也会输出。
-->
<!--
使用 mybatis 的时候,sql 语句是 debug 下才会打印,而这里我们只配置了 info,所以想要查看 sql 语句的话,有以下两种操作:
第一种把 <root level="info"> 改成 <root level="DEBUG">,这样就会打印 sql,不过这样日志那边会出现很多其他消息。
第二种就是单独给 dao 层下目录配置 debug 模式,这样配置 sql 语句会打印,其他还是正常 info 级别:
XML 文件配置:
全局配置(可选)
<logger name="com.apache.ibatis" level="DEBUG"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
包名配置(建议)
<logger name="com.xxx.dao" level="DEBUG"/>
properties 文件配置:
全局配置(可选)
logging.level.org.apache.ibatis=DEBUG
logging.level.org.mybatis=DEBUG
logging.level.java.sql.Connection=DEBUG
logging.level.java.sql.Statement=DEBUG
包名配置(建议)
logging.level.com.xxx.dao=debug
注意:com.xxx.dao 是你的包名。
-->
<!--
root 节点是必选节点,用来指定最基础的日志输出级别,只有一个 level 属性。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
不能设置为 INHERITED 或者同义词 NULL。默认是 DEBUG,不设置 level 不会输出到文件。
可以包含零个或多个元素,标识这个 appender 将会添加到这个 logger。
其输出会受到 logger 的影响,即注意 logger 中的 additivity 属性,如果为 false,则指定的包名下的日志不会输出。
-->
<!-- 4. 最终的策略 -->
<!-- 4.1 开发环境:打印控制台-->
<springProfile name="dev">
<!-- 修改此处的扫描包名,指定这个包的日志级别最低下限 -->
<logger name="com.glyxybxhtxt.controller" level="debug"/>
<!-- logger 的 level 是一个下限,所有大于这个下限的日志级别都会输出 -->
</springProfile>
<!--
因为 logger 指定了 level 的下限和 addtivity 默认为 true ,所以 root 的 level 可以不写。
root 能捕获 level 低的 logger 的日志信息,是因为 addtivity 为 true,从而导致 logger 的 level 优先级比 root 高。
-->
<root level="info">
<!--
appender-ref 是 appender 的引用。
如果 appender 里指定了 level,则只按照 appender 里的 level 进行输出。
-->
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
<!-- 4.2 生产环境:输出到文档
<springProfile name="pro">
<root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="WARN_FILE" />
</root>
</springProfile> -->
</configuration>
<!-- level 优先级:appender > logger > root -->
<!-- 修改日志输出目录,输出日志大小,项目指定扫描包即可使用 -->我已经配置好了这个模板,你只需要修改的是 12 - 16 行的日志路径以及名字。
File 标签是日志文件的输出地址:必须要为 ${LOG_PATH}/${LOG_FILE}。
level 标签:如果设置了 level 为 info,只会输出 info 的日志信息,其他日志级别的日志就会过滤掉,appender 的 level 标签优先级最高,如果指定了,则其他标签的 level 将会失效。
logger 用来设置某一个包或者具体的某一个类的日志打印级别,以及指定 appender。logger 仅有一个 name 属性,一个可选的 level 和一个可选的 addtivity 属性。
name:用来指定受此 logger 约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特俗值 INHERITED 或者同义词 NULL,代表强制执行上级的级别。如果未设置此属性,那么当前 logger 将会继承上级的级别(appender 里指定的),优先级高于 root 的 level,低于 appender 的 level。
addtivity:是否传递打印信息给上级的其他的 logger 或者 root 节点。默认是 true。如果为 ture,意思是日志级别高的其他 logger 或 root 都会捕获到该 looger 的日志信息,并「给自己」进行日志输出。 例子:
xml<logger name="org.springframework.web" level="info"/> <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/> <logger name="你的 controller 包路径" level="debug"/>注意 logger 里的 level 是一个下限,比其日志级别高的日志信息也会输出。
使用 mybatis 的时候,sql 语句是 debug 下才会打印,而这里我们只配置了 info,所以想要查看 sql 语句的话,有以下两种操作:
第一种把
<root level="info">改成<root level="DEBUG">,这样就会打印 sql,不过这样日志那边会出现很多其他消息。第二种就是单独给 dao 层下目录配置 debug 模式,这样配置 sql 语句会打印,其他还是正常 info 级别,如下: XML 文件配置:
全局配置(可选)
xml<logger name="com.apache.ibatis" level="DEBUG"/> <logger name="java.sql.Connection" level="DEBUG"/> <logger name="java.sql.Statement" level="DEBUG"/> <logger name="java.sql.PreparedStatement" level="DEBUG"/>包名配置(建议)
xml<logger name="com.xxx.dao" level="DEBUG"/>
properties 文件配置:
全局配置(可选)
propertieslogging.level.org.apache.ibatis=DEBUG logging.level.org.mybatis=DEBUG logging.level.java.sql.Connection=DEBUG logging.level.java.sql.Statement=DEBUG包名配置(建议)
propertieslogging.level.com.xxx.dao=debug注意:com.xxx.dao 是你的包名。
root 节点是必选节点,用来指定最基础的日志输出级别,只有一个 level 属性。
- level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能设置为 INHERITED 或者同义词 NULL。默认是 DEBUG,不设置 level 不会输出到文件。可以包含零个或多个元素,标识这个 appender 将会添加到这个 logger。其输出会受到 logger 的影响,即注意 logger 中的 additivity 属性,如果为 false,则指定的包名下的日志不会输出。
对比 12 - 16 行的日志路径以及名字。路径以及名字的效果如图:

INFO 日志内容的效果如图:

ERROR 日志内容的效果如图:

log4j.properties 详解
如果不喜欢在 log4j.xml 配置,那么也可以在 log4j.properties 配置,但是我建议在 xml 配置。
## 设置全局日志 Logger
log4j.rootLogger=DEBUG,CONSOLE,FILEOUT
# DEBUG、CONSOLE、FILE、ROLLING_FILE、MAIL、DATABASE
log4j.addivity.org.apache=true
## 输出控制台 Appender ##
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p][%d{yyyy-MM-dd HH\:mm\:ss,SSS}][%c] \:%m%n
## 另外两种输出格式,可选
# log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n\u00A0
# log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n
## 输出 DEBUG 级别以上的日志到 E://logs/debug.log
log4j.appender.D=org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File=E://logs/log.log
log4j.appender.D.Append=true
log4j.appender.D.Threshold=DEBUG
log4j.appender.D.layout=org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
## 输出 ERROR 级别以上的日志到 E://logs/error.log
log4j.appender.E=org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File=E://logs/error.log
log4j.appender.E.Append=true
log4j.appender.E.Threshold=ERROR
log4j.appender.E.layout=org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
## ...... 其他级别的日志同理
## 日志发生到服务器 Appender
#log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
#log4j.appender.SOCKET.RemoteHost=localhost
#log4j.appender.SOCKET.Port=7272
#log4j.appender.SOCKET.LocationInfo=true
## Set up for Log Facter 5
#log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
#log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n
## Log Factor 5 Appender
#log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
#log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
## 日志发生到邮箱 Appender
#log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
#log4j.appender.MAIL.Threshold=FATAL
#log4j.appender.MAIL.BufferSize=10
#log4j.appender.MAIL.From=openwolfl@163.com
#log4j.appender.MAIL.SMTPHost=mail.openwolf.com
#log4j.appender.MAIL.Subject=Log4J Message
#log4j.appender.MAIL.To=openwolfl@163.com
#log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
#log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
## JDBC Appender
#log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
#log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
#log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
#log4j.appender.DATABASE.user=root
#log4j.appender.DATABASE.password=123456
#log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
#log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
#log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
#log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
#log4j.appender.A1.File=SampleMessages.log4j
#log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
#log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout
### 自定义 Appender
#log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
#log4j.appender.im.host = mail.cybercorlin.net
#log4j.appender.im.username = username
#log4j.appender.im.password = password
#log4j.appender.im.recipient = 2456019588@qq.com
#log4j.appender.im.layout=org.apache.log4j.PatternLayout
#log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%nlog4js 配置
我使用 JS 来配置 log4j 日志,是因为我的邮箱项目是基于 node 构建。但是其原理 Java 的 log4j 类似。
本内容基于 node 进行 log4js 配置,其他框架的同理,只需要引入 log4js 即可使用日志功能。
安装
在 package.json 添加 log4js 依赖
"dependencies": {
"log4js": "^6.3.0",
}我的完整 package.json 如下:
{
"name": "email",
"version": "1.0",
"private": true,
"scripts": {
"dev": "node app.js"
},
"dependencies": {
"express": "^4.17.1",
"log4js": "^6.3.0",
"nodemailer": "^6.7.2"
}
}安装依赖:
npm install
# 如果使用的是 yarn
yarn install配置文件
安装完 log4js 依赖,我们就可以引用这个依赖,并且配置日志的级别、输出内容、输出路径。
// 引入插件 log4js
var log4js = require("log4js");
log4js.configure({
appenders: {
access: {
// info 日志的 name
type: "file",
filename: "logs/access.log",
layout: {
type: "pattern",
pattern: "[%d{yyyy-MM-dd hh:mm:ss SSS}] [%p] %c - %m",
},
},
error: {
// 错误日志的 name
type: "file",
filename: "logs/error.log",
layout: {
// 定义日志输出的样式
type: "pattern",
pattern: "[%d{yyyy MM dd hh:mm:ss SSS}] [%p] %c - %m%n",
},
},
},
// 引用 appenders
categories: {
default: { appenders: ["access"], level: "info" }, // 上方 appenders 的 name
error: { appenders: ["error"], level: "error" },
},
});
exports.logger = function (name) {
// name 取 categories 的 name
return log4js.getLogger(name || "default"); // name 为undefined 时,取 default
};
exports.use = function (app, logger) {
app.use(
log4js.connectLogger(logger || log4js.getLogger("default"), {
level: "info",
format: "请求类型/URI:「 :method:url 」",
})
);
};可能无法理解 29 行的 name,这个是引用 logger 时,传入的参数,根据这个参数,获取不同的日志输出格式,如下:
// 引入 info 日志
const logger = require("./log").logger();
// 引入 error 日志,传入错误日志的 name,对应 categories
const errLogger = require("./log").logger("error");
// 以下仅仅是测试,实际根据需求输出
logger.info("info 信息");
errLogger.error("error 信息");日志文件路径以及名字如图:

access 日志内容如图:

图片内容和我给的代码不一样,因为这是我实际使用的日志输出。不一样的地方仅仅是 default - 后面的内容,前面的内容都是在配置文件配置好了格式,你输出的内容就会放到 default - 后面。