在之前的『从0到1理解Java Web』的『日志框架』部分,我们知道了如何让项目打印日志在控制台上,方便我们调试观察代码的运行,这篇文章主要是介绍如何把日志打印输出到服务器文件上保存起来,上线后借助日志文件找到Bug。
这里分3部分,一个是流的概念,一个是log4j配置,另一个是打印spring自身的日志。
流
在linux中有流的概念,从一个地方流入(比如键盘,比如扫描仪,比如文件),流出到另一个地方(比如控制台,比如文件,比如屏幕),上一次我们实现了『从日志系统流出到控制台』,这次实现『从日志系统流出到文件』即可。
把日志的去向从控制台改到文件,需要改动哪里?这牵扯到第二部分,也就是log4j的配置。
log4j配置
log4j有3个组件,loggers/appenders/layouts,它们一起协同工作,指定了日志内容的格式,根据日志的类型与级别,将日志输出到指定的位置。
loggers
指定日志输出的最低级别,把级别信息传给appenders。
日志级别由低到高分别是:Trace < Debug < Info < Warn < Error < Fatal,只记录大于等于当前级别的信息。
appenders
指定日志的输出方式与保存位置。
主要有以下几类appender:
1.ConsoleAppender :将日志输出至控制台
2.DailyRollingFileAppender :将日志输出至文件,日志文件每天切割
3.FileAppender :将日志输出至文件
4.RollingFileAppender :将日志输出至文件,日志文件按指定的大小进行切割
5.WriterAppender :将日志以信息流的格式发送到指定位置
layouts
指定日志内容的格式,比如输出为Html等。
这3个组件的具体配置都在log4j.xml中。把lo4j4.xml修改为以下的内容:
1 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
| <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" packages="com.dianping"> <Properties> <Property name="log-path">/data/applogs/${sys:app.name}/logs</Property> <Property name="pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [${sys:app.name} ${hostName}}] [%-5level] [%t] [%c] - %msg%xEx%n</Property> <Property name="dw-pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} ${hostName} ${sys:app.name} %p %t %c %msg%xEx%n</Property> <Property name="scribeCategory">${sys:app.name}</Property> </Properties>
<Appenders> <RollingFile name="appAppender" fileName="${log-path}/app.log" filePattern="${log-path}/app.log.%d{yyyy-MM-dd}"> <PatternLayout pattern="${pattern}"/> <Policies> <TimeBasedTriggeringPolicy interval="1"/> </Policies> </RollingFile> <RollingFile name="errorAppender" fileName="${log-path}/error.log" filePattern="${log-path}/error.log.%d{yyyy-MM-dd}"> <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="${pattern}"/> <Policies> <TimeBasedTriggeringPolicy interval="1"/> </Policies> </RollingFile> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level [%c] - %msg%n"/> </Console> </Appenders>
<Loggers> <Root level="INFO"> <AppenderRef ref="appAppender"/> <AppenderRef ref="errorAppender"/> <AppenderRef ref="Console"/> </Root> </Loggers>
</Configuration>
|
另外建立classpath:META-INF下建立文件app.properties(即mai/resources/METa-INF下),在里面指定项目的名称,内容如下:
1
| app.name=my-project-name
|
随后启动项目,进入/data/applogs/my-project-name/logs目录,即可看到日志文件。
到这里,我们已经成功地将代码里的日志输出到文件里。每天保存,可是,如果你仔细点观察,会发现日志文件里并没有spring和其它第三方库的日志,这可是大问题,很多时候Bug是spring的bean注入失败或找不到对应的类引起的,如果没有spring的日志,我们很难追查到真正原因。
监听web运行中第三方库日志(如spring)
监听web运行时的日志,那么我们就能监听到所有日志,包括spring和其它技术栈的日志。
在web项目配置文件web.xml中加入对应的监听器,内容如下:
1 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
| <context-param> <param-name>log4jContextName</param-name> <param-value>poseidon-settlement-service</param-value> </context-param>
<context-param> <param-name>log4jConfiguration</param-name> <param-value>classpath:log4j2.xml</param-value> </context-param>
<listener> <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class> </listener>
<filter> <filter-name>log4jServletFilter</filter-name> <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class> </filter> <filter-mapping> <filter-name>log4jServletFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping>
<context-param> <param-name>log4jRefreshInterval</param-name> <param-value>60000</param-value> </context-param>
<listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener>
|
同时引入log4j-web包,启动项目,即可。