免去繁琐的手动埋点,Gin 框架可观测性最佳实践

作者:牧思

背景

在云原生时代的今天,Golang 编程语言越来越成为开发者们的首选,而对于 Golang 开发者来说,最著名的 Golang Web 框架莫过于 Gin [ 1] 框架了,Gin 框架作为 Golang 编程语言官方的推荐框架 [ 2] ,其提供了丰富的路由与中间件功能,使得 Golang 开发者可以轻松地构建复杂的 Web 应用。对于如此重要的 Web 框架,如何去快速而全面地对 Gin 应用进行监控成为了一大难题,本文将着重介绍 Gin 框架官方推荐的几种可观测性方案并进行对比,从而得出 Gin 框架可观测性的最佳实践。

观测方案一览

Gin 官方提供了丰富的插件来帮助开发者快速地搭建 Web 应用,在官方提供的插件列表 [ 3] 中,提供了对 OpenTelemetry 的几种支持方案,分别是 SDK 手动埋点方案 [ 4] ,编译时注入方案 [ 5] ,以及 eBPF 方案 [6 ] ,下面分别来对官方推荐的三种观测方案进行实践:

前置准备

  1. 首先使用 Gin 框架编写一个简单的 Golang 应用:
package mainimport ("io""log""net/http""time""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/hello-gin", func(c *gin.Context) {c.String(http.StatusOK, "hello\n")})go func() {_ = r.Run()}()// give time for auto-instrumentation to start uptime.Sleep(5 * time.Second)for {resp, err := http.Get("http://localhost:8080/hello-gin")if err != nil {log.Fatal(err)}body, err := io.ReadAll(resp.Body)if err != nil {log.Fatal(err)}log.Printf("Body: %s\n", string(body))_ = resp.Body.Close()// give time for auto-instrumentation to report signaltime.Sleep(5 * time.Second)}
}
  1. 根据文档 [ 7] 快速拉起 OpenTelemetry 的各种服务端依赖,比如 OpenTelemetry Collector,Jaeger,Prometheus 等等。

手动埋点

手动埋点方案即是利用了 Gin 框架的 Middleware 机制,在 Gin 的请求处理过程中为本次请求生成 span,我们需要基于以上代码进行改造:

const (SERVICE_NAME       = ""SERVICE_VERSION    = ""DEPLOY_ENVIRONMENT = ""HTTP_ENDPOINT      = ""HTTP_URL_PATH      = ""
)// 设置应用资源
func newResource(ctx context.Context) *resource.Resource {hostName, _ := os.Hostname()r, err := resource.New(ctx,resource.WithFromEnv(),resource.WithProcess(),resource.WithTelemetrySDK(),resource.WithHost(),resource.WithAttributes(semconv.ServiceNameKey.String(SERVICE_NAME), // 应用名semconv.ServiceVersionKey.String(SERVICE_VERSION), // 应用版本semconv.DeploymentEnvironmentKey.String(DEPLOY_ENVIRONMENT), // 部署环境semconv.HostNameKey.String(hostName), // 主机名),)if err != nil {log.Fatalf("%s: %v", "Failed to create OpenTelemetry resource", err)}return r
}func newHTTPExporterAndSpanProcessor(ctx context.Context) (*otlptrace.Exporter, sdktrace.SpanProcessor) {traceExporter, err := otlptrace.New(ctx, otlptracehttp.NewClient(otlptracehttp.WithEndpoint(HTTP_ENDPOINT),otlptracehttp.WithURLPath(HTTP_URL_PATH),otlptracehttp.WithInsecure(),otlptracehttp.WithCompression(1)))if err != nil {log.Fatalf("%s: %v", "Failed to create the OpenTelemetry trace exporter", err)}batchSpanProcessor := sdktrace.NewBatchSpanProcessor(traceExporter)return traceExporter, batchSpanProcessor
}// InitOpenTelemetry OpenTelemetry 初始化方法
func InitOpenTelemetry() func() {ctx := context.Background()var traceExporter *otlptrace.Exportervar batchSpanProcessor sdktrace.SpanProcessortraceExporter, batchSpanProcessor = newHTTPExporterAndSpanProcessor(ctx)otelResource := newResource(ctx)traceProvider := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()),sdktrace.WithResource(otelResource),sdktrace.WithSpanProcessor(batchSpanProcessor))otel.SetTracerProvider(traceProvider)otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))return func() {cxt, cancel := context.WithTimeout(ctx, time.Second)defer cancel()if err := traceExporter.Shutdown(cxt); err != nil {otel.Handle(err)}}
}func main() {r := gin.Default()// 初始化您的OpenTelemetrytp, err := InitOpenTelemetry()if err != nil {log.Fatal(err)}defer func() {if err := tp.Shutdown(context.Background()); err != nil {log.Printf("Error shutting down tracer provider: %v", err)}}()// 添加gin的OpenTelemetry中间件实现r.Use(otelgin.Middleware("my-server"))r.GET("/hello-gin", func(c *gin.Context) {c.String(http.StatusOK, "hello\n")})
}

