亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

如何自定義一個(gè)log適配器starter

 更新時(shí)間:2025年06月10日 11:56:51   作者:FLGB  
這篇文章主要介紹了如何自定義一個(gè)log適配器starter的問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

需求

為了適配現(xiàn)有日志平臺,java項(xiàng)目應(yīng)用日志需要添加自定義字段:

日志關(guān)鍵字段:

  • app:應(yīng)用名稱
  • host:主機(jī)IP
  • env:環(huán)境(DEV、UAT、GRAY、PRO)
  • namespace:命名空間(默認(rèn)main,多版本用到)
  • message:日志內(nèi)容
  • logCategory:日志分類 (HttpServer、HttpClient、DB、Job)
  • level:日志等級(Debug、Info、Warn、Error、Fatal)
  • error:錯誤明細(xì),可以為錯誤堆棧信息
  • createdOn:寫日志時(shí)間,毫秒時(shí)間戳,比如1725961448565

格式需要改編成json

{“app”:“formula”,“namespace”:“main”,“host”:“127.0.0.1”,“env”:“DEV”,“createdOn”:“2025-04-23T13:47:08.726+08:00”,“l(fā)evel”:“INFO”,“message”:“(????)??啟動成功 ?(′?`?)?”}

Starter 項(xiàng)目目錄結(jié)構(gòu)

logback-starter/
│
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── lf
│ │ │ └── logbackstarter
│ │ │ ├── config
│ │ │ │ ├── MDCInterceptor.java
│ │ │ │ ├── LogInitializer.java
│ │ │ │ └── LogbackInterceptorAutoConfiguration.java
│ │ │ │ └── LogbackProperties
│ │ │ └── LogbackAutoConfiguration.java
│ │ └── Resources
│ │ │ └── logback.xml
│ │ │ └── META-INF
│ │ │ └── spring.factories
└── pom.xml

pom.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.kayou</groupId>
  <artifactId>java-logs-starter</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>java-logs-starter</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <spring-boot.version>2.6.3</spring-boot.version>
  </properties>

  <!-- 只聲明依賴,不引入依賴 -->
  <dependencyManagement>
    <dependencies>
      <!-- 聲明springBoot版本 -->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-logging</artifactId>
    </dependency>
    <dependency>
      <groupId>net.logstash.logback</groupId>
      <artifactId>logstash-logback-encoder</artifactId>
      <version>6.6</version>
    </dependency>
    <!-- Logback Classic -->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>2.6.3</version>
        <!--                <configuration>-->
        <!--                </configuration>-->
        <!--                <executions>-->
        <!--                    <execution>-->
        <!--                        <goals>-->
        <!--                            <goal>repackage</goal>-->
        <!--                        </goals>-->
        <!--                    </execution>-->
        <!--                </executions>-->
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>8</source>
          <target>8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

LogInitializer實(shí)現(xiàn)

import org.slf4j.MDC;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.net.InetAddress;
import java.net.UnknownHostException;

@Configuration
@Order
public class LogInitializer {

    private final LogbackProperties properties;

    public LogInitializer(LogbackProperties properties) {
        this.properties = properties;
    }

    @PostConstruct
    public void init() {
        MDC.put("app", properties.getApp());
        MDC.put("env", properties.getEnv());
        MDC.put("namespace", properties.getNamespace());
        MDC.put("host", resolveLocalHostIp());
    }

    private String resolveLocalHostIp() {

        // 獲取 Linux 系統(tǒng)下的主機(jī)名/IP
        InetAddress inetAddress = null;
        try {
            inetAddress = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {

            return "unknown";
        }
        return inetAddress.getHostAddress();
    }
}

MDCInterceptor 實(shí)現(xiàn)

MDCInterceptor 用于在每個(gè)請求的生命周期中設(shè)置 MDC。

package com.lf;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MDCInterceptor implements HandlerInterceptor {

    private final LogbackProperties properties;

    public MDCInterceptor(LogbackProperties properties) {
        this.properties = properties;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        MDC.put("app", properties.getApp());
        MDC.put("env", properties.getEnv());
        MDC.put("namespace", properties.getNamespace());
        MDC.put("host", properties.getHost());
        return true;
    }
}

LogbackInterceptorAutoConfiguration實(shí)現(xiàn)

@Configuration
public class LogbackInterceptorAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(MDCInterceptor.class)
    public MDCInterceptor mdcInterceptor(LogbackProperties properties) {
        return new MDCInterceptor(properties);
    }

    @Bean
    public WebMvcConfigurer logbackWebMvcConfigurer(MDCInterceptor mdcInterceptor) {
        return new WebMvcConfigurer() {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(mdcInterceptor).addPathPatterns("/**");
            }
        };
    }
}

LogbackProperties

@ConfigurationProperties(prefix = "log.context")
public class LogbackProperties {
    private String app = "default-app";
    private String env = "default-env";
    private String namespace = "default-namespace";
    private String host = "";

    // Getter & Setter

    public String getApp() {
        return app;
    }

    public void setApp(String app) {
        this.app = app;
    }

    public String getEnv() {
        return env;
    }

    public void setEnv(String env) {
        this.env = env;
    }

    public String getNamespace() {
        return namespace;
    }

    public void setNamespace(String namespace) {
        this.namespace = namespace;
    }

    public String getHost() {
        if (host != null && !host.isEmpty()) {
            return host;
        }
        return resolveLocalHostIp();
    }

    public void setHost(String host) {
        this.host = host;
    }

    private String resolveLocalHostIp() {

        // 獲取 Linux 系統(tǒng)下的主機(jī)名/IP
        InetAddress inetAddress = null;
        try {
            inetAddress = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {

            return "unknown";
        }
        return inetAddress.getHostAddress();

    }
}

LogbackAutoConfiguration

@Configuration
@EnableConfigurationProperties(LogbackProperties.class)
public class LogbackAutoConfiguration {
}

resource

logback.xml

<included>

    <property name="LOG_PATH" value="/home/logs"/>

    <!-- 控制臺輸出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <mdc>
                    <includeMdcKeyName>app</includeMdcKeyName>
                    <includeMdcKeyName>env</includeMdcKeyName>
                    <includeMdcKeyName>namespace</includeMdcKeyName>
                    <includeMdcKeyName>host</includeMdcKeyName>
                    <includeMdcKeyName>createdOn</includeMdcKeyName>
                </mdc>

                <timestamp>
                    <fieldName>timestamp</fieldName>
                    <pattern>UNIX_MILLIS</pattern>
                    <timeZone>Asia/Shanghai</timeZone>
                </timestamp>

                <logLevel fieldName="level"/>
                <message fieldName="message"/>
                <stackTrace fieldName="stack_trace"/>
            </providers>
        </encoder>
    </appender>

    <!-- 文件輸出 -->
    <appender name="jsonLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APP_NAME}.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <mdc>
                    <includeMdcKeyName>app</includeMdcKeyName>
                    <includeMdcKeyName>env</includeMdcKeyName>
                    <includeMdcKeyName>namespace</includeMdcKeyName>
                    <includeMdcKeyName>host</includeMdcKeyName>
                    <includeMdcKeyName>createdOn</includeMdcKeyName>
                </mdc>
                <!-- 顯式指定毫秒時(shí)間戳的類 -->
                <timestamp>
                    <fieldName>timestamp</fieldName>
                    <pattern>UNIX_MILLIS</pattern>
                    <timeZone>Asia/Shanghai</timeZone>
                </timestamp>

                <logLevel fieldName="level"/>
                <message fieldName="message"/>
                <stackTrace fieldName="stack_trace"/>
            </providers>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="jsonLog"/>
    </root>

</included>

META-INF

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.lf.LogbackAutoConfiguration,\
  com.lf.LogbackInterceptorAutoConfiguration,\
  com.lf.LogInitializer

使用starter

引用starter

在其他項(xiàng)目中添加依賴:(需要install本地倉庫或deploy遠(yuǎn)程倉庫)

<dependency>
    <groupId>com.kayou</groupId>
    <artifactId>java-logs-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

在resource中添加日志文件logback.xml

<configuration scan="true">
    <!-- 添加自動意logback配置 -->
    <property name="APP_NAME" value="java-demo"/>
    <!-- 引入公共的logback配置 -->
    <include resource="logback-default.xml"/>

</configuration>

啟動日志效果

{"app":"java-demo","namespace":"default-namespace","host":"10.2.3.130","env":"dev","createdOn":"2025-04-23T14:41:57.981+08:00","level":"INFO","message":"Exposing 13 endpoint(s) beneath base path '/actuator'"}
{"app":"java-demo","namespace":"default-namespace","host":"10.2.3.130","env":"dev","createdOn":"2025-04-23T14:41:58.014+08:00","level":"INFO","message":"Tomcat started on port(s): 8090 (http) with context path ''"}
{"app":"java-demo","namespace":"default-namespace","host":"10.2.3.130","env":"dev","createdOn":"2025-04-23T14:41:58.125+08:00","level":"INFO","message":"Started Application in 4.303 seconds (JVM running for 5.293)"}

自定義Provider實(shí)現(xiàn)日志自定義字段格式

平臺日志需要日志level 為首字母大寫,時(shí)間createdOn 需要為時(shí)間戳,并且為Long數(shù)字, logback原生 mdc支持String 不支持其他類型

定義Provider

import ch.qos.logback.classic.spi.ILoggingEvent;
import com.fasterxml.jackson.core.JsonGenerator;
import net.logstash.logback.composite.AbstractJsonProvider;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;

@Configuration
public class MdcTypeAwareProvider extends AbstractJsonProvider<ILoggingEvent> {

    private final Set<String> longFields = new HashSet<>();

    public MdcTypeAwareProvider() {
        longFields.add("createdOn"); // 指定需要轉(zhuǎn)成 Long 類型的字段
    }

    @Override
    public void writeTo(JsonGenerator generator, ILoggingEvent event) throws IOException {
        Map<String, String> mdcProperties = event.getMDCPropertyMap();
        if (mdcProperties == null || mdcProperties.isEmpty()) {
            return;
        }
        for (Map.Entry<String, String> entry : mdcProperties.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            // 處理 level 字段,將首字母大寫
            if ("level".equalsIgnoreCase(key)) {
                value = value.substring(0, 1).toUpperCase() + value.substring(1).toLowerCase();
            }
            if (longFields.contains(key)) {
                try {
                    generator.writeNumberField(key, Long.parseLong(value));
                } catch (NumberFormatException e) {
                    generator.writeStringField(key, value); // fallback
                }
            } else {
                generator.writeStringField(key, value);
            }
        }
        // 將 level 作為日志的一個(gè)字段來寫入
        String level = event.getLevel().toString();
        level = level.substring(0, 1).toUpperCase() + level.substring(1).toLowerCase();  // 首字母大寫
        generator.writeStringField("level", level);
    }


}

spring.factories添加注入類

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.kayou.LogbackAutoConfiguration,\
  com.kayou.LogbackInterceptorAutoConfiguration,\
  com.kayou.LogInitializer,\
  com.kayou.MdcTypeAwareProvider

resource logback.xml 改造

去除引用的mdc,新增自定義mdc provider

 <!-- 控制臺輸出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>

                <provider class="com.kayou.MdcTypeAwareProvider"/>
                <!-- 顯式指定毫秒時(shí)間戳的類 -->
                <timestamp>
                    <fieldName>createdTime</fieldName>
                    <pattern>yyyy-MM-dd HH:mm:ss.SSS</pattern>
                    <timeZone>Asia/Shanghai</timeZone>
                </timestamp>
                <message fieldName="message"/>
                <stackTrace fieldName="stack_trace"/>
            </providers>
        </encoder>
    </appender>

    <!-- 文件輸出 -->
    <appender name="jsonLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APP_NAME}.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <provider class="com.kayou.MdcTypeAwareProvider"/>
                <timestamp>
                    <fieldName>createdTime</fieldName>
                    <pattern>yyyy-MM-dd HH:mm:ss.SSS</pattern>
                    <timeZone>Asia/Shanghai</timeZone>
                </timestamp>
                <message fieldName="message"/>
                <stackTrace fieldName="stack_trace"/>
            </providers>

        </encoder>
    </appender>

啟動日志輸出結(jié)果

{“app”:“java-demo”,“namespace”:“default-namespace”,“host”:“10.2.3.130”,“env”:“dev”,“createdOn”:1745820638113,“l(fā)evel”:“Info”,“createdTime”:“2025-04-28 14:10:38.596”,“message”:“(????)??啟動成功 ?(′?`?)?”}

