SpringBoot教程(三十二) | SpringBoot集成Skywalking鏈路跟蹤
- 一、Skywalking是什么?
- 二、Skywalking與JDK版本的對應關系
- 三、Skywalking下載
- 四、Skywalking 數據存儲
- 五、Skywalking 的啟動
- 六、部署探針
-
- 前提: Agents 8.9.0 放入 項目工程
- 方式一:IDEA 部署探針
- 方式二:Java 命令行啟動方式
- 方式三:編寫sh腳本啟動(linux環境)
- 七、Springboot 的啟動
-
- IDEA 部署探針方式啟動
- Skywalking 進行日志配置
- 實現入參、返參都可查看
-
- 方式一:通過 Agent 配置實現 (有缺點)
- 方式二:通過 trace 和 Filter 實現
- 方式三:通過 trace 和 Aop 去實現
一、Skywalking是什么?
SkyWalking是一個開源的、用于觀測分布式系統(特別是微服務、云原生和容器化應用)的平臺。
它提供了對分布式系統的追蹤、監控和診斷能力。
二、Skywalking與JDK版本的對應關系
SkyWalking 8.x版本要求Java版本至少為8(即JDK 1.8),
SkyWalking 9.x版本則要求Java版本至少為11(即JDK 11)
所以選擇的時候需要注意一下JDK版本。
三、Skywalking下載
Skywalking 官網下載地址 https://skywalking.apache.org/downloads/
-
其他的版本的 APM 地址
https://archive.apache.org/dist/skywalking/ -
其他的java 版本的 Agents 地址
https://archive.apache.org/dist/skywalking/java-agent/
注意點:
7.x及以下版本 APM 包里面有包括 Agents,但是8.x的就發現被分開了,所以8.x的及以上的 就需要 Agents 也得下載
目前該文選擇 下載 APM 8.9.1 和 Agents 8.9.0 后解壓
四、Skywalking 數據存儲
Skywalking 存在多種數據存儲
- h2(默認的存儲方式,重啟后數據會丟失)
- Elasticsearch (最常用的數據存儲方式)
- MySQL
- TiDB
- …
相關文件OAP 配置文件(config/application.yml)
我只截取了關于設置存儲方式的部分
storage:selector: ${SW_STORAGE:h2}elasticsearch:namespace: ${SW_NAMESPACE:""}clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:"http"}connectTimeout: ${SW_STORAGE_ES_CONNECT_TIMEOUT:500}socketTimeout: ${SW_STORAGE_ES_SOCKET_TIMEOUT:30000}numHttpClientThread: ${SW_STORAGE_ES_NUM_HTTP_CLIENT_THREAD:0}user: ${SW_ES_USER:""}password: ${SW_ES_PASSWORD:""}trustStorePath: ${SW_STORAGE_ES_SSL_JKS_PATH:""}trustStorePass: ${SW_STORAGE_ES_SSL_JKS_PASS:""}secretsManagementFile: ${SW_ES_SECRETS_MANAGEMENT_FILE:""} # Secrets management file in the properties format includes the username, password, which are managed by 3rd party tool.dayStep: ${SW_STORAGE_DAY_STEP:1} # Represent the number of days in the one minute/hour/day index.indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:1} # Shard number of new indexesindexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:1} # Replicas number of new indexes# Super data set has been defined in the codes, such as trace segments.The following 3 config would be improve es performance when storage super size data in es.superDatasetDayStep: ${SW_SUPERDATASET_STORAGE_DAY_STEP:-1} # Represent the number of days in the super size dataset record index, the default value is the same as dayStep when the value is less than 0superDatasetIndexShardsFactor: ${SW_STORAGE_ES_SUPER_DATASET_INDEX_SHARDS_FACTOR:5} # This factor provides more shards for the super data set, shards number = indexShardsNumber * superDatasetIndexShardsFactor. Also, this factor effects Zipkin and Jaeger traces.superDatasetIndexReplicasNumber: ${SW_STORAGE_ES_SUPER_DATASET_INDEX_REPLICAS_NUMBER:0} # Represent the replicas number in the super size dataset record index, the default value is 0.indexTemplateOrder: ${SW_STORAGE_ES_INDEX_TEMPLATE_ORDER:0} # the order of index templatebulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:5000} # Execute the async bulk record data every ${SW_STORAGE_ES_BULK_ACTIONS} requests# flush the bulk every 10 seconds whatever the number of requests# INT(flushInterval * 2/3) would be used for index refresh period.flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:15}concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2} # the number of concurrent requestsresultWindowMaxSize: ${SW_STORAGE_ES_QUERY_MAX_WINDOW_SIZE:10000}metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:5000}segmentQueryMaxSize: ${SW_STORAGE_ES_QUERY_SEGMENT_SIZE:200}profileTaskQueryMaxSize: ${SW_STORAGE_ES_QUERY_PROFILE_TASK_SIZE:200}oapAnalyzer: ${SW_STORAGE_ES_OAP_ANALYZER:"{"analyzer":{"oap_analyzer":{"type":"stop"}}}"} # the oap analyzer.oapLogAnalyzer: ${SW_STORAGE_ES_OAP_LOG_ANALYZER:"{"analyzer":{"oap_log_analyzer":{"type":"standard"}}}"} # the oap log analyzer. It could be customized by the ES analyzer configuration to support more language log formats, such as Chinese log, Japanese log and etc.advanced: ${SW_STORAGE_ES_ADVANCED:""}h2:driver: ${SW_STORAGE_H2_DRIVER:org.h2.jdbcx.JdbcDataSource}url: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db;DB_CLOSE_DELAY=-1}user: ${SW_STORAGE_H2_USER:sa}metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}maxSizeOfArrayColumn: ${SW_STORAGE_MAX_SIZE_OF_ARRAY_COLUMN:20}numOfSearchableValuesPerTag: ${SW_STORAGE_NUM_OF_SEARCHABLE_VALUES_PER_TAG:2}maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:100}asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:1}mysql:properties:jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest?rewriteBatchedStatements=true"}dataSource.user: ${SW_DATA_SOURCE_USER:root}dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root@1234}dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}dataSource.prepStmtCacheSize: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_SIZE:250}dataSource.prepStmtCacheSqlLimit: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_LIMIT:2048}dataSource.useServerPrepStmts: ${SW_DATA_SOURCE_USE_SERVER_PREP_STMTS:true}metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}maxSizeOfArrayColumn: ${SW_STORAGE_MAX_SIZE_OF_ARRAY_COLUMN:20}numOfSearchableValuesPerTag: ${SW_STORAGE_NUM_OF_SEARCHABLE_VALUES_PER_TAG:2}maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}tidb:properties:jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:4000/tidbswtest?rewriteBatchedStatements=true"}dataSource.user: ${SW_DATA_SOURCE_USER:root}dataSource.password: ${SW_DATA_SOURCE_PASSWORD:""}dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}dataSource.prepStmtCacheSize: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_SIZE:250}dataSource.prepStmtCacheSqlLimit: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_LIMIT:2048}dataSource.useServerPrepStmts: ${SW_DATA_SOURCE_USE_SERVER_PREP_STMTS:true}dataSource.useAffectedRows: ${SW_DATA_SOURCE_USE_AFFECTED_ROWS:true}metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}maxSizeOfArrayColumn: ${SW_STORAGE_MAX_SIZE_OF_ARRAY_COLUMN:20}numOfSearchableValuesPerTag: ${SW_STORAGE_NUM_OF_SEARCHABLE_VALUES_PER_TAG:2}maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}influxdb:# InfluxDB configurationurl: ${SW_STORAGE_INFLUXDB_URL:http://localhost:8086}user: ${SW_STORAGE_INFLUXDB_USER:root}password: ${SW_STORAGE_INFLUXDB_PASSWORD:}database: ${SW_STORAGE_INFLUXDB_DATABASE:skywalking}actions: ${SW_STORAGE_INFLUXDB_ACTIONS:1000} # the number of actions to collectduration: ${SW_STORAGE_INFLUXDB_DURATION:1000} # the time to wait at most (milliseconds)batchEnabled: ${SW_STORAGE_INFLUXDB_BATCH_ENABLED:true}fetchTaskLogMaxSize: ${SW_STORAGE_INFLUXDB_FETCH_TASK_LOG_MAX_SIZE:5000} # the max number of fetch task log in a requestconnectionResponseFormat: ${SW_STORAGE_INFLUXDB_CONNECTION_RESPONSE_FORMAT:MSGPACK} # the response format of connection to influxDB, cannot be anything but MSGPACK or JSON.postgresql:properties:jdbcUrl: ${SW_JDBC_URL:"jdbc:postgresql://localhost:5432/skywalking"}dataSource.user: ${SW_DATA_SOURCE_USER:postgres}dataSource.password: ${SW_DATA_SOURCE_PASSWORD:123456}dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}dataSource.prepStmtCacheSize: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_SIZE:250}dataSource.prepStmtCacheSqlLimit: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_LIMIT:2048}dataSource.useServerPrepStmts: ${SW_DATA_SOURCE_USE_SERVER_PREP_STMTS:true}metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}maxSizeOfArrayColumn: ${SW_STORAGE_MAX_SIZE_OF_ARRAY_COLUMN:20}numOfSearchableValuesPerTag: ${SW_STORAGE_NUM_OF_SEARCHABLE_VALUES_PER_TAG:2}maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}zipkin-elasticsearch:namespace: ${SW_NAMESPACE:""}clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:"http"}trustStorePath: ${SW_STORAGE_ES_SSL_JKS_PATH:""}trustStorePass: ${SW_STORAGE_ES_SSL_JKS_PASS:""}dayStep: ${SW_STORAGE_DAY_STEP:1} # Represent the number of days in the one minute/hour/day index.indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:1} # Shard number of new indexesindexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:1} # Replicas number of new indexes# Super data set has been defined in the codes, such as trace segments.The following 3 config would be improve es performance when storage super size data in es.superDatasetDayStep: ${SW_SUPERDATASET_STORAGE_DAY_STEP:-1} # Represent the number of days in the super size dataset record index, the default value is the same as dayStep when the value is less than 0superDatasetIndexShardsFactor: ${SW_STORAGE_ES_SUPER_DATASET_INDEX_SHARDS_FACTOR:5} # This factor provides more shards for the super data set, shards number = indexShardsNumber * superDatasetIndexShardsFactor. Also, this factor effects Zipkin and Jaeger traces.superDatasetIndexReplicasNumber: ${SW_STORAGE_ES_SUPER_DATASET_INDEX_REPLICAS_NUMBER:0} # Represent the replicas number in the super size dataset record index, the default value is 0.user: ${SW_ES_USER:""}password: ${SW_ES_PASSWORD:""}secretsManagementFile: ${SW_ES_SECRETS_MANAGEMENT_FILE:""} # Secrets management file in the properties format includes the username, password, which are managed by 3rd party tool.bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:5000} # Execute the async bulk record data every ${SW_STORAGE_ES_BULK_ACTIONS} requests# flush the bulk every 10 seconds whatever the number of requests# INT(flushInterval * 2/3) would be used for index refresh period.flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:15}concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2} # the number of concurrent requestsresultWindowMaxSize: ${SW_STORAGE_ES_QUERY_MAX_WINDOW_SIZE:10000}metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:5000}segmentQueryMaxSize: ${SW_STORAGE_ES_QUERY_SEGMENT_SIZE:200}profileTaskQueryMaxSize: ${SW_STORAGE_ES_QUERY_PROFILE_TASK_SIZE:200}oapAnalyzer: ${SW_STORAGE_ES_OAP_ANALYZER:"{"analyzer":{"oap_analyzer":{"type":"stop"}}}"} # the oap analyzer.oapLogAnalyzer: ${SW_STORAGE_ES_OAP_LOG_ANALYZER:"{"analyzer":{"oap_log_analyzer":{"type":"standard"}}}"} # the oap log analyzer. It could be customized by the ES analyzer configuration to support more language log formats, such as Chinese log, Japanese log and etc.advanced: ${SW_STORAGE_ES_ADVANCED:""}iotdb:host: ${SW_STORAGE_IOTDB_HOST:127.0.0.1}rpcPort: ${SW_STORAGE_IOTDB_RPC_PORT:6667}username: ${SW_STORAGE_IOTDB_USERNAME:root}password: ${SW_STORAGE_IOTDB_PASSWORD:root}storageGroup: ${SW_STORAGE_IOTDB_STORAGE_GROUP:root.skywalking}sessionPoolSize: ${SW_STORAGE_IOTDB_SESSIONPOOL_SIZE:16}fetchTaskLogMaxSize: ${SW_STORAGE_IOTDB_FETCH_TASK_LOG_MAX_SIZE:1000} # the max number of fetch task log in a request
五、Skywalking 的啟動
進入 D:apache-skywalking-apm-8.9.1apache-skywalking-apm-binin ,雙擊運行 startup.bat(用管理員方式啟動),會開啟兩個命令行窗口。
- (1)Skywalking-Collector:追蹤信息收集器,通過 gRPC/Http 收集客戶端的采集信息 。Http默認端口 12800,gRPC默認端口 11800。(如需要修改,可前往 apache-skywalking-apm-binconfigapplicaiton.yml 進行修改)
- (2)Skywalking-Webapp:管理平臺頁面 默認端口 8080 (如需要修改,可前往 apache-skywalking-apm-binwebappwebapp.yml 進行修改)
啟動圖如下:
接著瀏覽器Skywalking訪問:http://localhost:8080/
這個右邊有個自動刷新的按鈕,一定要啟動起來
不然到時候,springboot工程啟動以后,你以為沒有連接成功(F5刷新頁面是沒有用的)
六、部署探針
前提: Agents 8.9.0 放入 項目工程
也不說放其他位置不好,不過放到項目里面更好一點,后面你就能感受到便利了
方式一:IDEA 部署探針
修改啟動類的 VM options(虛擬機選項)配置
配置的jvm參數如下:
-javaagent:D:ideaObjectreactBootspringboot-fullsrcmainskywalking-agentskywalking-agent.jar
-Dskywalking.agent.service_name=woqu-ndy
-Dskywalking.collector.backend_service=127.0.0.1:11800
- javaagent: 表示 skywalking‐agent.jar的本地磁盤的路徑
(我這邊是放到項目里面了)
-Dskywalking.agent.service_name:表示在skywalking上顯示的服務名
-Dskywalking.collector.backend_service:表示skywalking的collector服務的IP及端口- 注意:-Dskywalking.collector.backend_service 可以指定遠程地址, 但是 javaagent 必須綁定你本機物理路徑的 skywalking-agent.jar
方式二:Java 命令行啟動方式
java -javaagent:D:ideaObjectreactBootspringboot-fullsrcmainskywalking-agentskywalking-agent.jar=-Dskywalking.agent.service_name=service-myapp,-Dskywalking.collector.backend_service=localhost:11800 -jar service-myapp.jar
方式三:編寫sh腳本啟動(linux環境)
#!/bin/bash # 設置 SkyWalking Agent 的路徑
AGENT_PATH="/home/yourusername/Desktop/apache-skywalking-apm-6.6.0/apache-skywalking-apm-bin/agent" # 設置 Java 應用的 JAR 文件路徑
JAR_PATH="/path/to/your/service-myapp.jar" # 設置 SkyWalking 服務名稱和 Collector 后端服務地址
SERVICE_NAME="service-myapp"
COLLECTOR_BACKEND_SERVICE="localhost:11800" # 構造 Java Agent 參數
JAVA_AGENT="-javaagent:$AGENT_PATH/skywalking-agent.jar -Dskywalking.agent.service_name=$SERVICE_NAME -Dskywalking.collector.backend_service=$COLLECTOR_BACKEND_SERVICE" # 啟動 Java 應用
java $JAVA_AGENT -jar $JAR_PATH
七、Springboot 的啟動
IDEA 部署探針方式啟動
啟動后,控制臺日志輸出開頭出現了以下的記錄,就表示連接上Skywalking了
再看 Skywalking(http://localhost:8080/) 頁面那邊,你就會發現有個這個圖(表示連接上了)
我們再請求一下 Controller 的接口,就會發現捕獲了相關接口記錄
(但是目前,還是沒有接口具體詳細的日志入參或者出參的)
Skywalking 進行日志配置
為log日志增加 skywalking的 traceId(追蹤ID)。便于排查
首先引入maven依賴
<!-- SkyWalking 的日志工具包 -->
<dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-logback-1.x</artifactId><version>9.0.0</version>
</dependency>
接著在 resources文件夾下創建 logback-spring.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"><!--定義日志文件的存儲地址 勿在 LogBack 的配置中使用相對路徑--><property name="LOG_HOME" value="D:/logs/" ></property><!-- 彩色日志 --><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /><!--控制臺日志, 控制臺輸出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout"><!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日志消息,%n是換行符--><pattern>%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} [%X{tid}] %clr([%-10.10thread]){faint} %clr(%-5level) %clr(%-50.50logger{50}:%-3L){cyan} %clr(-){faint} %msg%n</pattern></layout></encoder></appender><!--文件日志, 按照每天生成日志文件 (只能是 由 Logger 或者 LoggerFactory 記錄的日志消息哦)--><!--以下關于 日志文件的pattern 需要去掉顏色,防止出現 ANSI轉義序列--><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--日志文件輸出的文件名--><FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/pro.log</FileNamePattern><!--日志文件保留天數--><MaxHistory>30</MaxHistory></rollingPolicy><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout"><!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日志消息,%n是換行符--><!-- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%-10.10thread] %-5level %-50.50logger{50}:%-3L - %msg%n</pattern></layout></encoder><!--日志文件最大的大小--><triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"><MaxFileSize>10MB</MaxFileSize></triggeringPolicy></appender><!--skywalking grpc 日志收集--><appender name="grpc" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout"><Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern></layout></encoder></appender><!-- 日志輸出級別 --><root level="INFO"><appender-ref ref="STDOUT" ></appender-ref><appender-ref ref="FILE" ></appender-ref><appender-ref ref="grpc"/></root>
</configuration>
請求接口就可以發現TID的輸出
(在這里是882c67dc859046c398fbfc5725df9de0.109.17288962842340001)
然后把它放到 追蹤 欄目的追蹤id ,可以查到記錄
然后把它放到 日志 欄目的追蹤id ,可以查到記錄
實現入參、返參都可查看
方式一:通過 Agent 配置實現 (有缺點)
首先,你需要確認SkyWalking的Agent配置。
SkyWalking的Agent在啟動時會讀取配置文件,通常是agent.config。
默認情況下,請求參數的采集是關閉的,你需要手動開啟。
具體步驟如下:
在你的SkyWalking Agent配置文件agent.config中,找到plugin部分,確保以下配置項設置為true:
plugin.tomcat.collect_http_params=${SW_PLUGIN_TOMCAT_COLLECT_HTTP_PARAMS:true}
plugin.springmvc.collect_http_params=${SW_PLUGIN_SPRINGMVC_COLLECT_HTTP_PARAMS:true}
plugin.httpclient.collect_http_params=${SW_PLUGIN_HTTPCLIENT_COLLECT_HTTP_PARAMS:true}
缺點:可是以上設置,只能開啟get請求的入參采集,post無法獲取到,這個方式不怎么好
方式二:通過 trace 和 Filter 實現
一、引入追蹤工具包
<!-- SkyWalking 追蹤工具包 -->
<dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-trace</artifactId><version>9.0.0</version>
</dependency>
二、使用 HttpFilter 和 ContentCachingRequestWrapper
知識小貼士:為什么不用HttpServletRequest?
如果直接把HttpServletRequest中的InputStream讀取后輸出日志,會導致后續業務邏輯讀取不到InputStream中的內容,因為流只能讀取一次。
package com.example.springbootfull.quartztest.Filter;import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;@Slf4j
@Component
public class ApmHttpInfo extends HttpFilter {//被忽略的頭部信息 private static final Set<String> IGNORED_HEADERS;static {Set<String> ignoredHeaders = new HashSet<>();ignoredHeaders.addAll(java.util.Arrays.asList("Content-Type","User-Agent","Accept","Cache-Control","Postman-Token","Host","Accept-Encoding","Connection","Content-Length").stream().map(String::toUpperCase).collect(Collectors.toList()));IGNORED_HEADERS = ignoredHeaders;}@Overridepublic void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);try {filterChain.doFilter(requestWrapper, responseWrapper);} finally {try {//構造請求信息: 比如 curl -X GET http://localhost:18080/getPerson?id=1 -H 'token: me-token' -d '{ "name": "hello" }'//構造請求的方法&URL&參數StringBuilder sb = new StringBuilder("curl").append(" -X ").append(request.getMethod()).append(" ").append(request.getRequestURL().toString());if (StringUtils.hasLength(request.getQueryString())) {sb.append("?").append(request.getQueryString());}//構造headerEnumeration<String> headerNames = request.getHeaderNames();while (headerNames.hasMoreElements()) {String headerName = headerNames.nextElement();if (!IGNORED_HEADERS.contains(headerName.toUpperCase())) {sb.append(" -H '").append(headerName).append(": ").append(request.getHeader(headerName)).append("'");}}//獲取bodyString body = new String(requestWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);if (StringUtils.hasLength(body)) {sb.append(" -d '").append(body).append("'");}//輸出到inputActiveSpan.tag("input", sb.toString());//獲取返回值bodyString responseBody = new String(responseWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);//輸出到outputActiveSpan.tag("output", responseBody);} catch (Exception e) {log.warn("fail to build http log", e);} finally {//這一行必須添加,否則就一直不返回responseWrapper.copyBodyToResponse();}}}
}
效果如下(get請求):
效果如下(post請求):
方式三:通過 trace 和 Aop 去實現
在此就不細說了,這個也是一種方案
參考文章
【1】skywalking環境搭建(windows)
【2】windows下安裝skywalking 9.2
【3】skywalking9.1結合logback配置日志收集
【4】SpringBoot集成Skywalking日志收集
【5】skywalking展示http請求和響應