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

Spring Boot日志收集及鏈路追蹤實現示例

 更新時間:2022年12月14日 11:13:48   作者:失敗的面  
這篇文章主要為大家介紹了Spring Boot日志收集及鏈路追蹤實現示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

gitee鏈接

Spring Boot版本:2.3.4.RELEASE

最基本的日志功能及自定義日志

添加logback依賴:

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

在application配置文件中設置日志保存路徑:

server:
  port: 8888
# 日志保存路徑
logging:
  file:
    path: _logs/mylog-${server.port}.logs

關于logback的配置文件

logback-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--解決在項目目錄中生成LOG_PATH_IS_UNDEFINED文件-->
    <property name="LOG_PATH" value="${LOG_PATH:-${java.io.tmpdir:-/logs}}"/>
    <!-- 引入SpringBoot的默認配置文件defaults.xml -->
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <!-- 引入SpringBoot中內置的控制臺輸出配置文件console-appender.xml -->
    <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
    <!-- 引入自定義的文件輸出配置文件logback-spring-file-level.xml -->
    <include resource="logback-spring-file-level.xml"/>
    <!-- 設置root logger的級別為INFO,并將控制臺輸出和文件輸出中的appender都添加到root logger下 -->
    <root level="INFO">
        <!--沒有這行,控制臺將不會有輸出,完全由日志進行輸出-->
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="INFO_FILE"/>
        <appender-ref ref="WARN_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>
    <!-- jmx可以動態(tài)管理logback配置-->
    <jmxConfigurator/>
</configuration>

logback-spring-file.level.xml:

<?xml version="1.0" encoding="UTF-8"?>
<included>
    <!--INFO Level的日志-->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- %i用來標記分割日志的序號 -->
            <fileNamePattern>${LOG_PATH}.INFOLevel.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 單個日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB -->
            <!-- 經過試驗,maxHistory是指指定天數內,而不是多少天-->
            <maxFileSize>50MB</maxFileSize>
            <maxHistory>15</maxHistory>
            <totalSizeCap>50MB</totalSizeCap>
        </rollingPolicy>
        <!-- 配置日志的級別過濾器,只保留INFO Level的日志-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 格式化輸出-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"} %-5level -[%X{traceId}] - %msg%n</pattern>
        </encoder>
    </appender>
    <!--WARN Level的日志-->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- %i用來標記分割日志的序號 -->
            <fileNamePattern>${LOG_PATH}.WARNLevel.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 單個日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB -->
            <maxFileSize>50MB</maxFileSize>
            <maxHistory>15</maxHistory>
            <totalSizeCap>50MB</totalSizeCap>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!--過濾級別-->
            <level>WARN</level>
            <!--onMatch:符合過濾級別的日志。ACCEPT:立即處理-->
            <onMatch>ACCEPT</onMatch>
            <!--onMismatch:不符合過濾級別的日志。DENY:立即拋棄-->
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"} %-5level -[%X{traceId}] - %msg%n</pattern>
        </encoder>
    </appender>
    <!--ERROR Level的日志-->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- %i用來標記分割日志的序號 -->
            <fileNamePattern>${LOG_PATH}.ERRORLevel.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 單個日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB -->
            <maxFileSize>50MB</maxFileSize>
            <maxHistory>15</maxHistory>
            <totalSizeCap>50MB</totalSizeCap>
            <!--<cleanHistoryOnStart>true</cleanHistoryOnStart>-->
        </rollingPolicy>
        <!--對指定級別的日志進行過濾-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!--過濾級別-->
            <level>ERROR</level>
            <!--onMatch:符合過濾級別的日志。ACCEPT:立即處理-->
            <onMatch>ACCEPT</onMatch>
            <!--onMismatch:不符合過濾級別的日志。DENY:立即拋棄-->
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--日志輸出格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"} %-5level - [%X{traceId}] - %msg%n</pattern>
        </encoder>
    </appender>
    <!--自定義日志-->
    <appender name="CUSTOM_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- %i用來標記分割日志的序號 -->
            <fileNamePattern>${LOG_PATH}.MYLOGGERLevel.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 單個日志文件最大maxFileSizeMB, 保存maxHistory天的歷史日志, 所有日志文件最大totalSizeCapMB -->
            <!-- 經過試驗,maxHistory是指指定天數內,而不是多少天-->
            <maxFileSize>300MB</maxFileSize>
            <maxHistory>15</maxHistory>
            <totalSizeCap>300MB</totalSizeCap>
        </rollingPolicy>
        <!-- 配置日志的級別過濾器,只保留INFO Level的日志-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 格式化輸出-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"}\t%X{traceId}\t%msg%n</pattern>
        </encoder>
    </appender>
    <!--自定義日志日志不用綁定在root下,只記錄指定輸出-->
    <logger name="my_logger" additivity="false">
        <appender-ref ref= "CUSTOM_FILE"/>
    </logger>