優(yōu)化異步線程日志切不到的問題

如過在web請求處理中,使用了異步線程,web線程就直接返回了。后續(xù)子線程是不會被intercetor切到的。改成日志格式不匹配

在MdcTypeAwareProvider 去填充這些字段就可以了

@Configuration
public class LogbackPropertiesHolder {

    private static LogbackProperties properties;

    public LogbackPropertiesHolder(LogbackProperties properties) {
        LogbackPropertiesHolder.properties = properties;
    }

    public static LogbackProperties getProperties() {
        return properties;
    }
}
@Configuration
public class MdcTypeAwareProvider extends AbstractJsonProvider<ILoggingEvent> {

    private final Set<String> longFields = new HashSet<>();

    public MdcTypeAwareProvider() {
        longFields.add("createdOn");
    }

    @Override
    public void writeTo(JsonGenerator generator, ILoggingEvent event) throws IOException {
        Map<String, String> mdcProperties = event.getMDCPropertyMap();
        LogbackProperties properties = LogbackPropertiesHolder.getProperties();

        ensureMdcProperty(mdcProperties, "app", properties.getApp());
        ensureMdcProperty(mdcProperties, "env", properties.getEnv());
        ensureMdcProperty(mdcProperties, "namespace", properties.getNamespace());
        ensureMdcProperty(mdcProperties, "host", resolveLocalHostIp());
        ensureMdcProperty(mdcProperties, "createdOn", String.valueOf(System.currentTimeMillis()));

        for (Map.Entry<String, String> entry : mdcProperties.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();

            if (longFields.contains(key)) {
                try {
                    generator.writeNumberField(key, Long.parseLong(value));
                } catch (NumberFormatException e) {
                    generator.writeStringField(key, value);
                }
            } else {
                generator.writeStringField(key, value);
            }
        }

        String level = event.getLevel().toString();
        generator.writeStringField("level", level.substring(0, 1).toUpperCase() + level.substring(1).toLowerCase());
    }

    private void ensureMdcProperty(Map<String, String> mdcProperties, String key, String defaultValue) {
        if (!mdcProperties.containsKey(key)) {
            MDC.put(key, defaultValue);
        }
    }

    private String resolveLocalHostIp() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            return "127.0.0.1";
        }
    }
}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論