2019独角兽企业重金招聘Python工程师标准>>>
本文为转载学习
原文链接:http://hi.baidu.com/boyyf/item/cec95635dbd50e169dc65e26
认识Log4j
在你开发项目的过程过,是否时常使用System.out.println()?考虑是否需要记录程序运行过程中出现的错误?是否需要记录用户的行为?Apache Log4j项目将帮助我们逃脱硬编码写输出的痛苦,独立的日志输出程序将使得程序员可以便利的分级输出日志信息。更为重要的是,Log4j灵活的配置功能使得我们完全不需要修改程序,而仅仅修改配置文件即可彻底改变日志输出的格式、目标等属性,并且Log4j还为我们提供了各种便利的日志目的地,如“一天一个日志文件”、套接字、数据库、电子邮箱,甚至Unix的守护进程和Nt的事件服务。
Log4j的三大组建
Log4j有三个主要的组件:Loggers,Appenders和Layouts,这里可简单理解为日志记录器,日志要输出的地方和日志以何种形式输出。
Loggers
组件在此系统中被分为五个级别:DEBUG、INFO、WARN、ERROR和FATAL。这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL,明白这一点很重要,这里Log4j有一个规则:假设Loggers级别为P,如果在Loggers中发生了一个级别Q比P高的日志输出事件,则会输出,否则屏蔽掉。
Appenders
禁用与使用日志请求只是Log4j其中的一个小小的地方,Log4j日志系统允许把日志输出到不同的地方,如控制台(Console)、文件(Files)、根据天数或者文件大小产生新的文件、以流的形式发送到其它地方等等。
常见的Appender有:
org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
org.apache.log4j.net.SMTPAppender(发送到邮箱)
org.apache.log4j.jdbc.JDBCAppender(储存到数据库)
Layouts
有时用户希望根据自己的喜好格式化自己的日志输出。Log4j可以在Appenders的后面附加Layouts来完成这个功能。Layouts提供了四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式等等。
常见的Layout有:
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
Layouts有以下各常用的占位符:
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r 输出自应用启动到输出该log信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为"\r\n",Unix平台为"\n"
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
Log4j的配置文件
就本人看来,Log4j的便利之处就在于他的配置非常灵活的依赖于配置文件,可以说在程序中只需要写出在哪里需要输出日志,日志的级别,以及日志的内容(这些通常都是固定不变的),而对于常需要改变的内容,比如日志的格式、输出到哪里、怎么储存,甚至需要那些记录器都只需要修改配置文件,而无需修改程序。但同时,这也决定了Log4j的使用核心就在配置文件的编写。
Log4j的配置文件可以拥有两种形式,一是properties文件,另一种是xml文件,在此,只探讨properties文件形式。
首先请看一段配置文件(由于properties并不支持中文,复制使用时请将中文注释删掉,或者下载源程序包中的配置文件):
#下面是Logger的定义
#定义根logger,其余所有的logger都是它的子logger
log4j.rootLogger=DEBUG
#logger的定义策略1:根据类名定义logger
#这里就定义了两个logger,一个名为"com.ins1000.log4j.servlets",另一个名
#为"com.ins1000.log4j.servlets"。#logger的命名是具有层次性和隶属性的,跟
#类的全名一样,可以说"com.ins1000.log4j.servlets.Test"这个logger是"com.
#ins1000.log4j.servlets"这个的子logger。
log4j.logger.com.ins1000.log4j.servlets=DEBUG,CONSOLE
log4j.logger.com.ins1000.log4j.servlets.Test=DEBUG,CONSOLE,DailyRollingFile
#logger的定义策略2:根据用途定义logger
#定义了一个名为sa(system action)的logger,用于记录程序的系统行为,如程
#序启动,初始化完成等
log4j.logger.sa=DEBUG,CONSOLE_SA
#定义了一个名为us(users action)的logger,用于记录用户的一般行为,如注册
#发布文章、发布作品等
log4j.logger.ua=DEBUG,DailyRollingFile_UA
#定义了一个名为e(Errors或Exceptions)的logger,用于记录程序运行中出现的
#错误和异常
log4j.logger.e=DEBUG,CONSOLE_E,ROLLING_FILE_E
#以上各个定义的等号右方DEBUG的表示该logger的日志输出起始级别,接着后面是
#这个logger要输#出的Appender,可以有多个,用逗号隔开。
#其次,这里提到了两种logger的命名策略,虽然互联网上几乎所有的教程皆称以类
#的全名是最简单也最好的命名策略,因为其层次结构跟我们的项目完全一致,但是
#本人处于应用需要,还是提出了另一种根据用途命名的策略,即把所有需要记录的
#日志信息分为3中(系统行为、用户行为、异常),分别输出到不同的地方。
#下面定义各个层次是否继承父辈的属性(初始级别和Appenders)
log4j.additivity.com.ins1000.log4j=true
log4j.additivity.com.ins1000.log4j.Test=true
log4j.additivity.e=false
log4j.additivity.sa=false
log4j.additivity.ua=false
log4j.addivity.org.apache=true
#下面定义各个Appenders
###################################
# Console 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=[ins1000]%p: %m [%c]%n
###################################
# Console Appender For SystemAction
###################################
log4j.appender.CONSOLE_SA=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE_SA.Target=System.out
log4j.appender.CONSOLE_SA.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE_SA.layout.ConversionPattern=[ins1000]\u7cfb\u7edf\u4fe1\u606f: %m%n
###################################
# Console Appender For Errors and Exceptions
###################################
log4j.appender.CONSOLE_E=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE_E.Target=System.out
log4j.appender.CONSOLE_E.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE_E.layout.ConversionPattern=[ins1000]\u7cfb\u7edf\u5f02\u5e38: %m [%l]%n
#上面的Appender都是输出到控制台,多个项目的信息都可能被输出到控制台,所以
#一般都会加上项目名称,如[ins1000]
########################
# Rolling File For Errors and Exceptions
########################
log4j.appender.ROLLING_FILE_E=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE_E.Threshold=ERROR
log4j.appender.ROLLING_FILE_E.File=${webappHome}/WEB-INF/log/errors/ins1000.log
#日志文件的位置,其中${webappHome}代表环境变量中webappHome的值,Log4j会在
#初始化的死后自动期待,所以我们可以在Log4j初始化的时候将webapp的绝对路径存
#入系统环境标量中,从而解决要手动修改日志文件的问题
log4j.appender.ROLLING_FILE_E.Append=true
log4j.appender.ROLLING_FILE_E.MaxFileSize=5120KB
#一个文件的大小(当超过这个大小时,自动更换一个文件)
log4j.appender.ROLLING_FILE_E.MaxBackupIndex=1
log4j.appender.ROLLING_FILE_E.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE_E.layout.ConversionPattern=%n%n[%d{yyyy-MM-dd HH:mm:ss}]%m [%l]%n
########################
# DailyRollingFile Appender
#######################
log4j.appender.DailyRollingFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DailyRollingFile.DatePattern=yyyy-MM-dd'.log'
#日期戳后缀的格式
log4j.appender.DailyRollingFile.File=${webappHome}/WEB-INF/log/ins1000_
log4j.appender.DailyRollingFile.Append=true
log4j.appender.DailyRollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.DailyRollingFile.layout.ConversionPattern=[%-5p]%m [%c][%d{yyyy-MM-dd HH:mm:ss}]%n
#这个Appender的工作机理是先将日志写在/WEB-INF/log/ins1000_,待到了第二天,自动将其更名为
#ins1000_yyyy-MM-dd.log(其中yyyy-MM-dd是第一天的日期)。然后仍将第二天的日志先记录在在
#ins1000_中,第三天再改名,以此类推。
########################
# DailyRollingFile Appender For Users Action
#######################
log4j.appender.DailyRollingFile_UA=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DailyRollingFile_UA.DatePattern=yyyy-MM-dd'.log'
log4j.appender.DailyRollingFile_UA.File=${webappHome}/WEB-INF/log/users_action/ins1000_
#${webappHome} is an enviorment variable which is setted in Log4jInit
#it refers to the absolute path of the webapp
log4j.appender.DailyRollingFile_UA.Append=true
log4j.appender.DailyRollingFile_UA.layout=org.apache.log4j.PatternLayout
log4j.appender.DailyRollingFile_UA.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] %m%n
本人在网上处处寻觅,都没有发现有对Log4j配置文件详细介绍的文档,如果大家English不错的话,建议大家需要的时候可以看看Log4j的API,应该有比较详细的介绍。在此,本人只再介绍几个常用的Appender的配置:
#####################
# File Appender
#####################
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
# Use this layout for LogFactor 5 analysis
########################
# Rolling File
########################
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE.Threshold=ERROR
log4j.appender.ROLLING_FILE.File=rolling.log
log4j.appender.ROLLING_FILE.Append=true
log4j.appender.ROLLING_FILE.MaxFileSize=10KB
log4j.appender.ROLLING_FILE.MaxBackupIndex=1
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
####################
# Socket Appender
####################
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 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
########################
# SMTP Appender
#######################
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=FATAL
log4j.appender.MAIL.BufferSize=10
log4j.appender.MAIL.SMTPHost=mail.hollycrm.com
log4j.appender.MAIL.Subject=Log4J Message
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=
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
自动初始化Log4j的Servlet
package com.ins1000.log4j.servlets;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.apache.log4j.PropertyConfigurator;
public class Log4jInit extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
//获取本webapp所在的绝对路径
String prefix = config.getServletContext().getRealPath("/");
//从web.xml读取配置文件名
String file = config.getInitParameter("Log4j-init-file");
//对绝对路径进行修饰
String editedPrefix = prefix.substring(0,prefix.length()-1).replace("\\", "/");
//将修饰后的绝对路径存入系统环境变量
System.setProperty("webappHome", editedPrefix);
//执行Log4j的初始化
PropertyConfigurator.configure(prefix + file);
}
}
为了让这个Servlet在Web服务器启动时自动运行,还需要在项目的web.xml写入:
Log4jInit
Log4jInit
Log4jInit
com.ins1000.log4j.servlets.Log4jInit
Log4j-init-file
WEB-INF/config/Log4j.properties
1
在程序中使用Log4j
在程序中使用Log4j,也就是要输出日志信息,一般分为两个步骤:首先获得一个Logger实例,然后调用此实例的debug()、info()、warn()、error()、fatal()等进行日志的输出。
在上面的配置文件中,讲到了两种命名策略,一种是直接根据类的全名命名,另一种是根据用途命名,那么在实例化和使用的时候,就会稍微有些不同。
根据类全命命名:
Logger logger = Logger.getLogger(this.getClass());
//实例化一个logger,这里this.getClass()将返回这个类的全名,如果这个名字在配置文件中定义了,则这个logger有其相关定义了的属性,如果没有,则看是否定义了其父类和时候设置了继承。如果都没有,则拥有rootLogger的属性。
//当然,logger的实例化可以任意取名,比如Logger logger = Logger.getLogger("myLogger"),但一句相关的策略,将会更加便于管理。
logger.debug("按类取名测试:DEBUG");
logger.info("按类取名测试:INFO");
logger.warn("按类取名测试:WARN");
logger.error("按类取名测试:ERROR");
logger.error("按类取名测试:ERROR", Exception e);
logger.fatal("按类取名测试:FATAL");
//这就是条用logger的各种方法输出日志信息。其中logger.error("按类取名测试:ERROR", Exception e)也会将异常堆栈e的相关信息也输出到相应的Appender
根据用途命名:
Logger logger_sa = Logger.getLogger("sa");
logger_sa.info("Log4j演示程序启动成功");
Logger logger_ua = Logger.getLogger("ua");
logger_ua.info("用户boyyf注册成功");
Logger logger_e = Logger.getLogger("e");
try {
Integer.parseInt("a");
} catch (Exception e) {
logger_e.error("出现数值转换异常",e);
//这样会在日志中记录异常堆栈
}