OpenTracing Python:分布式追踪的标准 API

OpenTracing 的 Python 实现 opentracing-python,目前收获了 750 Star:

正文顶部截图

README区域截图

这个项目是 OpenTracing 组织维护的 Python 平台 API,为分布式追踪提供了一套标准化的接口。当前版本主要提供 API 定义和一个基础的 no-op 实现,让各类 instrumentation 库能够基于统一的接口来收集和传播分布式追踪上下文,而不需要绑定到具体的追踪后端。

在微服务架构中,一个用户请求往往会流经多个服务。如果没有追踪机制,定位性能瓶颈或排查故障将变得极为困难。OpenTracing 正是为了解决这一问题而设计的开放标准,而 opentracing-python 则是该标准在 Python 生态中的具体落地。

项目的核心工作围绕三个环节展开:

  1. 接收请求时,通过 inject/extract API 延续已有的追踪链路,创建 Span 对象
  2. 处理请求时,将当前 Span 存入请求本地的存储中,供后续创建子 Span 时取用
  3. 发起请求时,从本地存储取出当前 Span,创建子 Span,并通过 inject/extract API 将其嵌入到出站请求中

入站请求处理

服务端收到请求时的典型处理逻辑:

def handle_request(request):
    span = before_request(request, opentracing.global_tracer())
    with tracer.scope_manager.activate(span, True) as scope:
        handle_request_for_real(request)

def before_request(request, tracer):
    span_context = tracer.extract(
        format=Format.HTTP_HEADERS,
        carrier=request.headers,
    )
    span = tracer.start_span(
        operation_name=request.operation,
        child_of=span_context)
    span.set_tag('http.url', request.full_url)

    remote_ip = request.remote_ip
    if remote_ip:
        span.set_tag(tags.PEER_HOST_IPV4, remote_ip)

    return span

这里的关键是从请求头中提取 span_context。如果请求中已存在活跃追踪,则延续该追踪;否则启动新的根 Span。

出站请求处理

服务向其他服务发起调用时,需要创建子 Span 并将追踪上下文传递出去:

def before_http_request(request, current_span_extractor):
    parent_span = current_span_extractor()
    outbound_span = opentracing.global_tracer().start_span(
        operation_name=request.operation,
        child_of=parent_span
    )
    outbound_span.set_tag('http.url', request.full_url)

    http_header_carrier = {}
    opentracing.global_tracer().inject(
        span_context=outbound_span.context,
        format=Format.HTTP_HEADERS,
        carrier=http_header_carrier)

    for key, value in http_header_carrier.iteritems():
        request.add_header(key, value)

    return outbound_span

Scope 与进程内传播

OpenTracing 要求每个 Tracer 都包含一个 ScopeManager,用于管理当前活跃的 Span。Scope 可以通过上下文管理器自动注册和清理:

with tracer.start_active_span('someWork', finish_on_close=True) as scope:
    # 执行业务逻辑

如果需要手动管理 Scope:

span = tracer.start_span(operation_name='someWork')
scope = tracer.scope_manager.activate(span, True)
try:
    # 执行业务逻辑
except Exception as e:
    span.set_tag('error', '...')
finally:
    scope.close()

多框架支持

项目内置了多种 ScopeManager 实现,覆盖不同的异步框架:

from opentracing.scope_managers import ThreadLocalScopeManager
from opentracing.scope_managers.gevent import GeventScopeManager
from opentracing.scope_managers.tornado import TornadoScopeManager
from opentracing.scope_managers.asyncio import AsyncioScopeManager
from opentracing.scope_managers.contextvars import ContextVarsScopeManager

对于 asyncio 应用,推荐使用 ContextVarsScopeManager。相比 AsyncioScopeManager,它能自动将父 Span 传播到子协程、任务或回调中。

测试支持

项目还提供了 MockTracer 用于单元测试,无需接入真实的追踪后端即可验证 instrumentation 逻辑:

from opentracing.mocktracer import MockTracer

tracer = MockTracer()
with tracer.start_span('someWork') as span:
    pass

spans = tracer.finished_spans()

opentracing-python 作为 OpenTracing 规范在 Python 生态中的官方实现,为构建可观测的分布式系统提供了基础层接口。instrumentation 库可以基于此 API 开发,而应用开发者则可以自由选择后端追踪系统。

ntracing-python` 作为 OpenTracing 规范在 Python 生态中的官方实现,为构建可观测的分布式系统提供了基础层接口。instrumentation 库可以基于此 API 开发,而应用开发者则可以自由选择后端追踪系统。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。