SpringCloud集成Skywalking链路追踪和日志收集
1. 下载Agents
https://archive.apache.org/dist/skywalking/java-agent/9.0.0/apache-skywalking-java-agent-9.0.0.tgz
2. 上传到服务器解压
在Spring Cloud项目中,每部署一个服务时,就拷贝一份skywalking的agent文件到该服务器上并解压。不管是部署注册中心、网关、还是其它服务,都这么做,无论一个服务器部署多少个微服务,有一份就行。
3. 集成链路追踪
3.1. 修改Spring Boot启动参数
springcloud/springboot 一般是通过 java -jar xxx.jar 进行启动。我们只需要在其中加上 -javaagent 参数即可,格式如下面
java -javaagent:上一步解压目录/agent/skywalking-agent.jar=agent.service_name=自定义服务名,collector.backend_service=服务ip:11800 -jar xxx.jar
说明:
-javaagent后是skywalking-agent.jar的绝对路径,在apache-skywalking-java-agent-9.0.0.tgz解压后的包中
-Dskywalking.agent.service_name是服务的名称,自定义,一般用spring.application.name
-Dskywalking.collector.backend_service是指skywalking oap服务器的ip和端口号
示例:
java -javaagent:F:\project\git\agent\skywalking-agent\skywalking-agent.jar -Dskywalking.agent.service_name=skywalking_demo_test -Dskywalking.collector.backend_service=192.168.110.155:11800 -jar skywaking_demo.jar
启动springboot项目,然后查看控制台或文件中的日志
bash start.sh
3.2. Gateway集成Skywalking链路追踪
其他服务已经完成链路追踪功能,只有gateway服务需要特殊配置一下。
问题:Spring Cloud Gateway是基于WebFlux实现的,Skywalking默认不支持,在链路上是不展示gateway组件的
链路图如下图所示
解决方案如下
把agent/optional-plugins下面的两个插件
apm-spring-cloud-gateway-x.x-plugin-x.0.0.jar、apm-spring-webflux-x.x-plugin-x.0.0.jar
根据你的Spring Cloud Gateway版本选择合适的版本拷贝到agent/plugin目录下
,比如我的gateway版本为3.1.4,则拷贝apm-spring-cloud-gateway-3.x-plugin-9.0.0.jar、apm-spring-webflux-5.x-plugin-9.0.0.jar到plugin目录下
然后重启gateway服务
重新发起请求,链路图如下
4. 配置日志收集
需要先完成第三步 配置链路追踪,不然无法打印日志。
4.1. 普通SpingBoot项目配置
这里的普通springboot项目是指除gateway服务以外的其他服务
参考:SpringBoot集成Skywalking日志收集-CSDN博客
4.2. Spring Cloud Gateway日志收集配置
目前Spring Cloud Gateway服务日志会丢失TraceId,现在的解决方案如下
4.2.1. 修改POM文件
日志更换为log4j2,引入skywalking相关的依赖包
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><artifactId>spring-boot-starter-logging</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions></dependency><!--引入log4j2依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency><dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-log4j-2.x</artifactId><version>9.0.0</version></dependency><!--apm 工具包--><dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-trace</artifactId><version>9.0.0</version></dependency>
4.2.2. 增加如下两个配置类
LogHooks.java
package com.szc.gateway.logconfig;import org.springframework.stereotype.Component;
import reactor.core.publisher.Operators;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;@Component
public class LogHooks {private static final String KEY = "logMdc";@PostConstruct@SuppressWarnings("unchecked")public void setHook() {reactor.core.publisher.Hooks.onEachOperator(KEY,Operators.lift((scannable, coreSubscriber) -> new MdcSubscriber(coreSubscriber)));}@PreDestroypublic void resetHook() {reactor.core.publisher.Hooks.resetOnEachOperator(KEY);}}
MdcSubscriber.java
package com.szc.gateway.logconfig;import org.reactivestreams.Subscription;
import org.slf4j.MDC;
import org.springframework.cglib.beans.BeanMap;
import reactor.core.CoreSubscriber;
import reactor.util.context.Context;import java.util.HashMap;
import java.util.Map;
import java.util.Optional;public class MdcSubscriber implements CoreSubscriber {private static final String TRACE_ID = "traceId";private static final String SKYWALKING_CTX_SNAPSHOT = "SKYWALKING_CONTEXT_SNAPSHOT";private final CoreSubscriber<Object> actual;public MdcSubscriber(CoreSubscriber<Object> actual) {this.actual = actual;}@Overridepublic void onSubscribe(Subscription s) {actual.onSubscribe(s);}@Overridepublic void onNext(Object o) {Context c = actual.currentContext();Optional<String> traceIdOptional = Optional.empty();if (!c.isEmpty() && c.hasKey(SKYWALKING_CTX_SNAPSHOT)) {traceIdOptional = Optional.of(c.get(SKYWALKING_CTX_SNAPSHOT)).map(MdcSubscriber::beanToMap).map(t -> t.get(TRACE_ID)).map(MdcSubscriber::beanToMap).map(t -> t.get("id")).map(Object::toString);}try (MDC.MDCCloseable cMdc = MDC.putCloseable(TRACE_ID, traceIdOptional.orElse("N/A"))) {actual.onNext(o);}}@Overridepublic void onError(Throwable throwable) {actual.onError(throwable);}@Overridepublic void onComplete() {actual.onComplete();}@Overridepublic Context currentContext() {return actual.currentContext();}public static <T> Map<String, Object> beanToMap(T bean) {Map<String, Object> map = new HashMap<>();if (bean != null) {BeanMap beanMap = BeanMap.create(bean);for (Object key : beanMap.keySet()) {if (key.equals("traceId") || key.equals("id")) {map.put(key.toString(), beanMap.get(key));}}}return map;}}
4.2.3. 增加log4j2日志配置文件
log4j2.xml内容
<?xml version="1.0" encoding="UTF-8"?>
<Configuration><Properties><Property name="PATTERN" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [TID: %equals{%X{traceId}}{}{N/A}] [%logger{36}] [%thread] [%-5level] %msg%n"/></Properties><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="${PATTERN}"/></Console><Async name="Async"><AppenderRef ref="Console"/></Async><!--输出到日志文件,滚动分割日志文件,自动打包gz --><RollingFile name="INFO_FILE" fileName="logs/gateway-info1.log" filePattern="$logs/gateway-%d{yyyyMMdd}.log.%i"><PatternLayout pattern="${PATTERN}"/><Policies><!--默认一天一个文件 --><TimeBasedTriggeringPolicy /><!--一天内大于size就单独分隔--><SizeBasedTriggeringPolicy size="500MB"/></Policies></RollingFile><!--skywalking 日志收集 --><GRPCLogClientAppender name="APM_LOG"><PatternLayout pattern="${PATTERN}"/></GRPCLogClientAppender></Appenders><Loggers><Root level="INFO"><AppenderRef ref="Console"/><AppenderRef ref="INFO_FILE"/><AppenderRef ref="APM_LOG"/></Root></Loggers>
</Configuration>
4.2.4. 启动
启动gateway服务,发起http请求,可以看到日志中已经出现traceId
要注意的是,在skywalking控制台看日志时,是没有traceid的,这一点和普通的springboot项目不同
如下图所示,gateway服务的日志 traceId只能在内容里面查看
4.2.5. 完成
相关文章:

