激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 微服務分布式架構實現日志鏈路跟蹤的方法

微服務分布式架構實現日志鏈路跟蹤的方法

2021-11-26 13:02碼農架構 Java教程

在現有的系統中,由于大量的其他用戶/其他線程的日志也一起輸出穿行其中導致很難篩選出指定請求的全部相關日志。那我們如何來處理呢?帶著這個問題一起通過本文學習下吧

Logback 背景

Logback是由log4j創始人設計的另一個開源日志組件,官方網站:http://logback.qos.ch。它當前分為下面下個模塊:

  • logback-core:其它兩個模塊的基礎模塊
  • logback-classic:它是log4j的一個改良版本,同時它完整實現了slf4j API使你可以很方便地更換成其它日志系統如log4j或JDK14 Logging
  • logback-access:訪問模塊與Servlet容器集成提供通過Http來訪問日志的功能

普通debug日志

微服務分布式架構實現日志鏈路跟蹤的方法

SQL執行日志

微服務分布式架構實現日志鏈路跟蹤的方法

Logback 配置案例

微服務分布式架構實現日志鏈路跟蹤的方法

日志級別排序為:TRACE < DEBUG < INFO < WARN < ERROR

  • %d:表示日期
  • %n:換行
  • %thread:表示線程名
  • %level:日志級別
  • %msg:日志消息
  • %file:表示文件名
  • %class:表示文件名
  • %logger:Java類名(含包名,這里設定了36位,若超過36位,包名會精簡為類似a.b.c.JavaBean)
  • %line:Java類的行號

微服務分布式架構實現日志鏈路跟蹤的方法

注意:

%-4relative %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread][%X{TRACE_ID}] %-5level %logger{100}.%M\(%line\) - %msg%n

在logback中,%relative表示自應用程序啟動以來打印相對時間戳(以毫秒為單位). %-4只是元素的對齊方式.

案例

3452487 2021-08-03 15:19:36.940 [thread-monitor-daemon][] WARN  com.xxxx.common.util.MonitorLogger.warn(27) - 發現超時線程notify-replay-consumer...

微服務分布式架構實現日志鏈路跟蹤的方法

由于案例中是守護線程thread-monitor-daemon,所以不記錄鏈路ID。

對在系統設計的時候對于線程的命名規范也是有約束的

微服務分布式架構實現日志鏈路跟蹤的方法


這里就不做詳細展開后續有機會會分享。
回歸正題比如下面的例子中記錄了請求的鏈路ID

19006989 2021-08-04 22:35:25.776 [http-nio-0.0.0.0-8010-exec-10][1fc8pebmgwukw863w2p342rp2936a3r157w0:0:] INFO  com.xxx.framework.eureka.core.listener.EurekaStateChangeListener.listen(58) - 服務實例[XX-PAAS]注冊成功,當前服務器已注冊服務實例數量[3]

微服務分布式架構實現日志鏈路跟蹤的方法

對于上圖中顯示的系統啟動時間、當前時間、當前線程、對應路徑按照logback官方配置就可以逐步完善對于的日志信息,但是對于鏈路ID的生成寫入就需要特殊處理。

鏈路ID設計

對于鏈路追蹤設計我個人比較喜歡兩種方案

第一種

微服務分布式架構實現日志鏈路跟蹤的方法

在每一次請求中鏈路編號(traceId)、單元編號(spanId)都是通過HttpHeader的方式進行傳遞,日志的起始位置會主動生成traceId、spanId,而起始位置的Parent SpanId則是不存在的,值為null。

這樣每次通過restTemplate、Openfeign的形式訪問其他服務的接口時,就會攜帶起始位置生成的traceId、spanId到下一個服務單元。

 第二種

微服務分布式架構實現日志鏈路跟蹤的方法

在每一次請求中鏈路編號(traceId),沒經過一次微服務對于深度(Deep)加1

public static class ThreadTraceListener implements ThreadListener {
    @Override
    public void onThreadBegin(HttpServletRequest request) {
      String traceToken = ThreadLocalUtil.getTranVar(TRACE_ID);
      String fromServer = ThreadLocalUtil.getTranVar(FROM_SERVER);
      int deep;
      String traceId;
      if (StringUtils.isBlank(traceToken)) {
        traceId = IDGenerator.generateID();
        deep = 0;
        traceToken = StringHelper.join(traceId, ":0");
      } else {
        int index = traceToken.lastIndexOf(':');
        traceId = traceToken.substring(0, index);
        deep = Integer.valueOf(traceToken.substring(index + 1));
      }
      ThreadLocalUtil.setLocalVar(TRACE_ID, traceId);
      ThreadLocalUtil.setLocalVar(TRACE_DEEP, deep);
      ThreadLocalUtil.setTranVar(TRACE_ID, StringHelper.join(traceId, ":", deep + 1));
      ThreadLocalUtil.setLocalVar(FROM_SERVER, fromServer);
      ThreadLocalUtil.setTranVar(FROM_SERVER, getCurrentServer());
      MDC.put(TRACE_ID, StringHelper.join(traceToken, ":", fromServer));
    }