</included>

配置文件里的注釋比較詳細,可以根據需要自行修改,配置里有一個“traceId”,這不是logback自帶的,是我為了實現日志追蹤而添加的,后面會說到。

寫接口來測試一下:

package com.cc.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
import java.util.logging.Logger;
@RestController
public class TestController {
    Logger LOGGER = Logger.getLogger(this.getClass().toString());
    Logger MyLogger = Logger.getLogger("my_logger");
    @GetMapping("/w")
    public String logWarning() {
        LOGGER.warning("這是一段 warning 日志:" + UUID.randomUUID().toString().replace("-", ""));
        return "輸出 warning 日志";
    }
    @GetMapping("/e")
    public String logError() {
        LOGGER.severe("這是一段 error 日志:" + UUID.randomUUID().toString().replace("-", ""));
        return "輸出 error 日志";
    }
    @GetMapping("/m")
    public String logMyLogger() {
        MyLogger.info("這是一段 自定義 日志:" + UUID.randomUUID().toString().replace("-", ""));
        return "輸出 自定義 日志";
    }
}

啟動項目,分別執(zhí)行測試接口,然后我們就可以在_logs文件夾內看到4個日志文件,分別是記錄啟動信息的INFO日志、記錄警告的WARN日志、記錄錯誤的ERROR日志以及自定義的MYLOGGER日志。

日志鏈路追蹤

我們給HTTP請求賦予一個traceId,這個traceId將貫穿整個請求,請求過程中所有的日志都會記錄traceId,由此達到快速定位問題和過濾無關日志的效果。

為了好看些,我們定義一個常量類:

package com.cc.config.logback;
/**
 * Logback常量定義
 * @author cc
 * @date 2021-07-12 10:41
 */
public interface LogbackConstant {
    String TRACT_ID = "traceId";
}

然后是logback過濾器:

package com.cc.config.logback;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
import java.util.UUID;
/**
 * 日志追蹤id
 * @author cc
 * @date 2021-07-12 10:41
 */
@Component
public class LogbackFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {}
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            MDC.put(LogbackConstant.TRACT_ID, UUID.randomUUID().toString().replace("-", ""));
            chain.doFilter(request, response);
        } finally {
            MDC.remove(LogbackConstant.TRACT_ID);
        }
    }
    @Override
    public void destroy() {}
}

我們用處理后的UUID作為traceId,現在再調用測試接口,可以看到日志中附帶的traceId。

EFK日志收集系統

EFK是指Elasticsearch、Filebeat、和Kibana,原本還有個logstash,但是logstash的使用沒有filebeat簡單,并且它的內容過濾功能并不是剛需,所以就不加上了,但是后面仍然會附帶logstash的簡要介紹。

先說明一下EKF的工作流程

  • Spring Boot應用的日志會保存在指定的路徑
  • filbeat會檢測到日志文件的變化,并將內容發(fā)送到elasticsearch

    如果使用logstash,則會將內容發(fā)送到logstash

    logstash將內容進行過濾分析以及格式轉換等操作,再發(fā)送給elasticsearch,這種處理會使日志數據在kibana上顯示的更加詳細。

  • 訪問kibana可視化界面,在kibana中操作或查看elasticseach的保存的日志數據

環(huán)境準備

因為我的EFK環(huán)境是搭建在虛擬機的docker上,本機是Windows,所以為了讓docker上的filebeat容器能檢測到我的日志文件變化,我有兩種方案:

  • 將項目部署成jar包在虛擬機的Linux上運行,并將日志保存路徑設置到指定位置
  • 本機和虛擬機建立共享文件夾

因為VMWare建立共享文件夾十分簡單,并且我也能在本地開發(fā)環(huán)境實時更新代碼,所以選擇了方案1。

容器創(chuàng)建

這里假設讀者對docker有一定的了解,畢竟關于docker的介紹篇幅不小,而且也與主題無關,就不在這里細說了。

