Spring-Boot整合ELK

概述

    SpringBoot整合ELK单指将SpringBoot日志推送至Logstash以及使用教程。

日志流程

    项目输出Log日志  --> TCP推送Logstash  -->  Logstash接收日志处理  -->  输出到Elasticsearch中  -->  Kibana图形化展示

    流程图如下:

<img src="https://blog-kang.oss-cn-beijing.aliyuncs.com/1619167113083.png" style="zoom:50%;" />

Logstash配置

TCP方式

input {
        # TCP输入,Json格式编码UTF-8
    tcp {
     port => 9400
      codec => json {
             charset => "UTF-8"
      }
    }
    stdin{}
}
filter {
}

output {
  elasticsearch {
    action => "index"
    # 这里是es的地址,多个es要写成数组的形式
    hosts  => "elasticsearch-server:9200"
    # 用于kibana过滤,可以填项目名称,按日期生成索引
    index  => "vosp-log-%{+YYYY-MM-dd}"
    # es用户名
    user => vosp
    # es密码
    password => vosp123
    # 超时时间
    timeout => 300
  }
}

SpringBoot+Log4j2

引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions><!-- 去掉springboot默认配置 -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency> <!-- 引入log4j2依赖 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

编写SpringBoot启动以及配置类

    新建配置类,

import org.slf4j.MDC;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;


/**
 * @Author HuangKang
 * @Date 2021/4/22 下午5:44
 * @Summarize Log4j2启动配置文件事件监听器
 * SpringApplication application = new SpringApplication(VospApiApplication.class);
 * Set<ApplicationListener<?>> ls = application.getListeners();
 * Log4j2PropertiesEventListener eventListener = new Log4j2PropertiesEventListener();
 * application.addListeners(eventListener);
 * application.run(args);
 * 启动类启动注册监听器
 */
public class Log4j2PropertiesEventListener implements GenericApplicationListener {

    public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;

    private static Class<?>[] EVENT_TYPES = {ApplicationStartingEvent.class, ApplicationEnvironmentPreparedEvent.class,
            ApplicationPreparedEvent.class, ContextClosedEvent.class, ApplicationFailedEvent.class};

    private static Class<?>[] SOURCE_TYPES = {SpringApplication.class, ApplicationContext.class};

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            ConfigurableEnvironment envi = ((ApplicationEnvironmentPreparedEvent) event).getEnvironment();
            MutablePropertySources mps = envi.getPropertySources();
            // 获取配置文件配置源,注意版本不同SpringBoot可能配置源名称不一样,可以DEBUG查看名称
            PropertySource<?> ps = mps.get("configurationProperties");
            // 设置log4j2日志收集logstash地址
            if (ps != null && ps.containsProperty("log4j2.logstash.address")) {
                Object address = ps.getProperty("log4j2.logstash.address");
                if (address != null && !address.toString().trim().isEmpty()) {
                    MDC.put("log4j2.logstash.address", address.toString());
                }
            }
            // 设置log4j2日志收集logstash端口号
            if (ps != null && ps.containsProperty("log4j2.logstash.port")) {
                Object port = ps.getProperty("log4j2.logstash.port");
                if (port != null && !port.toString().trim().isEmpty()) {
                    MDC.put("log4j2.logstash.port", port.toString());
                }
            }
            // 设置log4j2日志收集logstash日志格式化表达式
            if (ps != null && ps.containsProperty("log4j2.logstash.pattern")) {
                Object pattern = ps.getProperty("log4j2.logstash.pattern");
                if (pattern != null && !pattern.toString().trim().isEmpty()) {
                    // 获取项目名
                    String appName = ps.getProperty("spring.application.name").toString();
                    // 获取项目名
                    String profile = ps.getProperty("spring.profiles.active").toString();
                    MDC.put("log4j2.logstash.pattern", pattern.toString().replace("${spring.application.name}", appName).replace("${spring.profiles.active}",profile));
                }
            }

        }
    }

    @Override
    public int getOrder() {
        return DEFAULT_ORDER;
    }

    @Override
    public boolean supportsEventType(ResolvableType resolvableType) {
        return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);
    }

    @Override
    public boolean supportsSourceType(Class<?> sourceType) {
        return isAssignableFrom(sourceType, SOURCE_TYPES);
    }

    private boolean isAssignableFrom(Class<?> type, Class<?>... supportedTypes) {
        if (type != null) {
            for (Class<?> supportedType : supportedTypes) {
                if (supportedType.isAssignableFrom(type)) {
                    return true;
                }
            }
        }
        return false;
    }
}

    修改SpringBoot启动类,添加监听器
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(BootK8sApplication.class);
        // 添加Log4j2配置文件监听
        Log4j2PropertiesEventListener eventListener = new Log4j2PropertiesEventListener();
        application.addListeners(eventListener);
        application.run(args);
    }       

