logback--进阶--02--Logger,Appenders 和 Layouts

logback–进阶–02–Logger,Appenders 和 Layouts


代码位置
https://gitee.com/DanShenGuiZu/learnDemo/tree/master/logback-learn

1、介绍

  1. Logback依赖于三个主要类:Logger,Appender 和 Layout。
  2. Logger 类是 logback-classic 模块的一部分
  3. Appender和Layout接口是 logback-core 模块的一部分。但是logback-core没有Logger记录器的概念。

2、Logger

  1. 在 logback-classic 中,Logger 是有继承关系的。
  2. 每个单独的 logger 都会关联到一个 LoggerContext,LoggerContext 负责制造 logger, 并将它们按树状结构排列。
  3. logger 记录器是带有名称的 Logger 对象,它们的名称区分大小写,并且遵循层级命名规则。

2.1、Logger 名称层次规则

  1. 记录器的名称层级规则跟 “.” 有关,它们有父亲或者祖先的关系。
  2. 例如:
    1. 命名为 com.nobody 的 logger 是命名为 com.nobody.User 的 logger 的父亲
    2. java 是 java.util 的父亲,是 java.util.List 的祖先。

2.2、root logger

位于 Logger 层次结构的顶部。我们可以按其名称获取到它

public static void main(String[] args) {
    Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
    rootLogger.info("rootLogger:{}", rootLogger.getName());
}

在这里插入图片描述

2.3、获取一个 Logger 对象

我们一般用 类的全限定名称作为 logger 名称,获取一个 Logger 对象,用于类中打印日志

public   class Demo5 {

    public static void main(String[] args) {
        //用 类的全限定名称作为 logger 名称,获取一个 Logger 对象
        Logger logger = LoggerFactory.getLogger(Demo5.class);
        logger.info("Hello Logback!");
    }
}

2.4、通过LoggerFactory.getLogger 获取相同名字的logger记录器,都是返回同一对象

public   class Demo5 {

    public static void main(String[] args) {
        //用 类的全限定名称作为 logger 名称,获取一个 Logger 对象
        Logger logger = LoggerFactory.getLogger(Demo5.class);
        Logger logger2 = LoggerFactory.getLogger("fei.zhou.logbacklearn.business.demo.Demo5");

        logger.info("logger :"+logger.hashCode()+"");
        logger.info("logger2:"+logger2.hashCode()+"");
    }
}

在这里插入图片描述

2.5、有效级别

  1. 有效级别也称为日志级别继承规则。
  2. 日志级别种类有TRACE,DEBUG,INFO,WARN 和 ERROR,它们在 ch.qos.logback.classic.Level中定义。
  3. 在 logback 中,Level 类是 final 的,不能被继承的。
  4. 级别按以下顺序排序:TRACE < DEBUG < INFO < WARN < ERROR。
  5. 如果没有为给定的 logger 记录器分配一个级别,那么它将从其最接近的祖先那里继承一个已分配的级别,比如一个 logger 的有效级别等于其层次结构中的第一个非空级别,它从其本身开始,在层次结构中向上扩展直到 root logger。
  6. 为了确保所有 logger 记录器最终都可以继承到级别,root logger 始终具有分配的级别。
    1. 默认情况下,此级别是 DEBUG。
  7. 打印方法决定记录请求的级别。
    1. 如果 L 是一个 logger 实例,则语句 L.info(“…”) 是一条级别为 INFO 的记录语句。
      1. 记录请求的级别只有高于或等于其 logger 的有效级别时被称为被启用,否则,称为被禁用。
    2. 假设记录请求级别为 p,其 logger 的有效级别为 q,只有则当 p>=q 时,该请求才会被执行。

2.6、有效级别测试

public class Demo5 {
    
