实现自定义SpringBoot框架日志组件の三: 自定义pattern

系列

实现自定义SpringBoot框架日志组件の一:日志系统
实现自定义SpringBoot框架日志组件の二:配置文件
实现自定义SpringBoot框架日志组件の三: 自定义pattern
实现自定义SpringBoot框架日志组件の四: 自适应

前言

前面我们自定义了输出格式,能够输出了,不过输出的还有一些瑕疵,这篇博客就来优化一下

目标:

  1. 输出带有方法名和行号
  2. 输出形式类似 logback的那种自动伸缩

pattern

上一篇博客,我直接贴出来了配置,但是没有详细讲解,因为这篇博客会去扩展pattern,所以这里简单介绍一下

%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight{%5p} [%clr{%23t}{magenta}] %highlight{%-40.40c{1.}} %clr{:}{faint} %m%n%ex

  1. %d
    输出时间,全称是 %date,后面接的参数是时间格式
  2. %highlight{%5p}
    %p是日志级别,全称是%level(不知道为什么没有对上),%5p 输出长度最小为5,长度不够左侧补空格,想要右侧补空格就是 %5-p, %highlight 颜色高亮,高亮配色是log4j2内置的,当然了你也可以自定义,如何配置请看官网Pattern Layout (网页记得往下拉,内容在中间)
  3. [%clr{%23t}{magenta}]
    %t输出线程name;%23t输出23长度,不够左侧补空格;%clr{xxx}{magenta} xxx输出固定的颜色magenta,颜色name列表还是看上面的官网链接;[]输出中括号
  4. %highlight{%-40.40c{1.}}
    %c是包名+类名; -40是最小长度40,不够右侧补空格(删除-就是左侧补空格),超出了就超出了;.40就是最大长度40,如果超出那就截掉左侧多余的; c{1.} 就是只完整输出类名,每个包名全部简略输出缩短为1,同理c{2.}就是每个包名缩短为2; %highlight 颜色高亮
  5. %ex
    异常的输出格式;没有异常的时候,这个不生效,有异常的时候,异常按照这个格式输出;不配置的话,默认是%xEx,此时会打印异常的扩展信息(JAR名称和版本),可能导致业务线程Block, 详见 美团技术

下图是pattern %d{yyyy-MM-dd HH:mm:ss.SSS} %highlight{%5p} [%clr{%23t}{magenta}] %highlight{%-40c} | %highlight{%.40c} | %highlight{%-40.40c{1.}} %clr{:}{faint} %m%n%ex的输出,大家感受一下

image.png

logback

我们运行一下 web-default,这个工程什么都没有配置,所以日志组件是 logback的,我们看一下效果

logback

可以看出来类名的输出效果是:

  1. 对齐,满足最大长度的限制
  2. 满足1的前提下,从右往左尽量输出多的包名

而 log4j2 的输出行为,只实现了功能1,没有功能2,


log4j2

方法和行号

%M 方法
%L 行号
这两个输出的时候,需要得到 location 信息,性能会降低一些

张哈希大佬给出了一个思路,大家可以参考 在被线上大量日志输出导致性能瓶颈毒打了很多次之后总结出的经验

我这里是不想那么麻烦,降低就降低吧,直接拿来用了

注意:log4j2 默认是不包含位置信息 location 的,也就是说 %M %L 默认情况下不会输出,需要主动开启,如以下配置

<AsyncRoot level="info" includeLocation="true">
          <AppenderRef ref="Console" />
           <AppenderRef ref="FILE" />
</AsyncRoot>

自定义 pattern

前面说了这么多,是为了介绍背景知识,一切都是为了实现我们的目标,这里再描述一下目标

目标:

  1. 输出带有方法名和行号
  2. 输出形式类似 logback的那种自动伸缩

为了实现目标1,我们的 pattern 就是 [%c.%M():%L]
但是因为log4j2 不支持自动伸缩,那没办法,只好自行实现一个了 Conversion Pattern
我们现在定义一个表达式吧,就叫 prettyClass, 意思是更优雅的类输出
再加一个长度限制,但是不想那么麻烦,就只支持纯数字的吧,写法是这样的 prettyClass

PrettyClassPatternConverter

那么该从哪里开始呢?
在张哈希的那篇博客里,我们看到他实现了一个自定义异常格式化插件


image.png

不难看出,log4j2 的异常默认插件就是 ThrowablePatternConverter, 且能猜到这个类的兄弟类都是各种插件

image.png

但是 %ex 是没有参数,我们还得找一个带参数的实现

image.png

经过debug,参数在构造方法的参数 options 里面

因为我们还要输出行号这种带 location 信息的,我们看一下行号的实现

image.png

可以发现这个实现类实现了接口 LocationAware

那么我们的思路就清晰了,有了如下代码 PrettyClassPatternConverter

package com.github.hwhaocool.log;

import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.impl.LocationAware;
import org.apache.logging.log4j.core.pattern.ConverterKeys;
import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;

/**
 * @author yellowtail
 * @since 2022/8/27 23:16
 */
@Plugin(
        name = "LineLocationPatternConverter",
        category = "Converter"
)
@ConverterKeys({"pc", "prettyClass"})
public class PrettyClassPatternConverter extends LogEventPatternConverter implements LocationAware {

    protected PrettyClassPatternConverter(String name, String style) {
        super(name, style);
    }

    private PrettyClassPatternConverter(final String[] options) {
        this("PrettyClass", "prettyClass");
    }

    // 这个是被触发的得到实例的方法
    public static PrettyClassPatternConverter newInstance(final String[] options) {
        return new PrettyClassPatternConverter(options);
    }

   // 需要位置信息
    @Override
    public boolean requiresLocation() {
        return true;
    }

    @Override
    public void format(LogEvent event, StringBuilder toAppendTo) {

      // 代码太长了就不贴了
    }
}

代码在 github PrettyClassPatternConverter

输出

具体的实现就不多解释了,原则如下:

  1. 没有带长度参数,那就全输出
  2. 带了长度参数,但是没有那么长,就全输出,右侧补空格
  3. 带了长度参数,总长度超出了,且类名+方法+行号,加在一起也超出了,那么包名就按照每层只输出一位的最省模式输出(此时会出现对不齐)
  4. 带了长度参数,总长度超出了,但是类名+方法+行号加在一起没有超出,那么包名就按照从右往左满足总长度要求的情况下尽量保留输出的原则(此时能对齐,有可能还会出现省略和空格同时出现的场景,因为总长度优先,包名输出了就超长,只能省略,省略了之后又不满足,就只能输出空格)

效果如下
%highlight{%pc} 无限制,此时不会对齐

image.png

%highlight{%pc{50}} 限制为50

image.png

此时可以看到效果

此时再试一下更短的


image.png

可以看到 org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext 尽力缩短了,还是会超出,没办法了,最后只能超出,导致对不齐

可以看到 o.s.boot.web.embedded.tomcat.TomcatWebServer 从右往左 在尽力输出

参考

log4j2-官网Pattern Layout
美团技术-# 日志导致线程Block的这些坑,你不得不防

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容