news 2026/7/10 12:02:35

opentelemetry全链路初探--python注入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
opentelemetry全链路初探--python注入

前言

经过上一节,opentelemetry的基本操作都已经融会贯通,但是有位老哥提出疑问?我的代码都已经写完了,为了添加全链路,还需要重构之前的代码吗?那这个代价太大了。那本章就来讨论一下opentelemetry的注入的问题

本小节主要关注python注入

使用装饰器

使用装饰器的好处就是非常灵活,并且对代码入侵很小,只需要装饰一下即可

decoration-s1.py

import tornado.httpserver as httpserver

import tornado.web

from tornado.ioloop import IOLoop

from opentelemetry import trace

from opentelemetry.sdk.trace import TracerProvider

from opentelemetry.sdk.resources import SERVICE_NAME, Resource

from opentelemetry.sdk.trace.export import BatchSpanProcessor

from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

from opentelemetry.trace import get_tracer

trace.set_tracer_provider(

TracerProvider(resource=Resource.create({SERVICE_NAME: "decoration-s1"}))

)

span_processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://127.0.0.1:4318/v1/traces"))

trace.get_tracer_provider().add_span_processor(span_processor)

def traced(name):

def decorator(func):

def wrapper(*args, **kwargs):

tracer = get_tracer(__name__)

with tracer.start_as_current_span(name):

return func(*args, **kwargs)

return wrapper

return decorator

class TestFlow(tornado.web.RequestHandler):

def get(self):

views()

self.finish('hello world')

@traced("phase-1")

def views():

pass

def applications():

urls = []

urls.append([r'/', TestFlow])

return tornado.web.Application(urls)

def main():

app = applications()

server = httpserver.HTTPServer(app)

server.bind(10000, '0.0.0.0')

server.start(1)

IOLoop.current().start()

if __name__ == "__main__":

try:

main()

except KeyboardInterrupt as e:

IOLoop.current().stop()

finally:

IOLoop.current().close()

查看jaeger:

watermarked-inject_1

串联多个span

改造decoration-s1.py

...

@traced("phase-1")

def views():

views_2()

@traced("phase-2")

def views_2():

pass

...

watermarked-inject_2

跨服务串联span

改造decoration-s1.py

...

@traced("phase-1")

def views():

views_2()

headers = {}

inject(headers)

requests.get("http://127.0.0.1:20000", headers=headers)

@traced("phase-2")

def views_2():

pass

...

新增decoration-s2.py

import tornado.httpserver as httpserver

import tornado.web

from tornado.ioloop import IOLoop

from opentelemetry import trace

from opentelemetry.sdk.trace import TracerProvider

from opentelemetry.sdk.resources import SERVICE_NAME, Resource

from opentelemetry.sdk.trace.export import BatchSpanProcessor

from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

from opentelemetry.trace import get_tracer

from opentelemetry.propagate import extract

trace.set_tracer_provider(

TracerProvider(resource=Resource.create({SERVICE_NAME: "decoration-s2"}))

)

span_processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://127.0.0.1:4318/v1/traces"))

trace.get_tracer_provider().add_span_processor(span_processor)

def traced(name):

def decorator(func):

def wrapper(*args, **kwargs):

tracer = get_tracer(__name__)

ctx = extract(args[0])

with tracer.start_as_current_span(name, context=ctx):

return func(*args, **kwargs)

return wrapper

return decorator

class TestFlow(tornado.web.RequestHandler):

def get(self):

views(self.request.headers)

self.finish('hello world')

@traced("phase-3")

def views(headers):

pass

def applications():

urls = []

urls.append([r'/', TestFlow])

return tornado.web.Application(urls)

def main():

app = applications()

server = httpserver.HTTPServer(app)

server.bind(20000, '0.0.0.0')

server.start(1)

IOLoop.current().start()

if __name__ == "__main__":

try:

main()

except KeyboardInterrupt as e:

IOLoop.current().stop()

finally:

IOLoop.current().close()

查看jaeger,跨服务已经串联

watermarked-inject_3

自动注入 opentelemetry-instrumentation