通过在代码里面对 Gin 服务添加 OpenTelemetry 中间件,可以有效地收集到 Gin 应用本身的调用链路信息:

可以看到,手动接入的方案需要对代码进行比较大的改造,需要去手动引入依赖,初始化 SDK,并手动注入 middleware,此外,该方案只能收集到 Gin 应用本身的链路信息,对于 Gin 的上游和下游应用也需要进行代码的改造才能将整个链路进行打通和串联。

编译时注入自动埋点

除了手动埋点方案,官方还推荐了编译时自动注入方案来实现在零代码修改的观测方案,用户可以参考阿里巴巴开源的编译时自动插桩项目 [ 8] 对上述实例程序进行插桩:

step 1:下载 Golang Agent 二进制包

首先,可以进入主页 [ 9] 下载最新版本的 Golang Agent 二进制包。

step 2:使用 Golang Agent 二进制包编译 Golang 应用

在拥有了 Golang Agent 的二进制包后,即可使用该二进制包代替 go build 编译 Golang 应用的二进制程序。

otel-linux-amd64 go build .

在执行上述命令后,即可在对应应用的根目录下找到具有可观测能力的 Golang 二进制程序。

step 3:配置上报端点,运行二进制程序

最后,通过文档 [ 10] 配置观测数据的上报端点,并且启动上一步中编译出来的具有可观测能力的 Golang 二进制程序:

可以看到,编译出来的二进制 Golang 程序可以完整地展示出应用的调用链路。

除了链路,编译出来的二进制 Golang 程序还可以有效地收集 Gin 应用的运行时指标,比如 Gin 应用的调用耗时,GC 次数,内存申请次数等等:

eBPF 自动埋点

官方提供的最后一种 Gin 应用的观测办法是通过 OpenTelemetry 的 eBPF 方案进行自动埋点,eBPF 方式只需要在部署应用时在应用进程命名空间下添加一个特权级的 Sidecar 容器,特权级的 Sidecar 容器会自动捕捉应用容器产生的观测数据,并且进行上报。

我们还是对第一步中使用的简易 Golang 应用进行观测,在 Kubernetes 环境中部署以下 yaml:

apiVersion: apps/v1
kind: Deployment
metadata:labels:app.kubernetes.io/name: emojiapp.kubernetes.io/part-of: emojivotoapp.kubernetes.io/version: v11name: emojinamespace: emojivoto
spec:progressDeadlineSeconds: 600replicas: 1revisionHistoryLimit: 10selector:matchLabels:app: emoji-svcversion: v11template:metadata:labels:app: emoji-svcversion: v11spec:containers:- env:- name: HTTPvalue: '8080'image: 'registry.cn-hangzhou.aliyuncs.com/private-mesh/ginotel:latest'imagePullPolicy: Alwaysname: emoji-svcports:- containerPort: 8080name: grpcprotocol: TCPresources:requests:cpu: 100mterminationMessagePath: /dev/termination-logterminationMessagePolicy: File- env:- name: OTEL_GO_AUTO_TARGET_EXEvalue: /usr/local/bin/app- name: OTEL_EXPORTER_OTLP_ENDPOINTvalue: 'http://jaeger.default.svc:4318'- name: OTEL_SERVICE_NAMEvalue: emojivoto-emojiimage: >-ghcr.io/open-telemetry/opentelemetry-go-instrumentation/autoinstrumentation-go:v0.19.0-alphaimagePullPolicy: IfNotPresentname: emojivoto-emoji-instrumentationresources: {}securityContext:privileged: truerunAsUser: 0terminationMessagePath: /dev/termination-logterminationMessagePolicy: FilednsPolicy: ClusterFirstrestartPolicy: AlwaysschedulerName: default-schedulersecurityContext: {}shareProcessNamespace: trueterminationGracePeriodSeconds: 0

Gin 应用产生的观测数据将会被自动地收集并上报至 jaeger 中:

eBPF 方案看起来非常的美好,但是实际使用时却有着各种限制,比如其对于 Golang 的小版本非常的敏感,demo 中的应用,如果我们使用 Go 1.23.4 版本(升级 1 个小版本)来进行编译,eBPF 就将因为 Golang 的版本不匹配而无法收集到任何观测数据:

此外,eBPF 方案还有其他较多的限制,比如 client 传递的 HTTP Header 不能超过 8 个,又比如 eBPF 对操作系统的内核版本的要求较高等等,具体可以参照这篇文章。