编写配置文件

    在Yaml中写入如下参数
spring:
  application:
    # 项目名称启动时传入Log4j2作为app名称
    name: test-k8s

logging:
  # Log4j2配置文件xml地址
  config: classpath:log4j2-spring.xml
log4j2:
  logstash:
    # 自定义配置Logstash地址
    address: 124.71.9.101
    # 自定义配置Logstash端口号
    port: 9400
    # 自定义Json消息
    # {
        #   "app": "${spring.application.name}",  当前项目名称
        #   "class": "%c",                        类全限定名称
        #   "method": "%M",                       输出日志方法
        #   "traceId": "%X{traceId}",             traceId跟踪
        #   "level": "%level",                    日志级别
        #   "message": "[%thread] [%c:%L] --- %replace{%msg}{\"}{\\\"}\"  消息内容体,将"替换为转义,防止日志中输出Json导致解析异常
        #   "profile":"${spring.profiles.active}" 当前启动环境
    # }
    # Json写入至ELK中属性
    pattern: "{\"app\":\"${spring.application.name}\", \"profile\":\"${spring.profiles.active}\", \"class\":\"%c\",\"method\":\"%M\",\"traceId\":\"%X{traceId}\",\"level\": \"%level\", \"message\": \"[%thread] [%c:%L] --- %replace{%msg}{\\\"}{\\\\\\\"}\\\"}%n"

编写Log4j2-XML文件

<?xml version="1.0" encoding="UTF-8"?>

<configuration status="info" monitorInterval="30">

    <properties>
        <!--日志路径-->
        <property name="log.path">./logs</property>
        <!--日志打印格式-->
        <property name="pattern">%d{yyyy-MM-dd HH:mm:ss,SSS} [%-5level] [%X{traceId}] [%t] [%C{1.}] %msg%n</property>

        <!--SpringBoot读取的配置地址,端口以及日志格式-->
        <Property name="logstashAddress">${ctx:log4j2.logstash.address}</Property>
        <Property name="logstashPort">${ctx:log4j2.logstash.port}</Property>
        <Property name="logstashPattern">${ctx:log4j2.logstash.pattern}</Property>
    </properties>
    <!--先定义所有的appender-->
    <appenders>
        <!--这个输出控制台的配置-->
        <console name="console" target="SYSTEM_OUT">
            <!--输出日志的格式-->
            <PatternLayout>
                <!-- 控制台彩色日志格式 -->
                <Pattern>%style{%d{yyyy-MM-dd HH:mm:ss,SSS}}{bright,white} %highlight{%-5level} %style{[%X{traceId}]}{cyan} [%style{%t}{bright,blue}] [%style{%C{1.}}{bright,yellow}:%L] %msg%n%style{%throwable}{red}</Pattern>
                <!-- 控制台统一日志格式 -->
                <!--                <Pattern>${pattern}</Pattern>-->
            </PatternLayout>
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
        </console>
        <RollingFile name="infoLog" immediateFlush="true" fileName="${sys:log.path}/info.log"
                     filePattern="${sys:log.path}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.zip">
            <Filters>
                <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
                <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <PatternLayout>
                <Pattern>${pattern}</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>

        <RollingFile name="warnLog" immediateFlush="true" fileName="${sys:log.path}/warn.log"
                     filePattern="${sys:log.path}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.zip">
            <Filters>
                <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
                <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <PatternLayout>
                <Pattern>${pattern}</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>

        <RollingFile name="errorLog" immediateFlush="true" fileName="${sys:log.path}/error.log"
                     filePattern="${sys:log.path}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.zip">
            <Filters>
                <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
                <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <PatternLayout>
                <Pattern>${pattern}</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>
        <!-- Socket TCP方式推送日志到Logstash中,只推送INFO以及以上级别日志 -->
        <Socket>
            <name>logstash</name>
            <protocol>TCP</protocol>
            <port>${logstashPort}</port>
            <host>${logstashAddress}</host>
            <PatternLayout pattern="${logstashPattern}"/>
            <reconnectionDelay>5000</reconnectionDelay>
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
        </Socket>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>
        <!--过滤掉无用的debug信息-->
        <logger name="org.springframework" level="INFO"/>
        <logger name="org.mybatis" level="INFO"/>
        <logger name="cn.binarywang" level="ERROR"/>
        <!--指定了logger就使用logger,没有指定就使用root-->
        <logger name="com.botpy.vosp.client" level="debug" additivity="false">
            <appender-ref ref="console"/>
            <appender-ref ref="infoLog"/>
            <appender-ref ref="warnLog"/>
            <appender-ref ref="errorLog"/>
        </logger>
        <logger name="logstashLog" level="info" additivity="false">
            <appender-ref ref="logstash"/>
        </logger>
        <root level="debug">
            <appender-ref ref="console"/>
            <appender-ref ref="infoLog"/>
            <appender-ref ref="warnLog"/>
            <appender-ref ref="errorLog"/>
            <appender-ref ref="logstash" />
        </root>
    </loggers>
