实战SSM_O2O商铺_06logback配置与使用

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 实战SSM_O2O商铺_06logback配置与使用

20191208103239519.png


日志概述


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


image.png


看出 slf4j 很强大,不但能和各种日志框架对接,还能和日志门面 commons-logging 进行融合。


logback的三个模块

  • logback-core
  • logback-classic
  • logback-access

logback-core是logback-classic和logback-access模块的基础模块。logback-classic是log4j的一个改良版本,均出自同一个作者之手。


Maven依赖

<!-- 1.日志 -->
<!-- 实现slf4j接口并整合 -->
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.2.1</version>
</dependency>


20180515124746649.png


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


配置


<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!--scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 -->
<!-- scanPeriod设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
  注意扫描间隔要加上单位,可用的单位是 milliseconds,seconds,minutes 和 hours。如果只指定了数字,但没有指定单位,这默认单位为 milliseconds。-->
<!--debug当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
  <!--  用来定义变量值,它有两个属性name和value,通过<property>定义的值会被插入到logger上下文中,可以使“${}”来使用变量-->
  <property name="app.name" value="o2o" /> 
  <property name="log.level" value="DEBUG"/>
  <property name="log.maxHistory" value="30"/>
  <!--<property name="log.filePath" value="${catalina.base}/logs/webapps"/>  -->
  <property name="log.filePath" value="D:/logs/${app.name}"/>
  <!--格式化输出,%d:日期;%thread:线程名;%-5level:级别,从左显示5个字符宽度;%msg:日志消息;%n:换行符-->
  <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
  <!-- 用来设置上下文名称,每个logger都关联到logger上下文,默认上下文名称为default。但可以使用<contextName>设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改。 -->
  <contextName>${app.name}</contextName> 
  <!-- 子节点<appender>:负责写日志的组件,它有两个必要属性name和class。name指定appender名称,class指定appender的全限定名 -->
  <!-- 控制台设置 -->
  <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
    <!-- 对记录事件进行格式化 encoder默认配置为PartternLayoutEncoder    -->
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <patten>${log.pattern}</patten>
    </encoder>
  </appender>
  <!-- DEBUG -->
  <appender name="debugAppender"
    class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- file被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。 -->
    <file>${log.filePath}/debug.log</file>
    <!-- append如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。 -->
    <append>true</append>
    <!-- rollingPolicy当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
    <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>
      <!--滚动策略:日志文件大于1MB时生成一个新的日志文件,每天生成一个新的日志文件 -->
      <timeBasedFileNamingAndTriggeringPolicy
        class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>1MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <!-- 日志格式 -->
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <pattern>${log.pattern}</pattern>
    </encoder>
    <!-- filter 只记录debug信息 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">   
         <level>DEBUG</level>   
         <onMatch>ACCEPT</onMatch>   
         <onMismatch>DENY</onMismatch>   
      </filter>  
  </appender>
  <!-- INFO -->
  <appender name="infoAppender"
    class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- file被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。 -->
    <file>${log.filePath}/info.log</file>
    <!-- append如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。 -->
    <append>true</append>
    <!-- rollingPolicy当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
    <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>
      <!--滚动策略:日志文件大于1MB时生成一个新的日志文件,每天生成一个新的日志文件 -->
      <timeBasedFileNamingAndTriggeringPolicy
        class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>1MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <!-- 日志格式 -->
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <pattern>${log.pattern}</pattern>
    </encoder>
    <!-- filter 只记录info信息 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>INFO</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
  </appender>
  <!-- ERROR -->
  <appender name="errorAppender"
    class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- file被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。 -->
    <file>${log.filePath}/error.log</file>
    <!-- append如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。 -->
    <append>true</append>
    <!-- rollingPolicy当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
    <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>
      <!--滚动策略:日志文件大于1MB时生成一个新的日志文件,每天生成一个新的日志文件 -->
      <timeBasedFileNamingAndTriggeringPolicy
        class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>1MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <!-- 日志格式 -->
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <pattern>${log.pattern}</pattern>
    </encoder>
    <!-- filter 只记录error信息 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>ERROR</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
  </appender>
   <!--打印特定包下的日志  
    additivity:是否向上级logger传递打印信息。默认是true. 作用在于 children-logger是否使用 rootLogger配置的appender进行输出。
    false:表示只用当前logger的appender-ref。
    true:表示当前logger的appender-ref和rootLogger的appender-ref都有效。
   -->
  <logger name="com.artisan.o2o" level="${log.level}" additivity="true">
    <appender-ref ref="debugAppender" />
    <appender-ref ref="infoAppender" />
    <appender-ref ref="errorAppender" />
  </logger>
  <!--  【日志输出级别】   表示把>=DEBUG级别的日志都输出到debugAppender对应的file -->
  <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;
  }
}


启动服务,测试



20180517020841585.png

2018051702092816.png

rollingPolicy的配置


20180517021024823.png


接下来,我们将AreaDao.xml中 id为 queryArea的statement sql 中的area_name 改成area_name1,因为数据库tb_area表没有该字段,验证下,error的配置项。


20180517021214814.png

同时 http://localhost:8080/o2o/superadmin/listArea


20180517021250653.png


这里将不同级别的日志分别打印到了不同的文件中,日志的配置可以灵活配置,这里仅仅是阐述用法,日志的记录方式后续会调整。


Github地址

代码地址: https://github.com/yangshangwei/o2o


相关文章
|
8月前
|
搜索推荐 JavaScript Java
计算机Java项目|基于SSM的个性化商铺系统
计算机Java项目|基于SSM的个性化商铺系统
|
6月前
|
Java 应用服务中间件 Maven
Mac使用Idea配置传统SSM项目(非maven项目)
Mac使用Idea配置传统SSM项目(非maven项目)
71 1
|
8月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的商铺租赁管理系统附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的商铺租赁管理系统附带文章和源代码部署视频讲解等
85 7
|
9月前
|
Java 数据库连接 应用服务中间件
SpringMVC关于SSM的整合配置步骤
SpringMVC关于SSM的整合配置步骤
55 1
|
9月前
|
应用服务中间件
【SSM】如何在IDEA配置tomcat启动项目
【SSM】如何在IDEA配置tomcat启动项目
141 1
|
9月前
|
SQL 测试技术
实战SSM_O2O商铺_32【商品】商品编辑之Dao层的实现
实战SSM_O2O商铺_32【商品】商品编辑之Dao层的实现
75 0
|
9月前
|
前端开发 数据库
实战SSM_O2O商铺_31【商品】商品添加之View层的实现
实战SSM_O2O商铺_31【商品】商品添加之View层的实现
59 0
|
9月前
|
前端开发 fastjson 测试技术
实战SSM_O2O商铺_30【商品】商品添加之Controller层的实现
实战SSM_O2O商铺_30【商品】商品添加之Controller层的实现
55 0
|
9月前
|
前端开发 Java 数据库连接
实战SSM_O2O商铺_29【商品】商品添加之Service层的实现及重构
实战SSM_O2O商铺_29【商品】商品添加之Service层的实现及重构
48 0
|
9月前
|
测试技术
实战SSM_O2O商铺_28【商品】商品添加之Dao层的实现
实战SSM_O2O商铺_28【商品】商品添加之Dao层的实现
70 0