观测方案对比

总的来说,手动埋点的自由度更高,但是接入和维护的成本也最高,适合技术能力强的用户自己完全控制。eBPF 自动埋点方案接入成本最低,但是随之而来的是性能的开销以及使用场景的各种限制。而编译时注入自动埋点的方案相对来说解决了前两种方案的各种问题,在降低了用户接入维护成本的同时也解决了插桩的性能,安全性等问题,某种程度上是目前最适合客户的 Gin 应用观测方案!

总结和展望

Golang Agent 成功解决了 Golang 应用监控中繁琐的手动埋点问题,并已商业化上线至阿里云公有云,为客户提供强大的监控能力。这项技术最初的设计初衷是为了让用户能够在不改动现有代码的前提下轻松地插入监控代码,从而实现对应用程序性能状态的实时监测与分析,但它的实际应用领域超越预期,包括服务治理、代码审计、应用安全、代码调试等,甚至在许多未被探索的领域中也展现出潜力。

我们已经将这项创新方案开源,并成功捐赠给 OpenTelemetry 社区 [ 11] 。开源不仅促进技术共享与提升,借助社区的力量还可以持续探索该方案在更多领域上的可能。

最后诚邀大家试用我们的商业化产品,并加入我们的钉钉群 (开源群:102565007776,商业化群:35568145) ,共同提升 Go 应用监控与服务治理能力。通过群策群力,我们相信能为 Golang 开发者社区带来更加优质的云原生体验。

相关链接:

[1] Gin

https://github.com/gin-gonic/gin

[2] 推荐框架

https://go.dev/doc/tutorial/web-service-gin

[3] 插件列表

https://github.com/gin-gonic/contrib

[4] SDK 手动埋点方案

https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/github.com/gin-gonic/gin/otelgin

[5] 编译时注入方案

https://github.com/alibaba/opentelemetry-go-auto-instrumentation

[6] eBPF 方案

https://github.com/open-telemetry/opentelemetry-go-instrumentation

[7] 文档

https://opentelemetry.io/docs/demo/kubernetes-deployment/

[8] 编译时自动插桩项目

https://github.com/alibaba/opentelemetry-go-auto-instrumentation

[9] 主页

https://github.com/alibaba/opentelemetry-go-auto-instrumentation

[10] 文档

https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/

[11] OpenTelemetry 社区

https://github.com/open-telemetry/opentelemetry-go-compile-instrumentation

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【QT】新建QT工程(详细步骤)

新建QT工程 1.方法(1)点击new project按钮,弹出对话框,新建即可,步骤如下:(2) 点击文件菜单,选择新建文件或者工程,后续步骤如上 2.QT工程文件介绍(1).pro文件 --》QT工程配置文件(2)main.cpp --》QT工程主…

优化MyBatis-Plus批量插入策略

优化MyBatis-Plus批量插入策略 优化MyBatis-Plus批量插入策略一、用Mybatis-plus中的saveBatch方法二、InsertBatchSomeColumn插件1.使用前配置2.代码示例1.配置类 MybatisPlusConfig2).实体类 User3).Mapper 接口 UserMapper4).测试类 InsertBatchTest 优化MyBatis-Plus批量插…

记一次系统单点登录、模拟web系统登录方式的开发过程,使用AES加密

1.系统原始登录方式 访问登录页 输入账号密码登录后 2.从登录页找进去,从代码层面查看系统登录逻辑 常规登录方式为前端ajax请求LoginService服务-->返回200则跳转到home系统首页 查看LoginService登录逻辑 后台获取ajax传递的信息-->比较验证码-->查询…

iPhone mini,永远再见了

世界属于多数派,尽管有极少数人对 iPhone mini 情有独钟,但因为销量惨淡,iPhone mini 还是逃不开停产的命运。 据 Counterpoint 的数据,iPhone 12/13 mini 两代机型,仅占同期 iPhone 销量的 5%。 因为是小屏手机&…

监控易一体化运维:监控易机房管理,打造高效智能机房

在数字化浪潮中,企业对数据中心和机房的依赖程度与日俱增,机房的稳定运行成为业务持续开展的关键支撑。信息化的变迁,见证了机房管理从传统模式向智能化、精细化转变的过程。今天,就为大家深度剖析监控易在机房管理方面的卓越表现…

概率与决策理论

1.Q-learning Q-Learning 是一种无模型(model-free)强化学习算法,用于学习在马尔可夫决策过程(MDP)中的最优策略。它通过迭代更新 ​Q 值(动作价值函数)​ 来估计在某个状态下采取某个动作的长…

Python 学习路线推荐

文章目录 一、基础语法学习1.学习资源2.学习建议 二、数据处理与分析方向1. 数据处理库学习学习资源实践示例 2. 数据可视化实践示例 三、Web 开发方向1. Web 框架选择与学习学习资源实践示例 2. 前端知识补充学习资源 四、人工智能与机器学习方向1. 机器学习基础学习资源实践示…

如何让DeepSeek-R1在内网稳定运行并实现随时随地远程在线调用

前言:最近,国产AI圈里的新星——Deepseek,简直是火到不行。但是,你是不是已经对那些千篇一律的手机APP和网页版体验感到腻味了?别急,今天就带你解锁一个超炫的操作:在你的Windows电脑上本地部署…

SpringCloud+Mybatis-Plus+Docker+RabbitMQ+Redis+Elasticsearch黑马商城

一.MyBatis—Plus 一.快速入门 MybatisPlus介绍:MybatisPlus是一个基于Mybatis的增强工具库,旨在简化开发、提升效率,同时保留Mybatis的灵活性。它在Mybatis的基础上只做增强不做改变,引入它不会对现有工程产生影响 官网&#…

01 相机标定与相机模型介绍

学完本文,您将了解不同相机模型分类、内参意义,及对应的应用代码模型 标定的意义 建模三维世界点投影到二维图像平面的过程。标定输出的是相机模型。 相机模型 相机模型可以解理解为投影模型 +

如何在 Postman 中正确设置 Session 以维持用户状态?

在 Postman 里面设置有 session 的请求。如果你还不知道什么是 session,那么请看这里—— session 是一种记录客户端和服务器之间状态的机制,用于保持用户的登录状态或者其他数据,从而让用户在不同页面之间保持一致的体验。 Postman 设置带 …

免费使用!OpenAI 全量开放 GPT-4o 图像生成能力!

2025年3月26日,OpenAI正式推出GPT-4o原生图像生成功能,这一更新不仅标志着多模态AI技术的重大突破,更引发了全球AI厂商的激烈竞争。从免费用户到企业开发者,从创意设计到科学可视化,GPT-4o正在重塑图像生成的边界。本文…

【JavaScript】八、对象

文章目录 1、对象的声明2、对象的使用3、对象中的方法4、遍历对象5、内置对象Math 1、对象的声明 一种数据类型,使用typeof查看类型,结果是object可以详细的描述描述某个事物 声明语法: // 多用花括号形式声明 // 比如声明一个person对象 …

C++指针(五)完结篇

个人主页:PingdiGuo_guo 收录专栏:C干货专栏 前言 相关文章:C指针(一)、C指针(二)、C指针(三)、C指针(四)万字图文详解! 本篇博客是介…

DataGear 企业版 1.4.0 发布,数据可视化分析平台

DataGear 企业版 1.4.0 已发布,欢迎体验! http://datagear.tech/pro/ 企业版 1.4.0 看板可视编辑模式新增了插入看板表单/面板布局、编辑图表联动、复制/粘贴、撤销/恢复等功能,具体更新内容如下: 新增:看板可视编辑…

windows第十八章 菜单、工具栏、状态栏

文章目录 创建框架窗口菜单菜单的风格通过资源创建菜单菜单的各种使用通过代码创建菜单在鼠标位置右键弹出菜单 CMenu常用函数介绍工具栏方式一,从资源创建工具栏方式二,代码创建 状态栏状态栏基础创建状态栏 创建框架窗口 手动创建一个空项目&#xff…

局域网共享失败?打印机/文件夹共享工具

很多时候,在办公或家庭环境中,我们需要进行打印机和文件夹的共享,以便更高效地协作和处理文件。然而,寻找对应版本的共享设置或是不想花费太多时间去进行复杂的电脑设置,总是让人感到头疼。今天,我要向大家…

C++中使用CopyFromRecordset将记录集拷贝到excel中时,如果记录集为0个,函数崩溃,是什么原因

文章目录 原因分析解决方案1. 检查记录集是否为空2. 安全调用COM方法3.进行异常捕获4. 替代方案:手动处理空数据 总结 在C中使用CopyFromRecordset将空记录集(0条记录)复制到Excel时崩溃的原因及解决方法如下: 原因分析 空记录集…

torchvision中数据集的使用

1、torchvision及其数据集的介绍 1.1 torchvision介绍 torchvision 是 PyTorch 的一个官方库,专门用于计算机视觉任务。它提供了以下核心功能: 预训练模型:如 ResNet、VGG、EfficientNet 等。数据集:内置常用视觉数据集&#xf…

d2025328

一、sql-判断三角形 610. 判断三角形 - 力扣&#xff08;LeetCode&#xff09; 用一下if加上判断条件 select x,y,z,if(xy > z and xz > y and yz > x and x-y < z and x-z < y and y-z < x,Yes,No) as triangle from Triangle 二、按照分类统计薪水 190…