</configuration>

新增traceId拦截器

    新建拦截器

import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

/**
 * @Author HuangKang
 * @Date 2021/4/23 下午2:23
 * @Summarize 请求TraceId拦截器
 */
@Component
public class RequestTraceIdInterceptor implements HandlerInterceptor {
    /**
     * 日志TRACE_ID名称常量
     */
    private static final String LOG_TRACE_ID_NAME = "traceId";

    /**
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        MDC.put(LOG_TRACE_ID_NAME, UUID.randomUUID().toString().replace("-",""));
        return true;
    }

}

    新增Mvc配置拦截器
package com.kang.test.k8s.config;

import com.kang.test.k8s.interceptor.RequestTraceIdInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author HuangKang
 * @Date 2021/4/23 下午4:00
 * @Summarize 自定义WebMvc配置
 */
@Configuration
public class CustomWebMvcConfig  implements WebMvcConfigurer {

    final RequestTraceIdInterceptor requestTraceIdInterceptor;

    @Autowired
    public CustomWebMvcConfig(RequestTraceIdInterceptor requestTraceIdInterceptor) {
        this.requestTraceIdInterceptor = requestTraceIdInterceptor;
    }

    /**
     * 添加拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加TraceId拦截器
        registry.addInterceptor(requestTraceIdInterceptor);
    }
}

    使用方式,新建Controller测试功能
    @RequestMapping("/")
    public Map index() throws UnknownHostException {
        Map<String, Object> map = new HashMap<>();
        InetAddress localHost = InetAddress.getLocalHost();
        String hostName = localHost.getHostName();
        String hostAddress = localHost.getHostAddress();
        map.put("主机名",hostName);
        map.put("主机地址",hostAddress);
        log.info("测试日志");
        return map;
    }
    调用接口后打印如下日志
可以查看到INFO  [3d9e051ceafe4e59bce8aa6ac2972fda] 成功打印traceId
2021-04-23 16:21:13,929 INFO  [3d9e051ceafe4e59bce8aa6ac2972fda] [http-nio-8080-exec-1] [c.k.t.k.c.TestK8sController:37] 测试日志

SpringBoot+Logback

引入依赖

    引入依赖正常即可
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>net.logstash.logback</groupId>
            <artifactId>logstash-logback-encoder</artifactId>
            <version>6.1</version>
        </dependency>

编写配置文件

spring:
  application:
    # 项目名称启动时传入,写入ELK通过app名称进行隔离
    name: test-k8s
  profiles:
    # 启动环境,ELK隔离通过profile属性隔离dev以及prod
    active: log
server:
  port: 8080
logging:
    # 日志文件地址
  config: classpath:logback-spring.xml
  # 配置Logstash地址
  logstash:
    address: 124.71.9.101:9400

编写XML文件

    新建XML文件,重点观察ELK Json属性,可以自定义拓展,新建logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--从配置文件读取配置路径,并且添加默认值-->
    <!--日志全局设置-->
    <springProperty scope="context" name="log.charset" source="log.charset" defaultValue="UTF-8"/>

    <springProperty scope="context" name="log.pattern" source="log.pattern"
                    defaultValue="%d{yyyy-MM-dd HH:mm:ss,SSS} [%-5level] [%X{traceId}] [%t] [%C{1.}] %msg%n"/>

    <!--INFO日志设置-->
    <springProperty scope="context" name="info.path" source="log.info.path" defaultValue="logs/info"/>
    <springProperty scope="context" name="info.history" source="log.info.history" defaultValue="10"/>
    <springProperty scope="context" name="info.maxsize" source="log.info.maxsize" defaultValue="1GB"/>
    <springProperty scope="context" name="info.filesize" source="log.info.filesize" defaultValue="10MB"/>
    <springProperty scope="context" name="info.pattern" source="log.info.pattern"
                    defaultValue="%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n"/>

    <!--ERROR日志设置-->
    <springProperty scope="context" name="error.path" source="log.error.path" defaultValue="logs/error"/>
    <springProperty scope="context" name="error.history" source="log.error.history" defaultValue="10"/>
    <springProperty scope="context" name="error.maxsize" source="log.error.maxsize" defaultValue="1GB"/>
    <springProperty scope="context" name="error.filesize" source="log.error.filesize" defaultValue="10MB"/>
    <springProperty scope="context" name="error.pattern" source="log.error.pattern"
                    defaultValue="%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n"/>

    <!--从SpringBoot配置文件读取项目名,环境,以及logstash地址-->
    <springProperty scope="context" name="springAppName" source="spring.application.name"/>
    <springProperty scope="context" name="springProfile" source="spring.profiles.active"/>
    <springProperty scope="context" name="logstashAddress" source="logging.logstash.address"/>

    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
    <!-- 定义彩色日志格式模板 -->

    <!--控制台日志打印格式-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <pattern>${log.pattern}</pattern>
            <charset>${log.charset}</charset>
        </encoder>
    </appender>

    <!--INFO日志打印-->
    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高, 所以我们使用下面的策略,可以避免输出 Error 的日志-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!--过滤 Error-->
            <level>ERROR</level>
            <!--匹配到就禁止-->
            <onMatch>DENY</onMatch>
            <!--没有匹配到就允许-->
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天的日志改名为今天的日期。即,<File> 的日志都是当天的。-->
        <!--<File>logs/info.spring-boot-demo-logback.log</File>-->
        <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
            <FileNamePattern>${info.path}/info_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>
            <!--只保留最近10天的日志-->
            <maxHistory>${info.history}</maxHistory>
            <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
            <totalSizeCap>${info.maxsize}</totalSizeCap>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为1KB,只是为了演示 -->
                <maxFileSize>${info.filesize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!--<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">-->
        <!--<maxFileSize>1KB</maxFileSize>-->
        <!--</triggeringPolicy>-->
        <encoder>
            <pattern>${info.pattern}</pattern>
            <charset>${log.charset}</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>
    <!--ERROR日志打印-->
    <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--如果只是想要 Error 级别的日志,那么需要过滤一下,默认是 info 级别的,ThresholdFilter-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天的日志改名为今天的日期。即,<File> 的日志都是当天的。-->
        <!--<File>logs/error.spring-boot-demo-logback.log</File>-->
        <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
            <FileNamePattern>${error.path}/error_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>
            <!--只保留最近90天的日志-->
            <maxHistory>${error.history}</maxHistory>
            <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
            <totalSizeCap>${error.maxsize}</totalSizeCap>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为1KB,只是为了演示 -->
                <maxFileSize>${error.filesize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>${error.pattern}</pattern>
            <charset>${log.charset}</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>


    <appender name="logstash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>${logstashAddress}</destination>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp>
                    <timeZone>UTC</timeZone>
                </timestamp>
                <pattern>
                    <pattern>
                        {
                        <!--设置项目-->
                        "app": "${springAppName:-}",
                        <!--设置环境-->
                        "profile": "${springProfile:-}",
                        <!--设置等级-->
                        "level": "%level",
                        <!--设置traceId-->
                        "traceId": "%X{traceId}",
                        <!--设置类名-->
                        "class": "%c",
                        <!--设置方法名-->
                        "method": "%M",
                        <!--设置消息-->
                        "message": "[%thread] [%X{traceId}] [%logger{35}:%L] --- %msg"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE_INFO"/>
        <appender-ref ref="FILE_ERROR"/>
        <appender-ref ref="logstash"/>
    </root>

</configuration>

新增traceId拦截器

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

推荐阅读更多精彩内容