opentelemetry-instrumentation可以自动采集在代码在不同阶段的trace

pip3 install opentelemetry-instrumentation opentelemetry-distro opentelemetry-exporter-otlp

opentelemetry-bootstrap -a install

查看支持的自动采集

▶ pip3 list | grep instrument

opentelemetry-instrumentation 0.56b0

opentelemetry-instrumentation-aiohttp-client 0.56b0

opentelemetry-instrumentation-aiohttp-server 0.56b0

opentelemetry-instrumentation-asyncio 0.56b0

opentelemetry-instrumentation-click 0.56b0

opentelemetry-instrumentation-dbapi 0.56b0

opentelemetry-instrumentation-elasticsearch 0.56b0

opentelemetry-instrumentation-flask 0.56b0

opentelemetry-instrumentation-grpc 0.56b0

opentelemetry-instrumentation-httpx 0.56b0

opentelemetry-instrumentation-jinja2 0.56b0

opentelemetry-instrumentation-kafka-python 0.56b0

opentelemetry-instrumentation-logging 0.56b0

opentelemetry-instrumentation-openai-v2 2.1b0

opentelemetry-instrumentation-pymysql 0.56b0

opentelemetry-instrumentation-redis 0.56b0

opentelemetry-instrumentation-requests 0.56b0

opentelemetry-instrumentation-sqlite3 0.56b0

opentelemetry-instrumentation-system-metrics 0.56b0

opentelemetry-instrumentation-threading 0.56b0

opentelemetry-instrumentation-tornado 0.56b0

opentelemetry-instrumentation-tortoiseorm 0.56b0

opentelemetry-instrumentation-urllib 0.56b0

opentelemetry-instrumentation-urllib3 0.56b0

opentelemetry-instrumentation-wsgi 0.56b0

可以看到,包括常见的mysql、redis、http requests等,都可以自动采集。来验证一下

auto-s1.py

from tornado.ioloop import IOLoop

import tornado.httpserver as httpserver

import tornado.web

import redis

import pymysql

import requests

class TestFlow(tornado.web.RequestHandler):

def get(self):

views()

self.finish('hello world')

def views():

get_redis()

get_db()

get_s2()

def get_redis():

r = redis.StrictRedis(host='localhost', port=6379, db=0)

r.set('name', 'hello')

def get_db():

db = pymysql.connect(host='localhost', user='root', password='123456')

cursor = db.cursor()

cursor.execute("SELECT VERSION()")

data = cursor.fetchone()

db.close()

def get_s2():

requests.get('http://127.0.0.1:20000')

def applications():

urls = []

urls.append([r'/', TestFlow])

return tornado.web.Application(urls)

def main():

app = applications()

server = httpserver.HTTPServer(app)

server.bind(10000, '0.0.0.0')

server.start(1)

IOLoop.current().start()

if __name__ == "__main__":

try:

main()

except KeyboardInterrupt as e:

IOLoop.current().stop()

finally:

IOLoop.current().close()

用opentelemetry-instrumentation启动auto-s1.py

▶ opentelemetry-instrument \

--traces_exporter otlp \

--service_name auto-s1 \

--exporter_otlp_endpoint http://0.0.0.0:4317 \

python3 auto-s1.py

auto-s2.py

from tornado.ioloop import IOLoop

import tornado.httpserver as httpserver

import tornado.web

class TestFlow(tornado.web.RequestHandler):

def get(self):

views()

self.finish('hello world')

def views():

pass

def applications():

urls = []

urls.append([r'/', TestFlow])

return tornado.web.Application(urls)

def main():

app = applications()

server = httpserver.HTTPServer(app)

server.bind(20000, '0.0.0.0')

server.start(1)

IOLoop.current().start()

if __name__ == "__main__":

try:

main()

except KeyboardInterrupt as e:

IOLoop.current().stop()

finally:

IOLoop.current().close()

同理,用opentelemetry-instrumentation启动auto-s2.py

▶ opentelemetry-instrument \

--traces_exporter otlp \

--service_name auto-s2 \

--exporter_otlp_endpoint http://0.0.0.0:4317 \

