日志那些事儿——谈谈需要日志输出的client jar应该如何设计

前言

上篇文章提到了应该如何设计需要输出日志的client jar,大概有三个比较重要的点。

  • 缩小jar包依赖范围,如果是基于maven,可以把client工程中依赖的日志相关jar scope设置为provided.
  • “感知”应用系统所使用的日志框架,匹配相应的日志框架
  • 不使用配置文件,改用编码配置logger

其中第一点非常好实现。本文着重分析第二点与第三点的思路和关键代码。

如何“感知”日志框架

记得很早之前第一次和彭老师喝咖啡的时候,彭老师问我最近在干啥,我说在做公司的权限平台。彭老师问我要设计的时候最开始想到的方案是啥,我说看了看网上的设计好像能满足项目的需求。彭老师说道你一开始其实应该想到像windows操作是怎么考虑权限问题的,看看它的设计说不定能找到灵感有更好地设计方案。 当然彭老师只是提供了一种思路,当面对问题的时候可以想想看有没有人已经很好得解决了这个问题。所以当我要在client jar中“感知”日志框架时,我会先想想在哪些场景下别人和我会有同样的需求。很明显,在一些中间件或者一些框架中会有这种需要,很多中间件会需要输出日志供调试和排错等。 所以,关于如何“感知”日志框架,我在某中间件中找到了答案,该中间件和我有同样的需求场景。对于我们平常使用来说,最重要的两种日志框架是log4j、logback,最重要的日志门面是slf4j、common-logging等,在本文场景中,暂不考虑log4j2。 “感知”日志框架,某中间件中是这么做的。

static {
        try {
            setLoggerFactory(new Slf4jLoggerFactory());
        } catch (Throwable var3) {
            try {
                setLoggerFactory(new Log4jLoggerFactory());              
            } catch (Throwable var2) {
                setLoggerFactory(new NopLoggerFactory());
            }
        } 
    }

public Slf4jLoggerFactory() throws ClassNotFoundException {    Class.forName("org.slf4j.impl.StaticLoggerBinder");
}

看见没,就是如此的简单粗暴,要判断系统中是否使用了slf4j,只需要判断“org.slf4j.impl.StaticLoggerBinder”是否存在。这种做法勉强可以算是对的吧,因为如果不使用slf4j,那引入slf4j的相关jar干嘛。这种做法简单粗暴,但是确实可行。

不使用配置文件,改用编码配置logger

前文提到了,如果要适配多种日志框架,那么就需要在client jar的classpath下准备多种不同的日志配置文件。使用配置文件不灵活,那么是否存在不使用配置文件的方式对Logger进行相关设置呢。答案肯定是有,那就是使用代码进行动态配置。 在对logback和log4j的源码进行分析的过程中提到,在logger.info过程中,会调用logger中所有的appender,那么我们要配置日志输出的路径,pattern等,只需要设置相应的appender就行,下文就将分别介绍如何使用代码设置logger的Appender

普通log4j appender设置

    public void configureAppender(org.apache.log4j.Logger logger, String name, String pattern,String fileName){
            DailyRollingFileAppender appender = new DailyRollingFileAppender();
        appender.setName(name);
        appender.setLayout(new PatternLayout(pattern)));
        appender.setAppend(true);
        appender.setFile(fileName);
        appender.setEncoding(encoding);
        appender.activateOptions();
        logger.removeAllAppenders();
        logger.addAppender(appender);
    }

以上代码为logger设置了一个DailyRollingFileAppender

slf4j+logback appender设置

public void configureAppender(ch.qos.logback.classic.Logger logger, String name, String pattern,String fileName){ 

        RollingFileAppender appender = new RollingFileAppender();
        appender.setContext(LogbackLoggerContextUtil.getLoggerContext());
        appender.setName(name);
        appender.setAppend(true);
        appender.setFile(fileName);
        TimeBasedRollingPolicy rolling = new TimeBasedRollingPolicy();
        rolling.setParent(appender);
        rolling.setFileNamePattern(fileName + ".%d{yyyy-MM-dd}");
        rolling.setContext(LogbackLoggerContextUtil.getLoggerContext());
        rolling.start();
        appender.setRollingPolicy(rolling);
        PatternLayout layout = new PatternLayout();
        layout.setPattern(pattern);
        layout.setContext(LogbackLoggerContextUtil.getLoggerContext());
        layout.start();
        appender.setLayout(layout);
        appender.start();
        this.logger.detachAndStopAllAppenders();
        this.logger.addAppender(appender);
        }

