日志在应用中发挥着作用,是应用的重要组成部分。日志用于记录应用的行为,记录应用的输入输出等,根据日志文件可以定位问题,挖掘数据,优化性能,统计应用各类指标,还原应用输入输出等重要功能,下面是一个Java应用使用log4j打印日志的简单例子。
一、日志根据内容的不同区分出不同的日志,需要根据应用需求而定。以下为根据需求,定义几个不同日志。如:
1. 记录应用的输入输出的access log,其中包含一次pv(请求)的详细信息,一次pv包含两行日志,一行请求,一行响应,请求中包括时间戳,pvid,请求URL,请求ip,请求参数等,响应中包括时间戳,pvid,响应结果等。
2. 记录应用行为的error log,包括时间,堆栈信息,线程信息,错误信息,应用代码打印信息等
3. 记录数据的service log,内容根据需要记录的数据而定。
4. 开发阶段、测试使用的console log,内容一般为最全的log,包含其他各种log。
二、系统中引入log4j
1,引入依赖
2,应用web.xml中增加配置
log4jConfigLocation
classpath:log4j.xml
3,web.xml中增加监听
org.springframework.web.util.Log4jConfigListener
4,增加log4j配置文件,通常为log4j.properties或者log4j.xml配置文件
三、Log4j组件简介
log4j有三个重要的组件:Loggers(记录器),Appenders(输出源)和Layouts(布局)。可以通俗的理解为,不同的日志,输出到什么地方,以什么样的格式输出,综合这三个组件就可以以不同的形式(Layouts)打印不同级别(Loggers)的日志到不同的地方(Appenders)。现就三个组件做简单介绍:
1,Loggers
Loggers组件默认有5个级别,即DEBUG,INFO,WARN,ERROR,FATAL,五个日志的级别是DEBUG
2,Appenders
log4j提供了把日志输出道不同地方的功能,如控制台(console),文件(Files),可以根据时间或者文件大小产生新的日志文件,也可以以流的方式发送到其他地方(邮件,数据库,文件系统)等。
常用的Appenders类如下:
org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
Appender配置方法
log4j.appender.appenderName=className
log4j.appender.appenderName.O1=xxx1
... ...
log4j.appender.appenderName.ON=xxxN
3,Layouts
Log4j在Appenders中增加Layouts来定义日志格式,Layouts提供了四种日输出的样式
org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)
Layouts的配置方法
log4j.appender.appenderName.layout=className
log4j.appender.appenderName.layout.O1=xxx1
... ...
log4j.appender.appenderName.layout.ON=xxxN
四、log4j配置详解
应用中需要对Logger,Appender,Layout进行详细的设定,log4j支持xml和properties形式的两种配置,下面是properties类型日志的详细配置。
1,配置root Logger
log4j.rootLogger=[level],appenderName1,appenderName2,... ...
Level为日志的最低级别,可设置OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别,一般是ERROR、WARN、INFO、DEBUG、ALL这几个级别,这里是总开关,如设置了INFO则DEBUG级别的日志不会打印。
appenderName则是指定日志输出到什么地方,可以配置多个,“,”号分割
定义各个包的日志级别可以
log4j.logger.org.springframework=error设置org.springframework包的日志级别为ERROR,表示org.springframework包下只打印大于等于ERROR级别的日志,没有设置的包按照root的定义打印
2,配置Appender
1)ConsoleAppender
Threshold:日志最低级别
encoding:编码
ImmediateFlush:true或者false,true表示日志会立即输出,默认true
2)FileAppender
Threshold:日志最低级别
encoding:编码
ImmediateFlush:true或者false,true表示日志会立即输出,默认true
File:日志文件路径
Append:true或者false,true日志追加到指定文件中,默认为true,false时会覆盖
DatePattern:
3)DailyRollingFileAppender
Threshold:日志最低级别
encoding:编码
ImmediateFlush:true或者false,true表示日志会立即输出,默认true
File:日志文件路径
Append:true或者false,true日志追加到指定文件中,默认为true,false时会覆盖
DatePattern:’_yyyyMMdd.HH’每小时产生一个新文件,可以按照分,时,天,周,月来滚动日志文件
yyyyMM每月
yyyyww每周
yyyyMMdd每天
yyyyMMdda每天两次
yyyyMMddHH每小时
yyyyMMddHHmm每分钟
4)RollingFileAppender
Threshold:日志最低级别
encoding:编码
ImmediateFlush:true或者false,true表示日志会立即输出,默认true
File:日志文件路径
Append:true或者false,true日志追加到指定文件中,默认为true,false时会覆盖
MaxFileSize:日志文件大小,超过后产生新的文件,后缀可以使MB,KB,GB等
MaxBackupIndex:设置产生滚动文件的最大数
Appender中也可以增加Filter,来过滤日志信息,符合条件的日志才会被打印。
3,配置Layout
主要看一下使用率比较高的ConversionPattern的格式化符号
%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平台为"rn",Unix平台为"n"。
%x:输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
%%:输出一个"%"字符。
另外,还可以在%与格式字符之间加上修饰符来控制其最小长度、最大长度、和文本的对齐方式。如:
1) c:指定输出category的名称,最小的长度是20,如果category的名称长度小于20的话,默认的情况下右对齐。
2)%-20c:"-"号表示左对齐。
3)%.30c:指定输出category的名称,最大的长度是30,如果category的名称长度大于30的话,就会将左边多出的字符截掉,但小于30的话也不会补空格。
properties配置样例:
log4j.rootLogger=DEBUG,console,dailyFile,im
log4j.additivity.org.apache=true
# 控制台(console)
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.ImmediateFlush=true
log4j.appender.console.Target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 日志文件(logFile)
log4j.appender.logFile=org.apache.log4j.FileAppender
log4j.appender.logFile.Threshold=DEBUG
log4j.appender.logFile.ImmediateFlush=true
log4j.appender.logFile.Append=true
log4j.appender.logFile.File=D:/logs/log.log4j
log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 回滚文件(rollingFile)
log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.Threshold=DEBUG
log4j.appender.rollingFile.ImmediateFlush=true
log4j.appender.rollingFile.Append=true
log4j.appender.rollingFile.File=D:/logs/log.log4j
log4j.appender.rollingFile.MaxFileSize=200KB
log4j.appender.rollingFile.MaxBackupIndex=50
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 定期回滚日志文件(dailyFile)
log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyFile.Threshold=DEBUG
log4j.appender.dailyFile.ImmediateFlush=true
log4j.appender.dailyFile.Append=true
log4j.appender.dailyFile.File=D:/logs/log.log4j
log4j.appender.dailyFile.DatePattern='.'yyyy-MM-dd
log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.dailyFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 应用于socket
log4j.appender.socket=org.apache.log4j.RollingFileAppender
log4j.appender.socket.RemoteHost=localhost
log4j.appender.socket.Port=5001
log4j.appender.socket.LocationInfo=true
# Set up for Log Factor 5
log4j.appender.socket.layout=org.apache.log4j.PatternLayout
log4j.appender.socket.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# Log Factor 5 Appender
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
# 发送日志到指定邮件
log4j.appender.mail=org.apache.log4j.net.SMTPAppender
log4j.appender.mail.Threshold=FATAL
log4j.appender.mail.BufferSize=10
log4j.appender.mail.From = [email protected]
log4j.appender.mail.SMTPHost=mail.com
log4j.appender.mail.Subject=Log4J Message
log4j.appender.mail.To= [email protected]
log4j.appender.mail.layout=org.apache.log4j.PatternLayout
log4j.appender.mail.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 应用于数据库
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=
log4j.appender.database.sql=INSERT INTO LOG4J (Message) VALUES('=[%-5p] %d(%r) --> [%t] %l: %m %x %n')
log4j.appender.database.layout=org.apache.log4j.PatternLayout
log4j.appender.database.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 自定义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 = [email protected]
log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
xml配置样例
自定义Filter
public class HJLogFilter extends Filter {
boolean acceptOnMatch = false;
private String levelMin;
private String levelMax;
public static int getLevel(String level){
level = level.toUpperCase();
if(level.equals("ACCESS")){
return LevelType.ACCESS.getType();
}
if(level.equals("SERVICE")){
return LevelType.SERVICE.getType();
}
if(level.equals("OFF")){
return LevelType.OFF.getType();
}
if(level.equals("FATAL")){
return LevelType.FATAL.getType();
}
if(level.equals("ERROR")){
return LevelType.ERROR.getType();
}
if(level.equals("INFO")){
return LevelType.INFO.getType();
}
if(level.equals("WARN")){
return LevelType.WARN.getType();
}
if(level.equals("DEBUG")){
return LevelType.DEBUG.getType();
}
if(level.equals("ALL")){
return LevelType.ALL.getType();
}
return LevelType.OFF.getType();
}
public String getLevelMin() {
return levelMin;
}
public void setLevelMin(String levelMin) {
this.levelMin = levelMin;
}
public String getLevelMax() {
return levelMax;
}
public void setLevelMax(String levelMax) {
this.levelMax = levelMax;
}
public boolean isAcceptOnMatch() {
return acceptOnMatch;
}
public void setAcceptOnMatch(boolean acceptOnMatch) {
this.acceptOnMatch = acceptOnMatch;
}
@Override
public int decide(LoggingEvent arg0) {
// TODO Auto-generated method stub
int inputLevel = arg0.getLevel().toInt();
if(inputLevel >= getLevel(levelMin) && inputLevel <= getLevel(levelMax)){
return 0;
}
return -1;
}
private static enum LevelType{
OFF(2147483647),
FATAL(50000),
ERROR(40000),
WARN(30000),
INFO(20000),
DEBUG(10000),
ALL(-2147483648),
ACCESS(1000),
SERVICE(1001);
int type;
public int getType() {
return type;
}
private LevelType(int type) {
this.type = type;
}
}
}
自定义日志级别
public class HJCustomLog {
private static class CustomerLogLevel extends Level{
public CustomerLogLevel(int level, String levelStr, int syslogEquivalent) {
super(level, levelStr, syslogEquivalent);
}
static final long serialVersionUID = 3491141966387921974L;
}
private static final Level accessLevel = new CustomerLogLevel(
HJLogFilter.getLevel("ACCESS"),
"ACCESS",
SyslogAppender.LOG_LOCAL0);
private static final Level serviceLevel = new CustomerLogLevel(
HJLogFilter.getLevel("SERVICE"),
"SERVICE",
SyslogAppender.LOG_LOCAL0);
public static void accessLog(Logger logger,String objLogInfo){
logger.log(accessLevel, objLogInfo);
}
public static void serviceLog(Logger logger,String objLogInfo){
logger.log(serviceLevel, objLogInfo);
}
}
日志的记录也和应用场景有关,生产环境(pro)一般要比测试环境(test)和开发环境(dev)日志更加谨慎,生产环境要提高日志的级别,不打印调试信息,数据库信息,sql等。一方面,生产系统要求安全性高,另一方面,生产环境吞吐量比较大时,日志会急剧增长,占用存储空间。
(完)