尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

opentelemetry全链路初探--python注入

opentelemetry全链路初探--python注入
📅 发布时间:2026/6/19 20:03:52

前言

经过上一节,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_tracertrace.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 wrapperreturn decoratorclass TestFlow(tornado.web.RequestHandler):def get(self):views()self.finish('hello world')@traced("phase-1")
def views():passdef 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 extracttrace.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 wrapperreturn decoratorclass TestFlow(tornado.web.RequestHandler):def get(self):views(self.request.headers)self.finish('hello world')@traced("phase-3")
def views(headers):passdef 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 requestsclass 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.webclass TestFlow(tornado.web.RequestHandler):def get(self):views()self.finish('hello world')def views():passdef 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 OTLPSpanExportertrace.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注入

联系我

  • 联系我,做深入的交流

至此,本文结束
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

本文来自博客园,作者:it排球君,转载请注明原文链接:https://www.cnblogs.com/MrVolleyball/p/19212863

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。

相关新闻

  • 开源方案RuoYi-Cloud-Plus详解——公网内网穿透到虚拟机环境(持续更新)
  • Elasticsearch 集群为所有分片(主分片和副本分片)进行分配,恢复正常分片调度行为
  • Pyodide 环境

最新新闻

  • Windows老游戏终极兼容解决方案:dxwrapper完全指南
  • 编写自定义脚本来自动化 vLLM 部署流程
  • 宣城市宁国吃正宗皖南徽菜 + 宁国农家土菜推荐去哪家? - 速递信息
  • 武汉买猫买狗去哪看?梦宠山庄实地体验分享 - 园友3800037
  • 从零到一:Jetlinks物联网平台服务器部署实战与避坑指南
  • (转)一次ANSYS EM 2023R1 “Request name electronics_desktop does not exist in the licensing pool.“的离谱解决记录

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号