    public static void main(String[] args) {
        
        // 获取一个名为 "com.foo" 的 logger 对象,并且转换为 ch.qos.logback.classic.Logger
        // 这样我们能为它设置级别
        ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.foo");

        //设置info级别
        logger.setLevel(Level.INFO);

        // 可以执行,因为 WARN >= INFO
        logger.warn("可以执行,因为 WARN >= INFO");
        
        // 不能执行,因为 DEBUG < INFO.
        logger.debug("不能执行,因为 DEBUG < INFO");

        // 获取一个名为 "com.boo.Bar" 的 logger 对象,没有设置级别,根据继承关系,继承"com.foo"的 logger的级别 INFO

        Logger barLogger = LoggerFactory.getLogger("com.foo.Bar");
        // 根据级别继承关系,可以执行,因为 INFO >= INFO.
        barLogger.info("根据级别继承关系,可以执行,因为 INFO >= INFO.");
        // 根据级别继承关系,不能执行,因为 DEBUG < INFO.
        barLogger.debug("根据级别继承关系,不能执行,因为 DEBUG < INFO.");
    }
}

在这里插入图片描述

3、Appenders

  1. appender 也叫做输出目标,将日志记录请求打印到目的地。
  2. 一个 logger 可以与多个 appender 绑定。

3.1、appender 种类

  1. 控制台
  2. 文件
  3. 远程 socket 服务
  4. MySQL
  5. PostgreSQL
  6. Oracle
  7. JMS
  8. 远程 UNIX Syslog 守护程序

3.2、日志输出流程

一个可以执行的日志打印请求,会将日志输出到当前 logger 关联的 appender,并且会根据层级关系输出到所有上层级 logger 所关联的 appender 中。

我们可以通过将 logger 的可叠加性标志additivity flag设置为 false,覆盖此默认行为,这样不会将日志输出到更高层级 logger 的 appender 中。

3.3、案例

假如有个 logger X.Y.Z,默认会将日志输出到 X.Y.Z,X.Y,X 这三个 logger 所关联的 appender 中。

1. 如果将 X.Y 这个 logger 的 additivity flag 设置为 false,则 X.Y.Z logger 打印的日志只会输出到 X.Y.Z 和 X.Y。

2. 如果将 X.Y.Z logger 的 additivity flag 设置为 false,则 X.Y.Z logger 打印的日志只会输出到 X.Y.Z 。

3、Layouts

  1. 用于自定义日志输出格式
  2. 通过将 layout 和 appender 相关联来实现
    1. layout 负责根据用户的需求格式化日志记录请求
    2. appender 负责将格式化后的日志输出发送到目的地。

3.1、案例

如果 patternLayout 配置为 “%-4relative [%thread] %-5level %logger{32} - %msg%n”,将输出类似以下格式日志信息:

176  [main] DEBUG manual.architecture.HelloWorld2 - Hello world.
  1. 第1个字段:自程序启动以来经过的毫秒数。
  2. 第2个字段:发出日志请求的线程名称。
  3. 第3个字段:日志请求的级别。
  4. 第4个字段:与日志请求关联的 logger 的名称。
  5. “-” 之后:日志信息。

3.2、参数化的日志

有些日志打印方法允许使用多个参数。这些带有多个参数的打印方法能提高性能,同时最大程度提高代码可读性。

例如,以下写法,为了构造 debug 方法的 msg 参数,会将整数 i 和 entry[i] 字符串都转换为字符串,并连接中间字符串,从而产生开销。不管最终此行代码是否会打印。

logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

为避免参数构造成本的一种方法,是在打印日志前,判断此 logger 是否开启此级别。

if(logger.isDebugEnabled()) { 
  logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}

这样,如果我们禁用了 debug 级别,则不会产生 msg 参数构造的开销。但是,如果 logger 开启了 debug 级别,则将产生两次开销,一次是判断 debugEnabled,一次是 debug 打印。实际上,debugEnabled 这种开销微不足道,因为它是实际日志打印请求所花费时间的不到1%。

不过有更好的选择,基于消息格式的方法,例如如下所示:

Object entry = new SomeObject(); 
logger.debug("The entry is {}.", entry);

只有在 debug 打印语句是开启的情况下,logger 才会格式化消息,并用 entry 代替 {}。也就是说,当禁用 debug 级别时,是不会产生 msg 参数构造的开销的。

以下两行将产生完全相同的输出。但是,在禁用日志记录语句的情况下,第二个将比第一个好至少30倍。

logger.debug("The new entry is "+entry+".");
logger.debug("The new entry is {}.", entry);

如果需要传递三个或更多参数,您可以这样写:

Object[] paramArray = {newVal, below, above};
logger.debug("Value {} was inserted between {} and {}.", paramArray);

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值