统一日志处理(slf4j和其他日志的统一整合)
1.将其他日志系统中原来不兼容的jar包去除
2.换上对于SLF4J兼容的jar包
3.使用相关日志实现类
日志加载及配置相关
不知是否有同样的小伙伴,虽然使用日志但是并不懂得其原理,为什么在项目类路径下配置日志配置文件,相关的日志就可以在控制台,文件系统中的日志文件中打印出来。
前提,maven 引入
org.slf4j
slf4j-log4j12
${slf4j-log4j}
该依赖会自动引入log4j和slf4j的相关jar包。
SLF4J不同于其他日志类库,与其它有很大的不同。SLF4J(Simple logging Facade for Java)不是一个真正的日志实现,而是一个抽象层( abstraction layer),它允许你在后台使用任意一个日志类库,所以使用slf4j时,需要和相关日志实现框架一起使用。
一,日志到底是如何被加载的
在org.apache.log4j.LogManager里面,存在如下静态代码,
static {
// By default we use a DefaultRepositorySelector which always returns 'h'.
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
repositorySelector = new DefaultRepositorySelector(h);
/** Search for the properties file log4j.properties in the CLASSPATH. */
//先去类路径下加载log4j.propesties
String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
null);
// if there is no default init override, then get the resource
// specified by the user or the default config file.
//类路径下不存在,就通过Resource加载配置资源
if(override == null || "false".equalsIgnoreCase(override)) {
String configurationOptionStr = OptionConverter.getSystemProperty(
DEFAULT_CONFIGURATION_KEY,
null);
String configuratorClassName = OptionConverter.getSystemProperty(
CONFIGURATOR_CLASS_KEY,
null);
URL url = null;
// if the user has not specified the log4j.configuration
// property, we search first for the file "log4j.xml" and then
// "log4j.properties"
//未指定配置情况,先查询是否存在log4j.xml配置文件
//没有则查询是否存在log4j.properties配置文件
if(configurationOptionStr == null) {
url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
if(url == null) {
url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
}
} else {
try {
url = new URL(configurationOptionStr);
} catch (MalformedURLException ex) {
// so, resource is not a URL:
// attempt to get the resource from the class path
url = Loader.getResource(configurationOptionStr);
}
}
// If we have a non-null url, then delegate the rest of the
// configuration to the OptionConverter.selectAndConfigure
// method.
//由OptionConverter.selectAndConfigure去加载非空url中的配置资源
if(url != null) {
LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
try {
OptionConverter.selectAndConfigure(url, configuratorClassName,
LogManager.getLoggerRepository());
} catch (NoClassDefFoundError e) {
LogLog.warn("Error during default initialization", e);
}
} else {
LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
}
} else {
LogLog.debug("Default initialization of overridden by " +
DEFAULT_INIT_OVERRIDE_KEY + "property.");
}
}
二,log4j日志的配置文件,如何配置控制台打印,和文件系统日志文件写入。
# Global logging configuration
#注意如果是开发环境日志级别需要配置为DEBUG,生产环境设置为info或error
#日志信息的优先级从高到低有ERROR、WARN、INFO、DEBUG
#代表root节点整个工程下所有输出日志的地方配置的输出的级别和输出的位置
log4j.rootLogger=CONSOLE,stdout,ERROR,INFO,DEBUG
# Console output...
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
#开发环境
log4j.appender.DEBUG=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DEBUG.Append = true
log4j.appender.DEBUG.Threshold = DEBUG
log4j.appender.DEBUG.File=D:\\Myself\\eclipse\\workspace\\SSMXML\\log\\daily\\debug\\debug.log
log4j.appender.DEBUG.DatePattern='.'yyyy-MM-dd
log4j.appender.DEBUG.layout=org.apache.log4j.PatternLayout
log4j.appender.DEBUG.layout.ConversionPattern=%-d{yyyy-MM-dd-HH-mm} [ %t:%r ] - [ %p ] %m%n
#生产环境
log4j.appender.INFO=org.apache.log4j.DailyRollingFileAppender
log4j.appender.INFO.Append = true
log4j.appender.INFO.Threshold = INFO
log4j.appender.INFO.File=D:\\Myself\\eclipse\\workspace\\SSMXML\\log\\daily\\info\\info.log
##设置为每天产生一个日志文件
log4j.appender.INFO.DatePattern='.'yyyy-MM-dd
log4j.appender.INFO.layout=org.apache.log4j.PatternLayout
log4j.appender.INFO.layout.ConversionPattern=%-d{yyyy-MM-dd-HH-mm} [ %t:%r ] - [ %p ] %m%n
log4j.appender.ERROR=org.apache.log4j.DailyRollingFileAppender
log4j.appender.ERROR.Append = true
log4j.appender.ERROR.Threshold = ERROR
log4j.appender.ERROR.File=D:\\Myself\\eclipse\\workspace\\SSMXML\\log\\daily\\error\\error.log
log4j.appender.ERROR.DatePattern='.'yyyy-MM-dd
log4j.appender.ERROR.layout=org.apache.log4j.PatternLayout
log4j.appender.ERROR.layout.ConversionPattern=%-d{yyyy-MM-dd-HH-mm} [ %t:%r ] - [ %p ] %m%n
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
##---------------------------以下是所有参数配置解释-----------------------------------
# Global logging configuration
#注意如果是开发环境日志级别需要配置为DEBUG,生产环境设置为INFO或ERROR
#日志信息的优先级从高到低有ERROR、WARN、INFO、DEBUG
#org.apache.log4j.ConsoleAppender(控制台)
#org.apache.log4j.FileAppender(文件)
#org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
#org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
#org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
#日志还可以输出到数据库,文件。。。
#org.apache.log4j.HTMLLayout(HTML表格形式)
#org.apache.log4j.SimpleLayout(简单格式的日志,只包括日志信息的级别和指定的信息字符串 ,如:DEBUG - Hello)
#org.apache.log4j.TTCCLayout(日志的格式包括日志产生的时间、线程、类别等等信息)
#org.apache.log4j.PatternLayout(灵活地自定义日志格式)
#ConversionPattern解释
#-X: X信息输出时左对齐
#
#%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
#
#%d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy-MM-dd HH:mm:ss,SSS},输出类似:2011-10-18 22:10:28,921
#%r: 输出自应用启动到输出该log信息耗费的毫秒数
#%c: 输出日志信息所属的类目,通常就是所在类的全名
#%t: 输出产生该日志事件的线程名
#%l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。
#%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
#%%: 输出一个"%"字符
#%F: 输出日志消息产生时所在的文件名称
#%L: 输出代码中的行号
#%m: 输出代码中指定的消息,产生的日志具体信息
#%n: 输出一个回车换行符,Windows平台为"\r\n",Unix平台为"\n"输出日志信息换行
#可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:
#%20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。
#%-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。
#%.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
#%20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边交远销出的字符截掉
#
#假设当前logger名字空间是"a.b.c"
#
#%c a.b.c
#%c{2} b.c
#
#%20c (若名字空间长度小于20,则左边用空格填充)
#%-20c (若名字空间长度小于20,则右边用空格填充)
#%.30c (若名字空间长度超过30,截去多余字符)
#%20.30c (若名字空间长度小于20,则左边用空格填充;若名字空间长度超过30,截去多余字符)
#%-20.30c (若名字空间长度小于20,则右边用空格填充;若名字空间长度超过30,截去多余字符)
#DatePattern选项的有效值为:
# '.'yyyy-MM,对应monthly(每月)
# '.'yyyy-ww,对应weekly(每周)
# '.'yyyy-MM-dd,对应daily(每天)
# '.'yyyy-MM-dd-a,对应half-daily(每半天)
# '.'yyyy-MM-dd-HH,对应hourly(每小时)
# '.'yyyy-MM-dd-HH-mm,对应minutely(每分钟)
三,使用SLF4J的好处
1. 在你的开源或内部类库中使用SLF4J会使得它独立于任何一个特定的日志实现,这意味着不需要管理多个日志配置或者多个日志类库,你的客户端会很感激这点。
2. SLF4J提供了基于占位符的日志方法,这通过去除检查isDebugEnabled(), isInfoEnabled()等等,提高了代码可读性。
3. 通过使用SLF4J的日志方法,你可以延迟构建日志信息(Srting)的开销,直到你真正需要,这对于内存和CPU都是高效的。
4. 作为附注,更少的暂时的字符串意味着垃圾回收器(Garbage Collector)需要做更好的工作,这意味着你的应用程序有为更好的吞吐量和性能。