logback自定义日志格式,以json格式为例

一、背景

在项目开发中,我们有时候会遇到需要指定日志格式的场景,比如项目的日志接入了在线日志收集系统,该收集系统要求日志需要满足其指定的日志格式才会被收集。

接下来,我就以打印json格式的日志为例,向各位分享两种方案。

二、方案

2.1 方案1

通过指定encoder的具体类为net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder类,在pattern中可以打印指定格式的日志。

pattern中的变量格式有三类。一类是logback自定义的诸如%level等,一类是如${app_name}这样我们定义在logback.xml中的properties。还有一类形如%X{variable_name}是通过在代码中设置进MDC变量的,关于MDC的使用本文就不展开了,感兴趣请自行搜索。

直接show出可用的logback配置代码,下面是一个appender的示例代码

xml 复制代码
    <appender name="your-appender-name" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log_path}/${app_name}-${currentTime}.log</File>
        <append>true</append>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log_path}/${app_name}-%d{yyyyMMdd}-%i.log</fileNamePattern>
            <maxHistory>${logback.file.maxHistory}</maxHistory>
            <maxFileSize>${logback.file.maxFileSize}</maxFileSize>
            <totalSizeCap>${logback.file.totalSizeCap}</totalSizeCap>
        </rollingPolicy>
        
        <!-- 打印json格式,请重点看这里-->
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                         <!--下面定义出一个json格式的消息,仅做示例-->
                        <!--具体的信息格式请根据你的需求而定-->
                        {
                        "app_name": "${app_name}_info",
                        "level": "%level",
                        "log_time": "%date{\"yyyy-MM-dd HH:mm:ss.SSS\"}",
                        <!--   "logger": "%logger",  %logger打印logger名字, %class打印具体类名-->
                        "logger": "%class",
                        "transaction_id": "%X{transaction_id}",
                        "address": "%X{address}",
                        "response_headers": "%X{response_headers}",
                        "response_payload": "%X{response_payload}",
                        "response_code": "%X{response_code}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

2.2 方案2

另一种打印自定义格式的方法则是通过代码处理。

  1. 首先,继承ch.qos.logback.core.LayoutBase<ILoggingEvent>,并重写doLayout(ILoggingEvent event)方法
java 复制代码
@Data
public class ProgramLayout extends LayoutBase<ILoggingEvent> {
    // 也可以自定义参数,后续可以在logback.xml中传入
    protected String appName;

    public ProgramLayout() {
    }

    /**
     * 覆盖该方法,可以定制需要的日志格式
     * @param event The event to format
     * @return
     */
    @Override
    public String doLayout(ILoggingEvent event) {
        ProgramLogParam params = new ProgramLogParam();
        params.setApp_name(this.appName);
        params.setLevel(event.getLevel().toString());
        params.setLogger(event.getLoggerName());
        params.setLog_time((new Timestamp(event.getTimeStamp())).toString());
        params.setTransaction_id(MDCUtil.getTransactionId());
        // 通过event.getFormattedMessage()就可以获取到源消息
        String message = event.getFormattedMessage();
        if (event.getThrowableProxy() != null) {
            ExtendedThrowableProxyConverter throwableConverter = new ExtendedThrowableProxyConverter();
            throwableConverter.start();
            message = event.getFormattedMessage() + "\n" + throwableConverter.convert(event);
            throwableConverter.stop();
        }

		// 如果打印的源日志消息就包含json格式的字符串,则截取该部分消息作为code_message
        int beginIndex = message.indexOf("{");
        int endIndex = message.lastIndexOf("}") + 1;
        if (beginIndex >= 0) {
            String jsonMsg = message.substring(beginIndex, endIndex);
            params.setCode_message(jsonMsg);
        } else {
            params.setCode_message(message);
        }
        return JSON.toJSONString(params) + CoreConstants.LINE_SEPARATOR;
    }
}

ProgramLogParam是个bean,我简单放一下,用了lombok的注解,方便查看

java 复制代码
@Data
public class ProgramLogParam {
    private String app_name;
    private String level;
    private String logger;
    private String log_time;
    private String code_message;
    private String transaction_id;
}
  1. 在logback.xml在配置encoder的layout为该ProgramLayout,即可达到打印指定日志格式的目的。
xml 复制代码
 <appender name="TRANSACTION_INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${LOG_HOME}/${APP_NAME}_info-info.log</file>
        <!--日志文档输出格式-->
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="com.demo.log.layout.TransactionLayout">
                <!--传入自定义参数-->
                <appName>${APP_NAME}</appName>
            </layout>
            <charset>UTF-8</charset>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/${APP_NAME}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>1024MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>2</maxHistory>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
相关推荐
G皮T13 分钟前
【Java】Java 运行时数据区域(一):名词概念
java·jvm·runtime·运行时·运行时数据区域
z***y86224 分钟前
Java数据挖掘开发
java·开发语言·数据挖掘
鱼锦0.028 分钟前
基于spring+vue把图片文件上传至阿里云oss容器并回显
java·vue.js·spring
從南走到北33 分钟前
JAVA国际版同城跑腿源码快递代取帮买帮送同城服务源码支持Android+IOS+H5
android·java·ios·微信小程序
q***098035 分钟前
Spring Boot 2.7.x 至 2.7.18 及更旧的版本,漏洞说明
java·spring boot·后端
程序员爱钓鱼39 分钟前
Python 编程实战 · 进阶与职业发展:数据分析与 AI(Pandas、NumPy、Scikit-learn)
后端·python·trae
q***14641 小时前
oracle 12c查看执行过的sql及当前正在执行的sql
java·sql·oracle
程序员爱钓鱼1 小时前
Python 编程实战 · 进阶与职业发展:Web 全栈(Django / FastAPI)
后端·python·trae
IT_陈寒1 小时前
90%的Python开发者不知道:这5个内置函数让你的代码效率提升300%
前端·人工智能·后端
好好研究1 小时前
SpringMVC框架 - 获取请求参数常用的注解
java·spring·mvc