Log4j - 配置
笔记
日志能记录项目运行的一点一滴,生产上,我们也能通过日志快速定位和处理问题。本内容介绍 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 的话也不会补空格。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# SpringBoot配置
log4j 的配置文件分为两种,log4j.xml
和 log4j.properties
,推荐使用 log4j.xml。
引入依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
2
3
4
5
依赖、版本不唯一,请自行选择。
如何进行测试呢?首先在类上面加上 @Slf4j
注解,然后使用 log 对象即可,因为该注解自动创建了 log 全局对象,如下:
@Slf4j
public class Log4jTest {
public void test() {
log.debug("现在是早上六点,开始自动签到");
log.info("现在是早上六点,开始自动签到");
log.error("现在是早上六点,开始自动签到");
log.warn("现在是早上六点,开始自动签到");
}
}
2
3
4
5
6
7
8
9
这样运行项目后,就可以输出到控制台,如果您不单单想要输出到控制台,也想要输出到文件里,请看下面。
# log4j.xml详解
首先配置在 application.properties 或 application.yml 引用 log4j.xml,路径在 resource 下。
logging:
config: classpath:log4j.xml
2
log4j.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 -->
<!-- 修改日志输出目录,输出日志大小,项目指定扫描包即可使用 -->
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
我已经配置好了这个模板,你只需要修改的是 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 的日志信息,并「给自己」进行日志输出。 例子:
<logger name="org.springframework.web" level="info"/> <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/> <logger name="你的 controller 包路径" level="debug"/>
1
2
3注意 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"/>
1
2
3
4包名配置(建议)
<logger name="com.xxx.dao" level="DEBUG"/>
1
properties 文件配置:
全局配置(可选)
logging.level.org.apache.ibatis=DEBUG logging.level.org.mybatis=DEBUG logging.level.java.sql.Connection=DEBUG logging.level.java.sql.Statement=DEBUG
1
2
3
4包名配置(建议)
logging.level.com.xxx.dao=debug
1注意: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%n
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# log4js配置
我使用 JS 来配置 log4j 日志,是因为我的邮箱项目是基于 node 构建。但是其原理 Java 的log4j 类似。
本内容基于 node 进行 log4js 配置,其他框架的同理,只需要引入 log4js 即可使用日志功能。
# 安装
在 package.json 添加 log4js 依赖
"dependencies": {
"log4js": "^6.3.0",
}
2
3
我的完整 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"
}
}
2
3
4
5
6
7
8
9
10
11
12
13
安装依赖:
npm install
# 如果使用的是 yarn
yarn install
2
3
4
# 配置文件
安装完 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 」' }))
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
可能无法理解 29 行的 name,这个是引用 logger 时,传入的参数,根据这个参数,获取不同的日志输出格式,如下:
// 引入 info 日志
const logger = require("./log").logger();
// 引入 error 日志,传入错误日志的 name,对应 categories
const errLogger = require("./log").logger("error");
// 以下仅仅是测试,实际根据需求输出
logger.info("info 信息");
errLogger.error("error 信息")
2
3
4
5
6
7
8
日志文件路径以及名字如图:
access 日志内容如图:
图片内容和我给的代码不一样,因为这是我实际使用的日志输出。不一样的地方仅仅是 default - 后面的内容,前面的内容都是在配置文件配置好了格式,你输出的内容就会放到 default - 后面。