yingjie@memoir
Skip to content

手动插桩

trace_utils.py

定义了两个函数,一个是创建数据处理管道,一个是创建tracer。tracer将用于产生span。 在这里使用了SDK和API,SDK是遥测数据处理的实现,API则是被开发者调用来产生span的。

python
# OTel API
from opentelemetry import trace as trace_api

# OTel SDK
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, BatchSpanProcessor

from resource_utils import create_resource

def create_tracing_pipeline()-> BatchSpanProcessor:
    # write spans straight to console (stdout)
    console_exporter = ConsoleSpanExporter()
    # push spans to one or more SpanExporters
    span_processor = BatchSpanProcessor(console_exporter)
    return span_processor
  

# function to create a tracer with the given name and version
def create_tracer(name:str, version:str)->trace_api.Tracer:
    provider = TracerProvider(
        resource=create_resource(name, version)
    )
    provider.add_span_processor(create_tracing_pipeline())
    trace_api.set_tracer_provider(provider)
    tracer = trace_api.get_tracer(name, version)
    return tracer

resource_utils.py

定义了资源的属性,方便辨识遥测信号的来源。这里使用了Semantic Convention来遵循标准并避免拼写错误。

python
from opentelemetry.sdk.resources import Resource
from opentelemetry.semconv.resource import ResourceAttributes

def create_resource(name: str, version: str) -> Resource:
    svc_resource = Resource.create(
        {
            ResourceAttributes.SERVICE_NAME: name,
            ResourceAttributes.SERVICE_VERSION: version
        }
    )
    return svc_resource

app.py

对Flask的端点“/”对应的函数index进行插桩。

先使用tracer装饰器,这样可以自动处理span的创建、开始和结束。 在index函数内部使用get_current_span方法获取当前环境中的span,为这个span设置属性,设置属性的时候使用Semantic Convention提供的属性名。

python
@app.route("/")
@tracer.start_as_current_span("index")
def index():
    span = trace_api.get_current_span()
    span.set_attributes(
        {
            SpanAttributes.HTTP_METHOD: request.method,
            SpanAttributes.URL_PATH: request.path,
            SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200,
        }
    )
    do_stuff()
    current_time = time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime())
    return f"Hello, World! It's currently {current_time}"

如何在不同应用中传递OTel的Context? 当一个请求经过不同的服务,用traceid来标识它,将traceid放到请求的header里,下一个服务收到请求的时候从header提取traceid使用OTel提供的attach方法来设置Context,当此请求在当前服务结束后使用deatach方法取消销毁Context?

python
from flask import Flask, make_response, request

from trace_utils import create_tracer
from opentelemetry import trace as trace_api
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry import context
from opentelemetry.propagate import inject,extract

@app.teardown_request
def teardown_request_func(err):
    previous_context = request.environ.get("previous_ctx_token",None)
    if previous_context:
        context.detach(previous_context)

  

@app.before_request
def before_request_func():
    ctx = extract(request.headers)
    previous_ctx = context.attach(ctx)
    request.environ["previous_ctx_token"] = previous_ctx

  
@app.route("/users", methods=["GET"])
@tracer.start_as_current_span("users")
def get_user():
    user, status = db.get_user(123)
    data = {}
    if user is not None:
        data = {"id": user.id, "name": user.name, "address": user.address}
    response = make_response(data, status)
    return response