# 創(chuàng)建一個網絡,用于容器間的通訊
docker network create mynetwork
docker run --name myes -p 9200:9200 -p 9300:9300 -itd --restart=always -v /etc/localtime:/etc/localtime -v /home/mycontainers/myes/data:/data --net mynetwork -e "discovery.type=single-node" -e "ES_JAVA_OPTS=-Xms256m -Xmx256m" elasticsearch:7.12.0
docker run --name myfilebeat -itd --restart=always -v /etc/localtime:/etc/localtime -v /mnt/hgfs/myshare/_logs:/data --net mynetwork -v /home/filebeat.yml:/usr/share/filebeat/filebeat.yml elastic/filebeat:7.12.0
docker run --name mykibana -p 5601:5601 -itd --restart=always -v /etc/localtime:/etc/localtime --net mynetwork -m 512m  --privileged=true kibana:7.12.0

上面filebeat的容器文件映射路徑要注意,映射到了我的共享文件夾,所以不一定和大家一樣,按需修改即可。

并且為了方便,我們直接映射了一個filebeat.yml配置文件到filebeat容器內,省的后面再進去修改了。

filebeat.yml:

filebeat.inputs:
- type: log
  enabled: true
  paths:
  - /data/*.log
output.elasticsearch:
  hosts: ['myes']
  index: "filebeat-%{+yyyy-MM-dd}"
setup.template.name: "filebeat"
setup.template.pattern: "filebeat-*"
processors:
  - drop_fields:
      fields: ["log","input","host","agent","ecs"]

配置文件說明:

filebeat.inputs:	// 輸入源
- type: log	// 標注這是日志類型
  enabled: true	// 啟用功能
  paths:	// 路徑
  - /data/*.log	// filebeat容器內的/data文件夾下,所有后綴為.log的文件
output.elasticsearch:	// 輸出位置:elasticsearch,后面簡稱es
  hosts: ['myes']	// es的鏈接,因為我們做了網段所以可以通過容器名進行通訊
  index: "filebeat-%{+yyyy-MM-dd}"	// 自定義es索引
setup.template.name: "filebeat"	// 配置了索引,就需要設置這兩項
setup.template.pattern: "filebeat-*" // 配置了索引,就需要設置這兩項
processors: // 處理器
  - drop_fields:	// 過濾或者叫移除指定字段,因為進入es的數據默認會帶上這些
      fields: ["log","input","host","agent","ecs"] 

讓kibana連接到elasticsearch

進入kibana容器中,修改配置文件并重啟:

docker exec -it mykibana bash

cd config/

vi kibana.yml

原內容:

server.name: kibana
server.host: "0"
elasticsearch.hosts: [ "http://elasticsearch:9200" ]
monitoring.ui.container.elasticsearch.enabled: true

修改成:

server.name: kibana
server.host: "0"
elasticsearch.hosts: [ "http://myes:9200" ]
monitoring.ui.container.elasticsearch.enabled: true

可以看出,如果es的容器名就是elasticsearch的話,就可以不用改。

測試容器有效性

elasticsearch:訪問 http://ip:9200 ,有json內容出現則成功

kibana:訪問 http://ip:5601 ,沒有報錯,出現可視化UI界面則成功,如果失敗,基本是連接問題,請確認配置文件內連接elasticsearch的內容是否正確,確認容器間是否在同一個網段可以進行通訊,調試時可以在容器內互相ping進行確認。

filebeat:等會進kibana可視化界面就能知道

測試效果

調用接口 localhost:8888/w,或者是e/m接口,以輸出日志內容到指定位置。此時filebeat已經能檢測到文件內容變更并推送到elasticsearch

  • 在指定的目錄可以看到輸出的日志文件,則說明日志文件保存成功。
  • 打開kibana可視化面板:IP:5061,點擊左上角的三橫線圖標,顯示菜單,找到Analytics-Discover,第一次進需要創(chuàng)建Index Patterns,因為我們在filebeat.yml中設置的索引是filebeat,所以這里也要用上,填寫了filebeat之后可以看到有匹配項,下一步,步驟2選擇時間過濾器,然后確定即可。此時已經可以看到logback->filebeat->elasticsearch的日志內容,然后借助kibana面板就能方便的進行數據檢索了。

至此,EFK入門級部署完成。

用Golang手擼一個輕量級日志收集工具

EFK使用方便,界面美觀,并且還支持分布式,可以說十分好用了,但是因為我的服務器內存沒有那么充裕,用EFK的話要消耗接近1G,所以我選擇了另一種方案:用Golang寫一個服務,結合Linux的grep指令,從日志文件中提取匹配的內容。這種方案好處是用Golang寫,內存占用很低,缺點是搜索效率低,但是對于我的小項目來說正合適。

附上Golang的代碼,其實原理很簡單,就是使用Gin框架啟動一個Web服務,然后調用shell腳本提取內容:

package main
import (
    "fmt"
    "os/exec"
    "github.com/gin-gonic/gin"
)
func main() {
    runServer()
}
func runServer() {
    r := gin.Default()
    r.GET("/log", func(c *gin.Context) {
        id := c.Query("id")
        result := runScript("./findLog.sh " + id)
        c.Header("Content-Type", "text/html; charset=utf-8")
        c.String(200, result)
    })
    r.Run(":18085")
}
func runScript(path string) string {
    cmd := exec.Command("/bin/bash", "-c", path)
    output, err := cmd.Output()
    if err != nil {
        fmt.Printf("Execute Shell:%s failed with error:%s", path, err.Error())
        return err.Error()
    }
    fmt.Printf("Execute Shell:%s finished with output:\n%s", path, string(output))
        return string(output)
}

findLog.sh:

cd /Users/chen/Desktop/mycontainers/mall-business/data/logs
id=$1
grep $id *.log% 

將這個Golang應用打包到指定平臺運行即可。

以上就是Spring Boot日志收集及鏈路追蹤實現示例的詳細內容,更多關于SpringBoot日志收集鏈路追蹤的資料請關注腳本之家其它相關文章!

相關文章

  • 詳解怎么用Java的super關鍵字

    詳解怎么用Java的super關鍵字

    今天帶大家學習Java中super關鍵字是怎么用的,文中有非常詳細的介紹,對正在學習的小伙伴們很有幫助,需要的朋友可以參考下
    2021-06-06
  • Spring?AOP核心功能示例代碼詳解

    Spring?AOP核心功能示例代碼詳解

    AOP面向切面編程,它是一種思想,它是對某一類事情的集中處理,而AOP是一種思想,而Spring?AOP是一個框架,提供了一種對AOP思想的實現,它們的關系和loC與DI類似,這篇文章主要介紹了Spring?AOP統一功能處理示例代碼,需要的朋友可以參考下
    2023-02-02
  • spring boot 實現Minio分片上傳的步驟

    spring boot 實現Minio分片上傳的步驟

    分片上傳,就是將所要上傳的文件,按照一定的大小,將整個文件分隔成多個數據塊來進行分別上傳,上傳完之后再由服務端對所有上傳的文件進行匯總整合成原始的文件,本文給大家介紹spring boot 實現Minio分片上傳的步驟,感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • Mybatis框架中Interceptor接口的使用說明

    Mybatis框架中Interceptor接口的使用說明

    這篇文章主要介紹了Mybatis框架中Interceptor接口的使用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 在SpringBoot中使用lombok的注意事項

    在SpringBoot中使用lombok的注意事項

    這篇文章主要介紹了在SpringBoot中使用lombok的注意事項,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java ThreadLocal的設計理念與作用

    Java ThreadLocal的設計理念與作用

    這篇文章主要介紹了Java ThreadLocal的設計理念與作用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • java實現停車場系統

    java實現停車場系統

    這篇文章主要為大家詳細介紹了java實現停車場系統,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • Java8新特性之類型注解_動力節(jié)點Java學院整理

    Java8新特性之類型注解_動力節(jié)點Java學院整理

    這篇文章主要介紹了Java8新特性之類型注解的相關資料,需要的朋友可以參考下
    2017-06-06
  • mybatis二級緩存默認未開啟源碼的問題

    mybatis二級緩存默認未開啟源碼的問題

    這篇文章主要介紹了mybatis二級緩存默認未開啟源碼的問題及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • SpringCloud降級規(guī)則使用介紹

    SpringCloud降級規(guī)則使用介紹

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

最新評論

乌恰县| 安龙县| 上栗县| 丹阳市| 安顺市| 清新县| 富源县| 长春市| 邓州市| 内黄县| 花莲县| 武义县| 宣化县| 凯里市| 成安县| 建宁县| 微博| 广平县| 昆明市| 金乡县| 遂川县| 抚顺县| 岳西县| 兴安县| 滁州市| 丽江市| 安宁市| 西乌珠穆沁旗| 霍邱县| 鄂州市| 成安县| 台湾省| 永城市| 从化市| 青河县| 洛浦县| 兴山县| 宜丰县| 当涂县| 靖边县| 四平市|