日志体系-logback

参考

logback介绍

背景

  1. logback来源于log4j,有着更好的性能与更好的速度,包含了很多独特的特性
  2. logback包含3个部分
  • logback-core:核心部分,是否两个部分的基础
  • logback-classic:log4j的改进优化
  • logback-access:与tomcat等servlet服务器继承提供远程访问

logback基本使用

package chapters.introduction;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloWorld1 {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger("chapters.introduction.HelloWorld1");
        logger.debug("hello world");
    }
}

需要引入的依赖包:classpath 添加 slf4j-api.jar、logback-core.jar 以及 logback-classic.jar。

  1. 根据前一节发展历程可知:slf4j-api对应于slf4j的门面,而logback-core与logback-classic则是用于做基本实现包
  2. LoggerFactory与Logger都是SLf4j中的类

Logback的系统运行状态

package chapters.introduction;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.util.StatusPrinter;

public class HelloWorld2 {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger("chapters.introduction.HelloWorld2");
        logger.debug("Hello world");

        // 打印内部的状态
        LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
        StatusPrinter.print(lc);
    }
}
22:39:20.241 [main] DEBUG chapters.introduction.HelloWorld1 - hello world
22:39:20,179 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
22:39:20,179 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
22:39:20,179 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml]
22:39:20,194 |-INFO in ch.qos.logback.classic.BasicConfigurator@28c97a5 - Setting up default configuration.
  1. Logback通过一个状态系统来报告本身的状态信息,发生在logback生命周期中的事件可以通过StatusManager来获取
  2. 注意Loggercontext来源于包classical中
  3. StatusPrinter打印上下文
  4. 根据打印结果可以看出寻找配置的过程
  5. 默认配置会创建一个ConsoleAppender,可以根据情况输出到入文件,TCP以及console等各种日志目的地。用户可以根据自己的情况创建Appender。

Logback的架构

1.Logback主要分为三个类:logger、Apennder、layout。其中classic中才有logger,而core中包含后两者,且无logger的概念

LoggerContext
  1. 日志的优点相对于直接输入流在于它可以输出一些日志,又不输出一部分日志。存在一个日志空间用于管理其中的所有日志,所有logger都受这个空间所管理。
  2. 一个Logger被当做一个实体,命名敏感遵循一个树状规则。
  3. 日志空间基于类似于包名,com.zmm中的logger就是com.zmm.child的父级别。是com.zmm.child.son的祖先级别。注意此处的包名是大小写敏感的。
  4. root logger 作为 logger 层次结构的最高层。它是一个特殊的 logger,因为它是每一个层次结构的一部分。每一个 logger 都可以通过它的名字去获取。例:
  5. Logger接口中主要的方法有
package org.slf4j; 
public interface Logger { 
  public void trace(String message);
  public void debug(String message);
  public void info(String message); 
  public void warn(String message); 
  public void error(String message); 
}

Logger Level

  1. 日志分为不同的等级,这些等级定义在ch.qos.logback.classic.Level,是不能够继承的类
  2. 如果Logger没有指定一个层级,就会继承祖先的层级直到找到一个明确的祖先层级,root的默认层级为DEBUG
  3. Logger打印的方法需要大于等于当前Logger的等级。所以关键在于日志等级排序。各级别的排序为:TRACE < DEBUG < INFO < WARN < ERROR。
  4. 例子如下:
    public static void main(String[] args) {

        // ch.qos.logback.classic.Logger 可以设置日志的级别
        // 获取一个名为 "com.foo" 的 logger 实例
        ch.qos.logback.classic.Logger logger = 
                (ch.qos.logback.classic.Logger)LoggerFactory.getLogger("com.foo");
        // 设置 logger 的级别为 INFO
        logger.setLevel(Level.INFO);

        // 这条日志可以打印,因为 WARN >= INFO
        logger.warn("警告信息");
        // 这条日志不会打印,因为 DEBUG < INFO
        logger.debug("调试信息");

        // "com.foo.bar" 会继承 "com.foo" 的有效级别
        Logger barLogger = LoggerFactory.getLogger("com.foo.bar");
        // 这条日志会打印,因为 INFO >= INFO
        barLogger.info("子级信息");
        // 这条日志不会打印,因为 DEBUG < INFO
        barLogger.debug("子级调试信息");
    }

Logger对象获取

通过 LoggerFactory.getLogger() 可以获取到具体的 logger 实例,名字相同则返回的 logger 实例也相同。(工厂模式),这样生产的同样名称的logger对象是相同的。

Logger x = LoggerFactory.getLogger("wombat");
Logger y = LoggerFactory.getLogger("wombat");

x与y是相同的对象,并且即使后生成父对象,任然会生成上述的继承等级。
推荐使用但类的全限定名来对 logger 进行命名,是目前最好的方式,没有之一。方便看出打印日志所在的类

Appender与layout

  1. Appender:对于Logback框架来说输出目的地即为Appender,一个logger可以有多个Appender。logger可以调用addAppender()来增加Appender,对于每一个日志都会输出到所有Appender
  2. Appender:具有叠加性,如果 root logger 添加了一个 console appender,所有允许输出的日志至少会在控制台打印出来。如果再给一个叫做 L 的 logger 添加了一个 file appender,那么 L 以及 L 的子级 logger 都可以在文件和控制台打印日志。
  3. Layout:日志输出格式,PatternLayout通过格式化输出日志类似于C语言的Printf函数。

日志打印性能

参数化日志
  1. 会有日志中参数拼接的损耗
  2. 推荐使用logger.isDebugEnabled()进行判断
  3. 日志格式化的方法:logger.debug(“asaf{}”,xx);这样子的方法能够在不打印日志的时候提高性能

底层设计

如下简述名为com.zmm的logger.info()的流程

  1. 过滤器责任链,通过每一条日志请求信息,进行过滤,如果过滤器返回的是Filter.DENY,那么这条日志就被丢弃,如果是FilterReply.neutral则会继续执行下一步。如果为ACCEPT则直接执行第3步
  2. 应用基本规则:比较应用有效级别与日志请求级别,如果符合则进入下一步,否则就丢弃日志
  3. 创建事件对象:LoggerEvent对象被创建,此对象存在此次日志打印的所有相关信息,包含当前时间,当前线程以及当前类的各种信息
  4. 输入日志:当事件创立完毕,Logback会调用该logger的上下文中的所有Appender,并且调用该Appender.doAppend()。其中append()方法是线程安全的。
  5. 格式化日志新消息:appender对象负责格式化日志,但是如果比较复杂的格式化会给layout对象进行格式化返回一个字符串,比如SocketAppender并不会把日志时间转变为一个字符串,而是进行序列化,所以不需要layout。
  6. 发送到指定介质。

UML流程如下
image

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值