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

springboot中的日志實現(xiàn)方式

 更新時間:2025年12月26日 09:35:07   作者:kkkkkkkkl24  
文章主要介紹了如何通過觀測來提升系統(tǒng)的性能和穩(wěn)定性,包括事件記錄、系統(tǒng)運行狀態(tài)的數(shù)字化、服務之間的全鏈路剖面等,同時,文章還分享了日志記錄、異常機制和日志進階的相關知識

很多人寫代碼,只管業(yè)務邏輯,不知道系統(tǒng)在跑的時候:

  • 哪個接口慢?
  • 哪個服務 QPS 高?
  • 哪個下游抖了?
  • 哪條鏈路撐不住了?
  • 哪個線程池快爆了?
  • 哪次 GC 卡頓導致 RT 抖動?

這些其實都可以通過觀測發(fā)現(xiàn),所以我想通過一系列的文章分享下“觀測”的實現(xiàn)。

一:觀測

1.1 “事件記錄”

你可以理解為:

“發(fā)生了什么”

比如:訂單創(chuàng)建、用戶登錄、異常、重試、降級等等。

  • 如果沒有 traceId,日志是碎片;
  • 如果有 traceId,日志就是“故事”。

1.2 “系統(tǒng)運行狀態(tài)的數(shù)字化”

你可以理解為:

“系統(tǒng)現(xiàn)在的健康狀況是什么”

比如:

  • QPS:有沒有被壓?
  • RT:變慢了嗎?
  • P99:高峰壓力如何?
  • JVM 堆:是否泄漏?
  • 線程池:是否被打滿?

1.3 “服務之間的全鏈路剖面”

你可以理解為:

“系統(tǒng)調(diào)用鏈長什么樣”

比如:一次下單 → 走了哪些服務、哪些接口、哪些耗時?

二:日志

2.1依賴

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

2.2配置

在resources文件夾下,添加logback-spring.xml文件,配置如下,

<configuration>
    <appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>具體文件路徑</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>具體文件路徑.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE"/>打印日志在控制臺(可以刪除,減小開銷)
        <appender-ref ref="JSON_FILE"/>輸出日志到文件
    </root>
</configuration>

三:異常機制

3.1統(tǒng)一相應結(jié)構(gòu)

@Data
public class ApiResponse<T> {
    private Integer code;
    private String message;
    private T data;

    public static <T> ApiResponse<T> success(T data) {
        ApiResponse<T> resp = new ApiResponse<>();
        resp.setCode(0);
        resp.setMessage("OK");
        resp.setData(data);
        return resp;
    }

    public static ApiResponse<?> fail(Integer code, String message) {
        ApiResponse<?> resp = new ApiResponse<>();
        resp.setCode(code);
        resp.setMessage(message);
        return resp;
    }
}

3.2錯誤碼枚舉

@Getter
public enum ErrorCode {
    SYSTEM_ERROR(10001, "系統(tǒng)異常,請稍后再試"),
    BAD_REQUEST(10002, "請求參數(shù)錯誤"),
    NOT_FOUND(10003, "資源不存在"),
    BUSINESS_ERROR(20001, "業(yè)務異常");

    private final int code;
    private final String msg;

    ErrorCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

3.3業(yè)務異常類

@Getter
public class BizException extends RuntimeException {

    private final int code;

    public BizException(ErrorCode errorCode) {
        super(errorCode.getMsg());
        this.code = errorCode.getCode();
    }
}

3.4全局異常處理器(核心)

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 處理業(yè)務異常
     */
    @ExceptionHandler(BizException.class)
    public ApiResponse<?> handleBizException(BizException e) {
        log.warn("Business exception: {}", e.getMessage(), e);
        return ApiResponse.fail(e.getCode(), e.getMessage());
    }

    /**
     * 處理系統(tǒng)異常
     */
    @ExceptionHandler(Exception.class)
    public ApiResponse<?> handleException(Exception e) {
        log.error("System exception:", e);
        return ApiResponse.fail(
                ErrorCode.SYSTEM_ERROR.getCode(),
                ErrorCode.SYSTEM_ERROR.getMsg()
        );
    }
}

四:日志進階

4.1加強日志

<configuration>

    <!-- JSON 文件輸出,按日期滾動 -->
    <appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>你的文件名</file>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>你的文件名.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>

         <!-- 核心:使用 Composite Encoder,讓我們能添加 MDC -->
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <!-- 時間戳 -->
                <timestamp />

                <!-- 日志等級 -->
                <logLevel />

                <!-- 線程名 -->
                <threadName />

                <!-- 日志位置 -->
                <callerData />

                <!-- 日志內(nèi)容 -->
                <message />

                <!-- 核心:輸出 MDC,如 traceId -->
                <mdc />

                <!-- 記錄 logger 名字 -->
                <loggerName />
            </providers>
        </encoder>
    </appender>

    <!-- 控制臺輸出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="JSON_FILE" />
    </root>
</configuration>

4.2TraceId 工具類

//追蹤id
public class TraceUtil {

    private static final String TRACE_ID = "traceId";

    public static String initTrace() {
        String traceId = UUID.randomUUID().toString().replace("-", "");
        MDC.put(TRACE_ID, traceId);
        return traceId;
    }

    public static void setTrace(String traceId) {
        MDC.put(TRACE_ID, traceId);
    }

    public static void clear() {
        MDC.remove(TRACE_ID);
    }

    public static String getTrace() {
        return MDC.get(TRACE_ID);
    }
}

4.3Filter

