文章目录
- 日志概述
- logging
- log4j
- commons-logging
- slf4j
- logback
- 日志框架总结
- Maven依赖
- logback加载配置文件规则
- logback 日志级别
- 配置
- 测试
- Github地址
日志概述
log4j、Logging、commons-logging、slf4j、logback,都耳熟能详吧,那么具体的区别和联系呢,我们这里借o2o这个小项目的机会梳理一下。
logging
Java 自带的日志工具类,在 JDK 1.5 开始就已经有了,在 java.util.logging 包下。
log4j
Log4j 是 Apache 的一个开源日志框架,也是市场占有率最多的一个框架,log4j 在 2015/08/05 Apache 宣布停止维护了,用户需要切换到 Log4j2上面去。
commons-logging
log4j 是一个具体的日志框架的实现,而 commons-logging 就是日志的门面接口,它也是 apache 最早提供的日志门面接口,用户可以根据喜好选择不同的日志实现框架,而不必改动日志定义,这就是日志门面的好处,符合面对接口抽象编程。
slf4j
全称:Simple Logging Facade for Java,即简单日志门面接口,和 Apache 的 commons-logging 是一样的概念,它们都不是具体的日志框架,你可以指定其他主流的日志实现框架。
Slf4j 也是现在主流的日志门面框架,使用 Slf4j 可以很灵活的使用占位符进行参数占位,简化代码,拥有更好的可读性。
logback
Logback 是 Slf4j 的原生实现框架,同样也是出自 Log4j 一个人之手,但拥有比 log4j 更多的优点、特性和更做强的性能,现在基本都用来代替 log4j 成为主流。
日志框架总结
- commons-logging、slf4j 只是一种日志抽象门面,不是具体的日志框架。
- log4j、logback 是具体的日志实现框架。
- 一般首选强烈推荐使用 slf4j + logback。当然也可以使用slf4j + log4j、commons-logging +log4j 这两种日志组合框架。
一般情况下,Logback与slf4J组合使用。
logback的官方网站:http://logback.qos.ch
SLF4J的官方网站:http://www.slf4j.org
看出 slf4j 很强大,不但能和各种日志框架对接,还能和日志门面 commons-logging 进行融合。
logback的三个模块
- logback-core
- logback-classic
- logback-access
logback-core是logback-classic和logback-access模块的基础模块。logback-classic是log4j的一个改良版本,均出自同一个作者之手。
Maven依赖
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.1version>
dependency>
logback加载配置文件规则
1. 在 classpath 中寻找 logback-test.xml文件
2. 如果找不到 logback-test.xml,则在 classpath 中寻找 logback.groovy 文件
3. 如果找不到 logback.groovy,则在 classpath 中寻找 logback.xml文件
4. 如果上述的文件都找不到,则 logback 会使用 JDK 的 SPI 机制查找 META-INF/services/ch.qos.logback.classic.spi.Configurator 中的 logback 配置实现类,这个实现类必须实现 Configuration 接口,使用它的实现来进行配置
5. 如果上述操作都不成功,logback 就会使用它自带的 BasicConfigurator 来配置,并将日志输出到 console
logback 日志级别
TRACE < DEBUG < INFO < WARN < ERROR
配置
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="app.name" value="o2o" /> <property name="log.level" value="DEBUG"/> <property name="log.maxHistory" value="30"/> <property name="log.filePath" value="D:/logs/${app.name}"/> <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/> <contextName>${app.name}contextName> <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <patten>${log.pattern}patten> encoder> appender> <appender name="debugAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.filePath}/debug.logfile> <append>trueappend> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.filePath}/debug/debug.%d{yyyy-MM-dd}.%i.log.zip fileNamePattern> <maxHistory>${log.maxHistory}maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>1MBmaxFileSize> timeBasedFileNamingAndTriggeringPolicy> rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${log.pattern}pattern> encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUGlevel> <onMatch>ACCEPTonMatch> <onMismatch>DENYonMismatch> filter> appender> <appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.filePath}/info.logfile> <append>trueappend> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.filePath}/info/info.%d{yyyy-MM-dd}.%i.log.zip fileNamePattern> <maxHistory>${log.maxHistory}maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>1MBmaxFileSize> timeBasedFileNamingAndTriggeringPolicy> rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${log.pattern}pattern> encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFOlevel> <onMatch>ACCEPTonMatch> <onMismatch>DENYonMismatch> filter> appender> <appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.filePath}/error.logfile> <append>trueappend> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.filePath}/error/error.%d{yyyy-MM-dd}.%i.log.zip fileNamePattern> <maxHistory>${log.maxHistory}maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>1MBmaxFileSize> timeBasedFileNamingAndTriggeringPolicy> rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${log.pattern}pattern> encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERRORlevel> <onMatch>ACCEPTonMatch> <onMismatch>DENYonMismatch> filter> appender> <logger name="com.artisan.o2o" level="${log.level}" additivity="true"> <appender-ref ref="debugAppender" /> <appender-ref ref="infoAppender" /> <appender-ref ref="errorAppender" /> logger> <root level="${log.level}"> <appender-ref ref="consoleAppender" /> root>
configuration>
测试
我们在AreaController中加些log输出
package com.artisan.o2o.web;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;import com.artisan.o2o.entity.Area;
import com.artisan.o2o.service.AreaService;@Controller
@RequestMapping("/superadmin")
public class AreaController {
Logger logger = LoggerFactory.getLogger(AreaController.class);@Autowired AreaService areaService; @RequestMapping(value = "/listArea", method = RequestMethod.GET) @ResponseBody public Map<String, Object> getAreas() { logger.info("-----begin getAreas------"); Long beginTimeLong = System.currentTimeMillis(); Map<String, Object> map = new HashMap<String, Object>(); List<Area> areaList = new ArrayList<Area>(); try { areaList = areaService.getAreaList(); map.put("total", areaList.size()); map.put("rows", areaList); for (Area area : areaList) { System.out.println("区域:" + area); } } catch (Exception e) { e.printStackTrace(); map.put("success", false); map.put("errMsg", e.getMessage().toString()); logger.error("exception happpens , desc [{}] ", e.getMessage()); } Long endTimeLong = System.currentTimeMillis(); logger.debug("cost [{}ms]", endTimeLong - beginTimeLong); logger.info("-----end getAreas------"); return map; }
}
启动服务,测试
rollingPolicy的配置
接下来,我们将AreaDao.xml中 id为 queryArea的statement sql 中的area_name 改成area_name1,因为数据库tb_area表没有该字段,验证下,error的配置项。
同时 http://localhost:8080/o2o/superadmin/listArea
这里将不同级别的日志分别打印到了不同的文件中,日志的配置可以灵活配置,这里仅仅是阐述用法,日志的记录方式后续会调整。