SpringCloud集成Skywalking链路追踪和日志收集
1. 下载Agents https://archive.apache.org/dist/skywalking/java-agent/9.0.0/apache-skywalking-java-agent-9.0.0.tgz 2. 上传到服务器解压 在Spring Cloud项目中,每部署一个服务时,就拷贝一份skywalking的agent文件到该服务器上并解压。不管是部署…...
HTTP 域名和主机是一回事吗?有了主机和域名,如何建站?
域名不等于主机名,例如baidu.com是一个权威域的域名,但是根本没有一个主机的名字叫做baidu.com,但是dns.baidu.com就是一个主机名,它就是负责baidu.com的服务器的主机名,www.baidu.com也是一个主机名,它是百度web服务器的主机名。…...
运营干货:四个技巧掌握爆款选题方法
在运营工作中,选题是一项至关重要的工作,选对了一个热门话题,就能吸引大量用户的关注和互动,从而取得更好的运营成果。 今天,就给大家分享四个爆款选题方法,让大家的运营更上一层楼! 第一种&a…...

柯桥商务口语之怎么样说英语更加礼貌?十个礼貌用语get起来!
当你在国外需要帮助的时候,这些礼貌用语真的是能够帮到你的哦 1.Would/Could you help me? 你可帮助我吗? 相信有些人想请求帮助的时候,一开口就用Can you,这个用在朋友或者熟人上面当然是没有问题的,但是如果是向…...

嵌入式工程师如何摸鱼?
有老铁问我,做嵌入式开发要加班吗? 也不知道搞什么鬼,现在的年轻人对加班这么抵触。 我刚做开发那会,啥也不懂,每天基本都要加班到晚上7-9点不等,我并不抵触加班,因为早早回家,也没什…...
C++语言题库(一)—— 基本知识类
目录 1. Hello World! 2. 据说一个人的标准体重应该是其身高(单位:厘米)减去100、再乘以0.9所得到的公斤数。已知市斤的数值是公斤数值的两倍。现给定某人身高,请你计算其标准体重应该是多少? 3. 给定一个华氏温度F…...

gemini1.5 API调用
https://ai.google.dev/pricing?hlzh-cn 查询可用的model https://generativelanguage.googleapis.com/v1beta/models?keyxxx 使用postman调用 https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro-latest:generateContent?keyxxx https://ai.google…...

C++从入门到精通——const与取地址重载
const与取地址重载 前言一、const正常用法const成员函数问题const对象可以调用非const成员函数吗非const对象可以调用const成员函数吗const成员函数内可以调用其它的非const成员函数吗非const成员函数内可以调用其它的const成员函数吗总结 二、取地址及const取地址操作符重载概…...

手写spring IOC底层源码来模拟spring如何利用多级缓存解决循环依赖的问题
在文章开始之前,先来看一张spring IOC加载过程的脑图吧 Spring IOC的加载过程 首先,当我们去new了一个applicationContext,它底层呢就会把我们配置的bean进行扫描,然后创建成一个一个的beanDefinition放在我们的beanDefinitionMap中,此时就有了一切创造bean的原料信…...
C++11 Thead线程和线程池
参考资料: 2、5.lock_guard 与 std::unique_lock-陈子青的编程学习课堂 (seestudy.cn) 3、C11 多线程编程-小白零基础到手撕线程池_哔哩哔哩_bilibili 一、 C11 Thead线程库的基本使用 # include <thread> std::thread t(function_name, args...); // 线…...

Windows版Apache 2.4.59解压直用(免安装-绿色-项目打包直接使用)
windows下Apache分类 Apache分为 安装版和解压版 安装版: 安装方便,下一步------下一步就OK了,但重装系统更换环境又要重新来一遍,会特别麻烦 解压版(推荐): 这种方式(项目打包特别方便&#x…...

刀具表面上的微结构
刀具表面微结构通常指在刀具表面对特定功能设计的微观纹理,这些纹理可以是沟槽、凹坑、凸起或任何其他形式的微观图案。这些微结构的设计和应用是为了改善刀具的切削性能,减少切削力和切削温度,提高切削效率和精度,同时降低切削液…...

css3实现微信扫码登陆动画
在做微信扫码登陆时,出现一个背景光图上下扫码动画,用css3图片实现。 实现原理: 1.准备一个渐变的背景.png图 2.css动画帧实现动画 看效果: css代码: #wx-scan{position: absolute;top:0px;left: 50%;z-index: 3;ma…...
vue3 导入excel数据
所需包 "xlsx": "^0.18.5"页面导入包 import * as XLSX from xlsx; import {genFileId, UploadProps, UploadRawFile,ElTable } from element-plus;页面 <el-upload accept".xlsx" :on-change"changeExcel" :on-exceed"ha…...
C# linq 根据多字段动态Group by
实现类: public static class LinqHepler {/// <summary>/// 根据单个字段动态Group/// </summary>/// <typeparam name"T"></typeparam>/// <param name"source"></param>/// <param name"prop…...

C语言学习/复习22----阶段测评编程题
一、阶段测评练习 题1: 题2:...

LeetCode-1766. 互质树【树 深度优先搜索 广度优先搜索 数组 数学 数论】
LeetCode-1766. 互质树【树 深度优先搜索 广度优先搜索 数组 数学 数论】 题目描述:解题思路一:DFS 中记录节点值的深度和编号,回溯写法。关键点是1 < nums[i] < 50解题思路二:0解题思路三:0 题目描述࿱…...
“数据安全服务能力”评定资格认证!不容错过
数据安全服务能力评定是指对数据安全服务提供商从事数据安全服务综合能力的评定,包括技术能力、服务能力、质量保证能力、人员构成与素质、经营业绩、资产状况等要素。 一、能力评定类型与等级 数据安全服务能力分为二个类型:数据安全评估、数据安全建…...
【MATLAB 分类算法教程】_3麻雀搜索算法优化支持向量机SVM分类 - 教程和对应MATLAB代码
分类代码案例3:麻雀搜索算法优化支持向量机SVM分类 - MATLAB完全代码教程 1. 初始化代码2.读取数据代码3.数据预处理代码4.利用麻雀搜索算法SSA求解最佳的SVM参数c和g代码5.根据最佳的参数进行SVM模型训练代码6.SVM模型预测代码7.准确率分析以及分类结果对比作图代码本文以红酒…...
利用机器学习库做动态定价策略的例子
动态定价是一个复杂的问题,涉及到市场需求、库存、竞争对手行为、季节性因素等多个变量。在实际应用中,动态定价通常需要复杂的模型和大量的数据分析。我选择使用Python(Golearn库)进行机器学习模型的训练和部署,而将G…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...