最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何自定義一個log適配器starter

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

需求

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

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

  • app:應(yīng)用名稱
  • host:主機IP
  • env:環(huán)境(DEV、UAT、GRAY、PRO)
  • namespace:命名空間(默認main,多版本用到)
  • message:日志內(nèi)容
  • logCategory:日志分類 (HttpServer、HttpClient、DB、Job)
  • level:日志等級(Debug、Info、Warn、Error、Fatal)
  • error:錯誤明細,可以為錯誤堆棧信息
  • createdOn:寫日志時間,毫秒時間戳,比如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 項目目錄結(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實現(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)下的主機名/IP
        InetAddress inetAddress = null;
        try {
            inetAddress = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {

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

MDCInterceptor 實現(xiàn)

MDCInterceptor 用于在每個請求的生命周期中設(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實現(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)下的主機名/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>
                <!-- 顯式指定毫秒時間戳的類 -->
                <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

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

<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實現(xiàn)日志自定義字段格式

平臺日志需要日志level 為首字母大寫,時間createdOn 需要為時間戳,并且為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 作為日志的一個字段來寫入
        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"/>
                <!-- 顯式指定毫秒時間戳的類 -->
                <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é)

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

相關(guān)文章

  • Java中的線程中斷機制和LockSupport詳解

    Java中的線程中斷機制和LockSupport詳解

    這篇文章主要介紹了Java中的線程中斷機制和LockSupport詳解,在Java中沒有辦法立即停止一條線程,然而停止線程卻顯得尤為重要,如取消一個耗時操作,因此,Java提供了一種用于停止線程的協(xié)商機制中斷,也即中斷標(biāo)識協(xié)商機制,需要的朋友可以參考下
    2023-09-09
  • idea創(chuàng)建SpringBoot自動創(chuàng)建Lombok無效果的問題解決方案

    idea創(chuàng)建SpringBoot自動創(chuàng)建Lombok無效果的問題解決方案

    這篇文章主要介紹了idea創(chuàng)建SpringBoot自動創(chuàng)建Lombok無效果的問題解決方案,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • Java RMI機制講解

    Java RMI機制講解

    這篇文章主要介紹了Java RMI機制講解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • Java版本兼容性之JDK 21的SDK在JDK 1.8的使用解讀

    Java版本兼容性之JDK 21的SDK在JDK 1.8的使用解讀

    文章介紹了Java的字節(jié)碼版本機制以及如何處理UnsupportedClassVersionError錯誤,文章首先解釋了JVM如何通過檢查.class文件的字節(jié)碼版本號來確定是否可以運行該文件,然后給出了三個解決方案:統(tǒng)一環(huán)境、交叉編譯和多版本JAR
    2025-11-11
  • java分頁攔截類實現(xiàn)sql自動分頁

    java分頁攔截類實現(xiàn)sql自動分頁

    這篇文章主要為大家詳細介紹了java分頁攔截類可以實現(xiàn)sql自動分頁,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Java基礎(chǔ)之CardLayout的使用

    Java基礎(chǔ)之CardLayout的使用

    這篇文章主要介紹了Java基礎(chǔ)之CardLayout的使用,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • SpringBoot中使用攔截器攔截跳轉(zhuǎn)登錄的兩種實現(xiàn)方法

    SpringBoot中使用攔截器攔截跳轉(zhuǎn)登錄的兩種實現(xiàn)方法

    攔截器(Interceptor)是Spring框架提供的一種機制,用于在請求的生命周期中插入自定義邏輯,如身份驗證、日志記錄等,本文將詳細介紹兩種在SpringBoot中使用攔截器來控制用戶登錄并跳轉(zhuǎn)到指定頁面的方法,需要的朋友可以參考下
    2024-11-11
  • Java對int[]數(shù)組做新增刪除去重操作代碼

    Java對int[]數(shù)組做新增刪除去重操作代碼

    這篇文章主要介紹了Java里面對int[]數(shù)組做新增刪除去重實現(xiàn),這里記錄下使用int[]數(shù)組對數(shù)組進行新增刪除去重等操作,用來更加了解java里面的集合類思想,需要的朋友可以參考下
    2023-10-10
  • 如何通過idea把項目到私有倉庫

    如何通過idea把項目到私有倉庫

    本文介紹Harbor倉庫的創(chuàng)建與使用流程,涵蓋Maven遠程配置、pom.xml參數(shù)設(shè)置、Dockerfile構(gòu)建鏡像及執(zhí)行發(fā)布步驟,旨在實現(xiàn)項目運維自動化,降低維護成本
    2025-07-07
  • java計算自然數(shù)中的水仙花數(shù)的方法分享

    java計算自然數(shù)中的水仙花數(shù)的方法分享

    這篇文章主要介紹了java計算自然數(shù)中的水仙花數(shù)的方法,需要的朋友可以參考下
    2014-03-03

最新評論

西青区| 杭州市| 民县| 泸州市| 略阳县| 咸宁市| 拜泉县| 汕头市| 江油市| 元阳县| 清水县| 张家港市| 松阳县| 法库县| 庐江县| 连城县| 鄂尔多斯市| 拉孜县| 华蓥市| 福清市| 怀宁县| 南和县| 来宾市| 新民市| 水富县| 枣强县| 枣阳市| 屏南县| 呈贡县| 克山县| 万州区| 资中县| 如东县| 色达县| 方正县| 东乌珠穆沁旗| 监利县| 博客| 齐河县| 鄂州市| 江城|