python3 auto-s2.py

已经看到整个完整的链路追踪了

watermarked-inject_4

opentelemetry-instrument与装饰器结合使用

由于opentelemetry-instrument不能跟踪自定义的模块,可以结合装饰器跟踪重点函数

修改一下auto-s1.py

...

from opentelemetry import trace

from opentelemetry.sdk.trace import TracerProvider

from opentelemetry.sdk.trace.export import BatchSpanProcessor

from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

trace.set_tracer_provider(TracerProvider())

tracer = trace.get_tracer(__name__)

span_processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://127.0.0.1:4318/v1/traces"))

trace.get_tracer_provider().add_span_processor(span_processor)

def traced_function(func):

def wrapper(*args, **kwargs):

with tracer.start_as_current_span(func.__name__):

return func(*args, **kwargs)

return wrapper

...

def views():

get_redis()

get_db()

get_important()

get_s2()

@traced_function

def get_important():

pass

...

watermarked-inject_5

小结

本节介绍了2种注入的方法

其中装饰器的方法,提前将trace流程写好,函数只需要调用装饰即可完成注入,减少了代码入侵度

而opentelemetry-instrument则是采用aop思想,将目标模块(比如pymysql、requests等)动态替换成预定义的模块,从而实现trace的注入,该方法的优点就是对业务代码的无入侵

在python中,结合以上两种方法,可以很好的完成trace注入

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/10 8:17:16

5分钟掌握GitHub入门教程优化:从零基础到高效协作

5分钟掌握GitHub入门教程优化:从零基础到高效协作 【免费下载链接】introduction-to-github Get started using GitHub in less than an hour. 项目地址: https://gitcode.com/GitHub_Trending/in/introduction-to-github 想要快速掌握GitHub的使用技巧&…

作者头像 李华
网站建设 2026/7/10 1:16:32

快速上手:Color Thief智能配色方案实战指南

快速上手:Color Thief智能配色方案实战指南 【免费下载链接】color-thief Grab the color palette from an image using just Javascript. Works in the browser and in Node. 项目地址: https://gitcode.com/gh_mirrors/co/color-thief 面对品牌视觉统一和网…

作者头像 李华
网站建设 2026/7/10 10:10:02

A16z 谈 AI 留存的「水晶鞋效应」:第一个月,决定了一切 都是一次认真“试鞋”的机会:这一次,能不能真的解决我手里的问题?

A16z 谈 AI 留存的「水晶鞋效应」:第一个月,决定了一切 原创 Cubo Group 矩阵魔方AI出海 2025年12月12日 19:45 陕西 在传统 SaaS 时代,有一条几乎没人怀疑的共识:产品早期留存差,是正常现象。 MVP 功能不全&#…

作者头像 李华
网站建设 2026/7/10 3:42:33

5、深入了解 Ubuntu 网络配置与 X Window 系统

深入了解 Ubuntu 网络配置与 X Window 系统 1. Ubuntu 无线网络配置 在过去,为 Linux 系统配置无线网络是一件非常繁琐的事情,需要执行许多复杂的步骤才能连接到无线网络。不过,现在情况有了很大的改善。Ubuntu 系统中包含了一个名为 Network Manager 的实用工具,它让连接…

作者头像 李华
网站建设 2026/7/10 10:04:38

分享几则中年夫妻关系的有益建议

著名演员何晴去世了,很震惊,她是我最喜欢的女演员,曾经出演过四大名著。分享几则中年夫妻关系的有益建议: 1、可以容忍对方的生活习惯。包括拉S放P、不叠被、不洗衣,但要管好自己,还是尽量别过份坦荡。 2、…

作者头像 李华
网站建设 2026/7/10 3:17:01

(108页PPT)园区大数据治理解决方案(附下载方式)

篇幅所限,本文只提供部分资料内容,完整资料请看下面链接 (108页PPT)园区大数据治理解决方案.pptx_智慧园区总体规划PPT资源-CSDN下载 资料解读:《园区大数据治理解决方案》 详细资料请看本解读文章的最后内容。 在数…

作者头像 李华