跳转到主要内容

Python的OpenTracing API。请参阅http://opentracing.io上的文档

项目描述

GitterChat BuildStatus PyPI Documentation Status

此库是OpenTracing的Python平台API。

阅读要求

为了理解Python平台API,必须首先熟悉OpenTracing项目和更具体术语

状态

在当前版本中,opentracing-python仅提供API和基本no-op实现,该实现可用于由仪器库收集和传播分布式跟踪上下文。

未来版本将包括一个使用抽象的Recorder接口的参考实现,以及一个与Zipkin兼容的Tracer。

用法

仪器库的工作通常包括三个步骤

  1. 当一个服务接收到一个新的请求(通过HTTP或其他协议),它使用OpenTracing的inject/extract API来继续一个活动跟踪,在这个过程中创建一个Span对象。如果请求不包含活动跟踪,服务将启动一个新的跟踪和一个新的 Span。

  2. 服务需要将当前Span存储在某种请求局部存储中,(称为Span 激活),在创建子Span时可以从中检索,例如在服务向另一个服务进行RPC调用的情况下。

  3. 在调用其他服务时,必须从请求局部存储中检索当前Span,创建一个子Span(例如,通过使用start_child_span()辅助函数),然后通过OpenTracing的inject/extract API将该子Span嵌入到出站请求中(例如,使用HTTP头)。

以下是对之前提到的步骤的代码示例。第2步所需的请求局部存储的具体实现取决于服务及其使用的框架/仪器库,作为ScopeManager的子项包含在Tracer.scope_manager中。详细信息见下文。

入站请求

在你的服务器请求处理程序代码中的某个地方

def handle_request(request):
    span = before_request(request, opentracing.global_tracer())
    # store span in some request-local storage using Tracer.scope_manager,
    # using the returned `Scope` as Context Manager to ensure
    # `Span` will be cleared and (in this case) `Span.finish()` be called.
    with tracer.scope_manager.activate(span, True) as scope:
        # actual business logic
        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)

    caller_name = request.caller_name
    if caller_name:
        span.set_tag(tags.PEER_SERVICE, caller_name)

    remote_port = request.remote_port
    if remote_port:
        span.set_tag(tags.PEER_PORT, remote_port)

    return span

出站请求

在你的服务中,即将进行出站调用的某个地方

from opentracing import tags
from opentracing.propagation import Format
from opentracing_instrumentation import request_context

# create and serialize a child span and use it as context manager
with before_http_request(
    request=out_request,
    current_span_extractor=request_context.get_current_span):

    # actual call
    return urllib2.urlopen(request)


def before_http_request(request, current_span_extractor):
    op = request.operation
    parent_span = current_span_extractor()
    outbound_span = opentracing.global_tracer().start_span(
        operation_name=op,
        child_of=parent_span
    )

    outbound_span.set_tag('http.url', request.full_url)
    service_name = request.service_name
    host, port = request.host_port
    if service_name:
        outbound_span.set_tag(tags.PEER_SERVICE, service_name)
    if host:
        outbound_span.set_tag(tags.PEER_HOST_IPV4, host)
    if port:
        outbound_span.set_tag(tags.PEER_PORT, port)

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

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

    return outbound_span

作用域和进程内传播

为了在使用的请求局部存储中获取/设置当前活动Span,OpenTracing要求每个Tracer都包含一个ScopeManager,它通过Scope提供对活动Span的访问。任何Span都可以转移到另一个任务或线程,但不能是Scope

# Access to the active span is straightforward.
scope = tracer.scope_manager.active()
if scope is not None:
    scope.span.set_tag('...', '...')

常见情况是启动一个Scope,它通过ScopeManager自动注册为进程内传播。

请注意,start_active_span('...')Scope.close()时会自动完成span(与start_active_span('...', finish_on_close=False)不同,它不会完成)。

# Manual activation of the Span.
span = tracer.start_span(operation_name='someWork')
with tracer.scope_manager.activate(span, True) as scope:
    # Do things.

# Automatic activation of the Span.
# finish_on_close is a required parameter.
with tracer.start_active_span('someWork', finish_on_close=True) as scope:
    # Do things.

# Handling done through a try construct:
span = tracer.start_span(operation_name='someWork')
scope = tracer.scope_manager.activate(span, True)
try:
    # Do things.
except Exception as e:
    span.set_tag('error', '...')
finally:
    scope.close()

如果有作用域,它将作为任何新启动的Span的父级,除非程序员在start_span()/start_active_span()时传递ignore_active_span=True或明确指定父级上下文

scope = tracer.start_active_span('someWork', ignore_active_span=True)

每个服务/框架都应该提供一个特定的ScopeManager实现,它依赖于自己的请求局部存储(线程局部存储,或适用于异步框架的基于协程的存储等)。

作用域管理器

此项目在opentracing.scope_managers子模块中包含一系列ScopeManager实现,可以根据需要导入

from opentracing.scope_managers import ThreadLocalScopeManager

存在针对thread-localopentracing.scope_managers子模块的默认实例)、geventTornadoasynciocontextvars的实现

from opentracing.scope_managers.gevent import GeventScopeManager # requires gevent
from opentracing.scope_managers.tornado import TornadoScopeManager # requires tornado<6
from opentracing.scope_managers.asyncio import AsyncioScopeManager # fits for old asyncio applications, requires Python 3.4 or newer.
from opentracing.scope_managers.contextvars import ContextVarsScopeManager # for asyncio applications, requires Python 3.7 or newer.

注意,对于asyncio应用程序,由于自动将父span传播到子协程、任务或计划好的回调,因此最好使用ContextVarsScopeManager而不是AsyncioScopeManager

开发

测试

virtualenv env
. ./env/bin/activate
make bootstrap
make test

您可以使用tox运行测试。

tox

测试平台套件

一个设计用于测试API更改和实验功能的测试平台套件包含在testbed目录下。有关更多信息,请参阅测试平台README

仪器测试

本项目已实现了OpenTracing API的接口设计。包含MockTracer,以方便对OpenTracing Python工具进行单元测试。

from opentracing.mocktracer import MockTracer

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

spans = tracer.finished_spans()
someWorkSpan = spans[0]

文档

virtualenv env
. ./env/bin/activate
make bootstrap
make docs

文档编写在 docs/_build/html

许可证

Apache 2.0 许可证.

发布

在新的版本发布之前,请将自上次版本以来的更改摘要添加到CHANGELOG.rst。

pip install zest.releaser[recommended]
prerelease
release
git push origin master --follow-tags
python setup.py sdist upload -r pypi upload_docs -r pypi
postrelease
git push

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源分发

opentracing-2.4.0.tar.gz (46.2 kB 查看哈希值)

上传时间

支持者: