grpc中间件之链路追踪(otel+jaeger)

参考文档

https://github.com/grpc-ecosystem/go-grpc-middleware/blob/main/examples/client/main.go
https://github.com/grpc-ecosystem/go-grpc-middleware/blob/main/examples/server/main.go
https://github.com/open-telemetry/opentelemetry-go/blob/main/example/jaeger/main.go

直接展示代码:

client代码:

package main

import (
	"context"
	"fmt"
	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
	myInterceptor "go_grpc/grpc_middleware/interceptor"
	"go_grpc/grpc_middleware/model"
	"go_grpc/grpc_middleware/pb"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
	"log"
	"os"
	"time"
)

func main() {
	//创建traceProvider
	tp, err := myInterceptor.NewTracerProvider("http://localhost:14268/api/traces", "grpc_mid_client")
	if err != nil {
		fmt.Println("NewTracerProvider err:", err)
		os.Exit(1)
	}
	conn, err := grpc.Dial("localhost:4399", grpc.WithTransportCredentials(insecure.NewCredentials()),
		//一元拦截器
		grpc.WithChainUnaryInterceptor(
			//openTelemetry 链路追踪
			otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(tp)),
		),
		//流拦截器
		grpc.WithChainStreamInterceptor(func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
			// Pre-processing logic
			s := time.Now()
			cs, err := streamer(ctx, desc, cc, method, opts...)
			// Post processing logic
			log.Printf("method: %s, latency: %s\n", method, time.Now().Sub(s))
			return cs, err
		}),
	)

	//必须执行这一步,才能形成正常的链路追踪
	defer func() {
		println("关闭TracerProvider。所有注册的跨度处理器都会按照它们注册的顺序关闭,并释放所有持有的计算资源。")
		if err := tp.Shutdown(context.Background()); err != nil {
			panic(err)
		}
	}()
	if err != nil {
		log.Fatalf("connection failed,err:%s", err)
	}
	client := pb.NewOrderClient(conn)
	ctx := metadata.NewOutgoingContext(context.Background(), md)
	//客户端发送
	resp, err := client.OrderDetail(ctx, &pb.OrderReq{
		OrderId: 5,
	})
	if err != nil {
		log.Fatalf("orderDetail failed,err:%s", err)
	}
	fmt.Printf("resp:%v\n", resp)

}

server代码(这里只展示核心代码):

	//创建traceProvider
	tp, err := myInterceptor.NewTracerProvider("http://localhost:14268/api/traces", "grpc_mid_server")
	if err != nil {
		fmt.Println("NewTracerProvider err:", err)
		os.Exit(1)
	}

	orderServer := service.NewOrderService()
	rpcServer := grpc.NewServer(
		//4.引入grpc-middleware定义的拦截器
		grpc.ChainUnaryInterceptor(
			//openTelemetry 链路追踪
			otelgrpc.UnaryServerInterceptor(otelgrpc.WithTracerProvider(tp)),
		),
	)
	pb.RegisterOrderServer(rpcServer, orderServer)

myInterceptor包:

package interceptor

import (
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/jaeger"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	tracesdk "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
)

// NewTracerProvider 创建trace的提供者
// tracerProvider returns an OpenTelemetry TracerProvider configured to use
// the Jaeger exporter that will send spans to the provided url. The returned
// TracerProvider will also use a Resource configured with all the information
// about the application.
// 参考gitHub example :https://github.com/open-telemetry/opentelemetry-go/blob/main/example/jaeger/main.go
// 访问 http://127.0.0.1:16686/ 即可通过jaeger查看调用过程
func NewTracerProvider(url string, service string) (*tracesdk.TracerProvider, error) {
	// Create the Jaeger exporter
	// 创建 Jaeger exporter
	exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
	if err != nil {
		return nil, err
	}
	tp := tracesdk.NewTracerProvider(
		// Always be sure to batch in production.
		tracesdk.WithBatcher(exp),
		// Record information about this application in a Resource.
		tracesdk.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceNameKey.String(service),
			attribute.String("environment", "dev"),
			attribute.Int64("ID", 1),
		)),
	)
	//SetTracerProvider将“tp”注册为全局跟踪提供程序。
	otel.SetTracerProvider(tp)
	//传播(Propagation)是在服务和进程之间传递上下文的机制。它对上下文对象进行序列化或反序列化,并提供相关的跟踪(Trace)信息,以便从一个服务传播到另一个服务。
	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
	return tp, nil
}

代码写好后,先启动server端的代码,再启动client端的代码。然后登录http://127.0.0.1:16686/ 即可通过jaeger查看调用过程。(要先下载jaeger)
在这里插入图片描述

在这里插入图片描述

【如何看客户端的trace信息有没有传递到服务端?】
可以在server端打印上下文的入站metadata:

md, ok := metadata.FromIncomingContext(ctx) //如果客户端那边有开启链路追踪,这里就能输出:traceparent:[00-c92465d487349809e1c1157ba4133f77-0aa3bcd98ed5fedb-01]
fmt.Printf("md:%v\n", md)

可以看到输出metadata携带了trace信息,说明客户端的trace顺利传递到服务端了:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/41840.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学会项目成本管理计算,PMP计算题就是送分题

学会项目成本管理计算&#xff0c;PMP计算题就是送分题 PMP中的计算主要在 <项目成本管理> 的控制成本部分&#xff0c;服务于挣值管理&#xff08;EVM&#xff0c;Earned Value Management&#xff09;、挣值分析&#xff08;EVA&#xff0c;Earned Value Analysis&…

基于SSM的校园二手交易平台

零、源码获取&#xff1a; 链接点击直达&#xff1a;下载链接 一、设计概要 本次设计的是一个校园二手交易平台&#xff08;C2C&#xff09;&#xff0c;C2C指个人与个人之间的电子商务&#xff0c;买家可以查看所有卖家发布的商品&#xff0c;并且根据分类进行商品过滤&…

微信怎么自动加好友,通过好友后自动打招呼

很多客户朋友每天花大量的时间用手机搜索添加好友&#xff0c;这样的添加很集中也容易频繁&#xff0c;而且效率还低。对方通过后&#xff0c;有时也不能及时和客户搭建链接&#xff0c;导致客户也流失了。 现在可以实现自动添加和自动打招呼哦&#xff0c;只需要导入数据、设置…

SpringCloud(三)LoadBalancer负载均衡

一、负载均衡 实际上&#xff0c;在添加LoadBalanced注解之后&#xff0c;会启用拦截器对我们发起的服务调用请求进行拦截&#xff08;注意这里是针对我们发起的请求进行拦截&#xff09;&#xff0c;叫做LoadBalancerInterceptor&#xff0c;它实现ClientHttpRequestIntercep…

店铺记账用什么软件好?应该如何选购?

店铺记账过程中&#xff0c;会遇到各种问题&#xff1a;手写记账容易出错、效率低下、数据容易丢失&#xff1b;手动整理数据导致实际库存和账面库存不匹配&#xff0c;影响补货和订单管理。 而借助专业的店铺记账软件&#xff0c;可以有效解决上面这些问题&#xff0c;通过自动…

redis穿透问题

1.概述 一个热点数据在高并发情况下过期时间到了&#xff0c;会导致大量流量查询redis为null&#xff0c;进而请求数据库进行更新数据&#xff0c;从流量上来说请求打到了数据库上&#xff0c;这种情况可能会造成mysql服务崩溃。 2. 解决方式之一&#xff08;加锁解决之本地锁&…

『红外图像 数据增强』DDE(Digital Detail Enhancement)算法

DDE处理的细节 分离背景层和细节层&#xff1a;使用特殊的滤波器&#xff0c;将图像分成背景层和细节层。背景层通常包含低频信息&#xff0c;而细节层包含高频信息。 对背景层进行灰度增强&#xff1a;通过对背景层应用适当的灰度增强算法&#xff0c;提高背景层的对比度和视…

PostgreSQL 考试认证指南:考前准备和考试概述

下面是关于考前准备和考试概述的指南&#xff1a; 考前准备&#xff1a; 1.确定考试内容&#xff1a;详细了解考试的内容范围和考试要求。可以查阅PostgreSQL官方网站或认证考试指南&#xff0c;以获取相关信息。 2.学习和实践&#xff1a;系统地学习和掌握与PostgreSQL相关…

Vant源码解析(四)----Popup弹出层,详解样式方法

这个功能&#xff0c;自己也手写过&#xff0c;毕竟有很多弹窗的嘛。 我自己写就是&#xff1a;一个背景层&#xff0c;然后一个盒子里面放内容。再写个显示隐藏事件。够够的了。 Vant的Popup弹出层 页面结构 短短一个背景加内容盒子&#xff0c;vant套了几层。 这是引用的组件…

抖音矩阵系统源码:开发搭建与技术详解

一、 抖音矩阵系统源码开发概述 抖音短视频seo矩阵系统源码是一款在高速数据处理和分析方面表现卓越的系统。它结合了各种先进的技术&#xff0c;包括深度学习、大数据分析和可视化等&#xff0c;使得抖音在信息处理时更加高效和准确。 该系统源码的开发搭建需要多方面的技术支…

2023网络安全面试题汇总(附答题解析+配套资料)

随着国家政策的扶持&#xff0c;网络安全行业也越来越为大众所熟知&#xff0c;相应的想要进入到网络安全行业的人也越来越多&#xff0c;为了更好地进行工作&#xff0c;除了学好网络安全知识外&#xff0c;还要应对企业的面试。 所以在这里我归总了一些网络安全方面的常见面…

性能测试:Jmeter压测过程中的短信验证码读取

目录 问题背景 解决思路 实现方法 1. 建立JDBC连接 2. 使用JDBC请求获取验证码 3. 使用正则将验证码提取并使用 总结&#xff1a; 问题背景 现如今国内的大部分软件或者网站应用&#xff0c;普遍流行使用短信业务&#xff0c;比如登录、注册以及特定的业务通知等。 对…

Enterprise:通过 App search 摄入数据

App Search 是 Elastic Enterprise Search 的一部分&#xff0c;Elastic Enterprise Search 是由 Elasticsearch 提供支持的内容搜索工具集合。 最初由 App Search 引入的一些功能&#xff08;例如网络爬虫&#xff09;现在可以直接通过企业搜索使用。 将这些功能与其他企业搜…

密码学学习笔记(十二):压缩函数 - Davies–Meyer结构

密码学中压缩函数是指将输入的任意长度消息压缩为固定长度输出的函数。压缩函数以两个特定长度的数据为输入&#xff0c;产生与其中一个输入大小相同的输出。简单来说就是它接受一些较长的数据&#xff0c;输出更短的数据。 压缩函数接收长度为X和Y的两个不同输入&#xff0c;并…

青岛大学_王卓老师【数据结构与算法】Week05_14_队列的顺序表示和实现2_学习笔记

本文是个人学习笔记&#xff0c;素材来自青岛大学王卓老师的教学视频。 一方面用于学习记录与分享&#xff0c; 另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。 如有侵权&#xff0c;请留言作删文处理。 课程视频链接&#xff1a; 数据结构与算法基础…

回归预测 | MATLAB实现基于ELM-Adaboost极限学习机结合AdaBoost多输入单输出回归预测

回归预测 | MATLAB实现基于ELM-Adaboost极限学习机结合AdaBoost多输入单输出回归预测 目录 回归预测 | MATLAB实现基于ELM-Adaboost极限学习机结合AdaBoost多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于ELM-Adaboost极限学…

Java线程相关

线程优先级 在Java线程中&#xff0c;通过一个整型成员变量priority来控制优先级&#xff0c;优先级的范围从1~10&#xff0c;在线程构建的时候可以通过setPriority(int)方法来修改优先级&#xff0c;默认优先级是5&#xff0c;优先级高的线程分配时间片的数量要多于优先级低的…

【基于 GitLab 的 CI/CD 实践】01、GitLab CI/CD 基础概念

目录 一、为什么要做 CI/CD &#xff1f; 1.1 背景-传统的应用开发发布模式 问题 1.2 持续集成与持续交付 持续集成&#xff08;CI&#xff09; 持续交付&#xff08;CD&#xff09; 持续部署&#xff08;CD&#xff09; 1.3 CI/CD 的价值体现 1.4 推荐常用的 CI/CD 工…

Linux内核结构与特性简介

系统调用接口&#xff1a;位于最上层&#xff0c;实现了一些基本的功能&#xff0c;如read和write等系统调用。这是用户空间程序与内核交互的接口&#xff0c;提供了对内核功能的访问。 内核代码&#xff1a;位于系统调用接口之下&#xff0c;可以看作是独立于体系结构的通用内…

linux之Ubuntu系列(四)用户管理 用户和权限 chmod 超级用户root, R、W、X、T、S 软链接和硬链接 shell

r(Read&#xff0c;读取)&#xff1a;对文件而言&#xff0c;具有读取文件内容的权限&#xff1b;对目录来说&#xff0c;具有浏览目 录的权限。 w(Write,写入)&#xff1a;对文件而言&#xff0c;具有新增、修改文件内容的权限&#xff1b;对目录来说&#xff0c;具有删除、移…