    @Override
    public void onThreadEnd(HttpServletRequest request) {
      MDC.remove(TRACE_ID);
    }
  }

針對請求攔截

protected void doFilterInternal(HttpServletRequest request,
      HttpServletResponse response,
      FilterChain chain) throws ServletException, IOException {
    long startTime = System.currentTimeMillis();
    // 從Header中裝載傳遞過來的變量
    Map<String, Object> tranVar = new HashMap<String, Object>();
    Enumeration<String> headers = request.getHeaderNames();
    while (headers.hasMoreElements()) {
      String key = headers.nextElement();
      if (!StringUtils.isEmpty(key)
          && key.startsWith(ThreadLocalUtil.TRAN_PREFIX)) {
        tranVar.put(key.substring(ThreadLocalUtil.TRAN_PREFIX.length()),
            request.getHeader(key));
      }
    }
    ThreadLocalHolder.begin(tranVar, request);
    try {
      if (isGateway) {
        response.addHeader("X-TRACE-ID", TraceUtil.getTraceId());
      }
      // 檢查RPC調用深度
      checkRpcDeep(request, response);
      // 業務處理
      chain.doFilter(request, response);
      // 記錄RPC調用次數
      logRpcCount(request, response);
    } catch (Throwable ex) {
      // 錯誤處理
      Response<?> result = ExceptionUtil.toResponse(ex);
      Determine determine = ExceptionUtil.determineType(ex);
      ExceptionUtil.doLog(result, determine.getStatus(), ex);
      response.setStatus(determine.getStatus().value());
      response.setCharacterEncoding("UTF-8");
      response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
      response.getWriter().write(JsonUtil.toJsonString(result));
    } finally {
      try {
        doMonitor(request, response, startTime);
        if (TraceUtil.isTraceLoggerOn()) {
          log.warn(StringHelper.join(
              "TRACE-HTTP-", request.getMethod(),
              " URI:", request.getRequestURI(),
              ", dt:", System.currentTimeMillis() - startTime,
              ", rpc:", TraceUtil.getRpcCount(),
              ", status:", response.getStatus()));
        } else if (log.isTraceEnabled()) {
          log.trace(StringHelper.join(request.getMethod(),
              " URI:", request.getRequestURI(),
              ", dt:", System.currentTimeMillis() - startTime,
              ", rpc:", TraceUtil.getRpcCount(),
              ", status:", response.getStatus()));
        }
      } finally {
        ThreadLocalHolder.end(request);
      }
    }
}

到此這篇關于微服務分布式架構實現日志鏈路跟蹤的方法的文章就介紹到這了,更多相關微服務分布式架構日志鏈路跟蹤內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://mp.weixin.qq.com/s/s_dVunSq9bkJGeRVN9qRaA

延伸 · 閱讀

精彩推薦
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 国产88久久久国产精品免费二区 | 国产精品资源手机在线播放 | 亚洲第一色婷婷 | 羞羞网站 | 国产精品久久久久久久久久东京 | 黄污在线观看 | 中国免费一级毛片 | 国产精品一区久久久久 | 色婷婷综合久久久中字幕精品久久 | 九九热精品在线视频 | 日韩视频高清 | 日本中文不卡视频 | 国产一级毛片高清视频完整版 | 最新毛片在线观看 | 亚洲九草| 欧美三级欧美成人高清www | 嫩呦国产一区二区三区av | 91精品国产91久久久久久丝袜 | 精品国产乱码久久久久久预案 | 中文字幕www. | 欧美在线观看视频网站 | 视频一区二区精品 | h视频在线观看免费 | 在线播放91 | 久久精品欧美视频 | 国产69精品久久99不卡免费版 | 久久精精品| 免费观看一区二区三区视频 | 精品一区二区三区电影 | 污视频在线免费播放 | 中文字幕亚洲情99在线 | 亚洲网站在线播放 | 国产精品久久久久久久久久久久午夜 | 特级a欧美做爰片毛片 | 91久久另类重口变态 | 国产一区二区精品91 | 亚洲天堂岛国片 | 精品一区二区电影 | 国产亚洲精品久久久久久久久久 | 久久久久一区二区三区四区五区 | 2017亚洲男人天堂 |