@Component
public class TraceIdFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
                                    throws ServletException, IOException {

        // 如果 header 已經(jīng)有 traceId,如網(wǎng)關或 NGINX 傳遞
        String traceId = request.getHeader("traceId");

        if (traceId == null || traceId.isEmpty()) {
            traceId = TraceUtil.initTrace();
        } else {
            TraceUtil.setTrace(traceId);
        }

        try {
            filterChain.doFilter(request, response);
        } finally {
            TraceUtil.clear();
        }
    }
}

4.4線程池追蹤

@Configuration
public class ThreadPoolConfig {

    @Bean("commonExecutor")
    public ThreadPoolTaskExecutor commonExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        executor.setCorePoolSize(8);
        executor.setMaxPoolSize(16);
        executor.setQueueCapacity(200);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("common-exec-");

        // 拒絕策略 
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());

        // 任務裝飾器(增強:日志、鏈路追蹤、異常等)
        executor.setTaskDecorator(runnable -> () -> {
            try {
                runnable.run();
            } catch (Exception e) {
                System.err.println("Execute error: " + e.getMessage());
                throw e;
            }
        });

        executor.initialize();
        return executor;
    }
}

總結(jié)

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

相關文章

  • MySQL三種常用存儲引擎InnoDB、MyISAM、Memory深度解析

    MySQL三種常用存儲引擎InnoDB、MyISAM、Memory深度解析

    在線教程千萬篇,為什么你的 SQL 還是慢?因為沒理解存儲引擎的底層機制,本文將帶你從源碼角度徹底搞懂 InnoDB 行鎖、聚簇索引,并給出生產(chǎn)環(huán)境的最優(yōu)選型,需要的朋友可以參考下
    2026-05-05
  • MySQL腳本批量自動插入數(shù)據(jù)及數(shù)據(jù)可按條件插入實現(xiàn)

    MySQL腳本批量自動插入數(shù)據(jù)及數(shù)據(jù)可按條件插入實現(xiàn)

    在初始化數(shù)據(jù)庫或者導入一些數(shù)據(jù)時,常常會用到批量的操作,本文主要介紹了MySQL腳本批量自動插入數(shù)據(jù)及數(shù)據(jù)可按條件插入實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • MySQL中EXPLAIN語句及用法實例

    MySQL中EXPLAIN語句及用法實例

    我們常常用到explain這個命令來查看一個這些SQL語句的執(zhí)行計劃,查看該SQL語句有沒有使用上了索引,下面這篇文章主要給大家介紹了關于MySQL中EXPLAIN語句及用法的相關資料,需要的朋友可以參考下
    2022-05-05
  • mysql查詢本周內(nèi)每天統(tǒng)計量按天展示的示例代碼

    mysql查詢本周內(nèi)每天統(tǒng)計量按天展示的示例代碼

    本文主要介紹了mysql查詢本周內(nèi)每天統(tǒng)計量按天展示的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 從原理到實踐詳解MySQL大批量數(shù)據(jù)導入的性能優(yōu)化指南

    從原理到實踐詳解MySQL大批量數(shù)據(jù)導入的性能優(yōu)化指南

    在日常運維或數(shù)據(jù)遷移場景中,MySQL大批量數(shù)據(jù)導入慢的問題經(jīng)常困擾著開發(fā)者和運維人員,本文將為大家詳細介紹三大核心優(yōu)化方案,幫你把數(shù)據(jù)導入效率提升10倍以上
    2025-12-12
  • 詳解mysql數(shù)據(jù)庫增刪改操作

    詳解mysql數(shù)據(jù)庫增刪改操作

    這篇文章主要介紹了mysql數(shù)據(jù)庫增刪改操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Mysql CPU占用高的問題解決方法小結(jié)

    Mysql CPU占用高的問題解決方法小結(jié)

    最近發(fā)現(xiàn)php網(wǎng)站發(fā)布信息比較慢,而且同網(wǎng)站目錄下的asp經(jīng)常登錄后立即就重新登錄,立即考慮到服務器資源占用問題,所以進服務器看到原來mysql占用率較高 25-60%左右,偶爾能跑到100%,所有導致上述問題的發(fā)生
    2012-06-06
  • MySQL事務與鎖實例教程詳解

    MySQL事務與鎖實例教程詳解

    事務是指滿足ACID特性的的一組操作,可以通過Commit提交事務,也可以也可以通過Rollback進行回滾。會存在中間態(tài)和一致性狀態(tài),也是真正在數(shù)據(jù)庫表中存在的狀態(tài)
    2022-11-11
  • mysql間隙鎖的具體使用

    mysql間隙鎖的具體使用

    MySQL中有多種鎖類型,本文主要介紹了mysql間隙鎖的具體使用,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2024-02-02
  • MySQL校對規(guī)則(COLLATION)的具體使用

    MySQL校對規(guī)則(COLLATION)的具體使用

    本文主要介紹了MySQL校對規(guī)則(COLLATION)的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08

最新評論

松滋市| 宣城市| 凯里市| 滨州市| 同德县| 嘉善县| 天等县| 娄底市| 揭阳市| 清水县| 梨树县| 手游| 兴国县| 恩平市| 许昌市| 南通市| 巴林左旗| 哈尔滨市| 尉氏县| 和平县| 常熟市| 阿合奇县| 炉霍县| 乐清市| 宣武区| 盐边县| 和龙市| 收藏| 清涧县| 永嘉县| 皋兰县| 长丰县| 呈贡县| 新河县| 北海市| 疏勒县| 利津县| 梁河县| 山阴县| 资溪县| 陆川县|