日志
基础知识
如图所示,应用调了sl4j-api,即日志门面接口。
日志门面接口本身通常并没有实际的日志输出能力,它底层还是需要去调用具体的日志框架API的,也就是实际上它需要跟具体的日志框架结合使用。
由于具体日志框架比较多,而且互相也大都不兼容,日志门面接口要想实现与任意日志框架结合可能需要对应的桥接器,上图红框中的组件即是对应的各种桥接器!
我们在代码中需要写日志,变成下面这么写
import org.slf4j.Logger; import org.slf4j.LoggerFactory; //省略 Logger logger = LoggerFactory.getLogger(Test.class); // 省略 logger.info("info");
在代码中,并不会出现具体日志框架的api。
程序根据classpath中的桥接器类型,和日志框架类型,判断出logger.info应该以什么框架输出!注意了,如果classpath中不小心引了两个桥接器,那会直接报错的!
案例实战
案例一
一个项目,一个模块用log4j,另一个模块用slf4j+log4j2,如何统一输出?
这里就要用上slf4j的适配器,slf4j提供了各种各样的适配器,用来将某种日志框架委托给slf4j。其最明显的集成工作方式有如下:
根据题意应该选log4j-over-slf4j适配器,于是就变成下面这张图
就可以实现日志统一为log4j2来输出
根据适配器工作原理的不同,被适配的日志框架并不是一定要删除!
以上图为例,log4j这个日志框架删不删都可以,你只要能保证log4j的加载顺序在log4j-over-slf4j后即可。
因为log4j-over-slf4j这个适配器的工作原理是,内部提供了和log4j一模一样的api接口,因此你在程序中调用log4j的api的时候,你必须想办法让其走适配器的api。如果你删了log4j这个框架,那你程序里肯定是走log4j-over-slf4j这个组件里的api。如果不删log4j,只要保证其在classpth里的顺序比log4j前即可!
logback.xml
参考文档:
http://www.51gjie.com/javaweb/1107.html
<--把日志输出到控制台--> <appender name="ConsoleAppender" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <charset>UTF-8</charset> <pattern>${NORMAL_PATTERN}</pattern> </encoder> </appender> <!--滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件--> <appender name="RuntimeAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/runtime.log</file> <encoder> <pattern>${NORMAL_PATTERN}</pattern> </encoder> <!--设置日志滚动的策略,这是使用按照时间滚动--> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--设置滚动生成文件的格式,这里设置的精确到天,也就是按照天滚动,如果时间设置精确到秒,就按秒来滚动--> <!--设置按天来滚动,前一天日志打印到23点59分,然后就一直没有请求日志,直到次日的1点才有新的日志进入, 在0点到1点这个时间段,日志文件是不会滚动生成新的日志文件。因为滚动的动作是需要日志写入动作来触发--> <fileNamePattern>${LOG_HOME}/runtime.%d{yyyy-MM-dd}.log</fileNamePattern> <!--设定最大的文件数,比如按天滚动,这里设置了30天,在第31天日志生成的时候,第一天的日志就会被删掉--> <maxHistory>7</maxHistory> </rollingPolicy> </appender> <appender name="ErrorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/error.log</file> <encoder> <pattern>${NORMAL_PATTERN}</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>7</maxHistory> </rollingPolicy> <!--将过滤器的日志级别配置为INFO,所有INFO级别的日志交给appender处理,非INFO级别的日志,被过滤掉--> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!--用于存放日志对象,同时指定关联的package位置 --> <!-- name指定关联的package --> <!-- level表明指记录哪个日志级别以上的日志 --> <!-- appender-ref指定logger向哪个文件输出日志信息 --> <!-- additivity为true时,logger会把根logger的日志输出地址加入进来,但logger水平不依赖于根logger --> <logger name="com.campus.o2o" level="${log.level}" additivity="true"> <appender-ref ref="debugAppender" /> <appender-ref ref="infoAppender" /> <appender-ref ref="errorAppender" /> </logger> <!-- 特殊的logger,根logger --> <root lever="info"> <!-- 指定默认的日志输出 --> <appender-ref ref="consoleAppender" /> </root>