以上代码为logback设置了RollingFileAppender

需要注意的是,当使用slf4j的日志门面时,通过LoggerFactory.getLogger得到的logger实例实际类型不尽相同,当使用slf4j+log4j时为org.slf4j.impl.Log4jLoggerAdapter,当使用slf4j+logback时为ch.qos.logback.classic.Logger,前者需要通过反射的手段取得org.apache.log4j.Logger对其设置Appender。

关键代码已经列在上面了,很多代码其实出自官网,官方有提供使用代码进行logger的配置。最后上一张类图来说明整个设计,该类图完整地展示了如何设计一个能自适应多种日志类型的日志工具。

适配logback/log4j的日志类结构图.jpg

总结

大体的步骤就是识别日志框架,使用相应日志框架得到对应的logger,例如org.apache.log4j.Logger等,根据logger的实际类型将其包装成统一的logger类型并且配置相应的Appender。类图完整地展示了整个设计。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏令仔很忙

设计模式六大原则——迪米特法则(LoD)

   在图书馆借书,刚开始的时候,直接跑到相应的楼层去,到里面去转,去找要借的书,在里面溜达半天才能找到;后来知道图书馆有一个电脑查询处,然后直接在电脑上输入...

24410
来自专栏王亚昌的专栏

Way to Go

Go is designed from first principles to advance the practice of software enginee...

8820
来自专栏java一日一条

Java Fork/Join 框架

响应式编程(Reactive Programming / RP)作为一种范式在整个业界正在逐步受到认可和落地,是对过往系统的业务需求理解梳理之后对系统技术设计/...

28810
来自专栏老九学堂

【编程解惑】Java、JavaEE、JavaSE、Java Web、JavaScript有什么区别?

很多有想入门Java的小伙伴在听到Java那么多叫法的时候,是不是表示一脸懵逼,今天老九君就给大家捋一捋Java大家族间的分门别类。 ? Java分为:Jav...

41990
来自专栏NetCore

复杂而艰辛的重构之路--起步

你有没有试过,当你踏入一个新的公司,看到了几千几万几十万代码的时候,那种崩溃的感觉? 代码多不可怕,怕的是代码的可读性、维护性、扩展性是如此之差,这时候该怎么办...

21690
来自专栏何俊林

你是否真的适合搞NDK开发?

最近很多人说,Android越来越不好找工作了,学习NDK开发会不会好点,今天就聊聊这个问题。是否应该选择学NDK? 1 哪些场景下要用到NDK开发? 跨平台的...

22750
来自专栏编程

Go语言·听说你想让程序运行的更快?

作者:孙飞撩技术 链接:https://www.jianshu.com/p/0db174aebfec 來源:简书 共11254字,阅读需28分钟 迁移自 CSD...

22560
来自专栏王亚昌的专栏

Go语言入门之路

Go is designed from first principles to advance the practice of software enginee...

38350
来自专栏Android点滴积累

Android指纹识别深入浅出分析到实战(6.0以下系统适配方案)

  指纹识别这个名词听起来并不陌生,但是实际开发过程中用得并不多。Google从Android6.0(api23)开始才提供标准指纹识别支持,并对外提供指纹识别...

33380
来自专栏chenssy

【死磕 Spring】----- IOC 之深入理解 Spring IoC

在一开始学习 Spring 的时候,我们就接触 IoC 了,作为 Spring 第一个最核心的概念,我们在解读它源码之前一定需要对其有深入的认识,本篇为【死磕 ...

13320

扫码关注云+社区

领取腾讯云代金券