在追踪应用的链路数据之前,您需要通过客户端将应用数据上报至可观测链路 OpenTelemetry 版服务端。本文介绍如何通过OpenTelemetry Python SDK上报Python应用数据。

前提条件

获取接入点信息
  1. 登录可观测链路 OpenTelemetry 版控制台
  2. 在左侧导航栏单击集群配置,然后在右侧页面单击接入点信息页签。
  3. 在页面顶部选择需要接入的地域,然后在集群信息区域打开显示Token开关。
  4. 客户端采集工具区域单击OpenTelemetry
    在下方表格的相关信息列中,获取接入点信息。OT接入点信息
    说明 如果应用部署于阿里云生产环境,则选择阿里云VPC网络接入点,否则选择公网接入点。

示例Demo

示例代码仓库地址:python-opentelemetry-demo

方法一:手动埋点上报Python应用数据

  1. 下载所需包。
    pip install opentelemetry-api
    pip install opentelemetry-sdk
    pip install opentelemetry-exporter-otlp
  2. manual.py文件中设置OpenTelemetry初始化代码。
    • 请将代码中的<token><endpoint>替换成前提条件中获取的接入点信息。
    • 请根据实际情况替换代码中的<service-name>(服务名)和<host-name>(主机名)。
    from opentelemetry import trace, baggage
    from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter as OTLPSpanGrpcExporter
    from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter as OTLPSpanHttpExporter
    from opentelemetry.sdk.resources import SERVICE_NAME, Resource, HOST_NAME
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    
    def init_opentelemetry():
        # 设置服务名、主机名
        resource = Resource(attributes={
            SERVICE_NAME: "<service-name>",
            HOST_NAME: "<host-name>"
        })
        # 使用GRPC协议上报
        span_processor = BatchSpanProcessor(OTLPSpanGrpcExporter(
            endpoint="<endpoint>",
            headers=("Authentication=<token>")
        ))
        # 使用HTTP协议上报
        # span_processor = BatchSpanProcessor(OTLPSpanHttpExporter(
        #     endpoint="<endpoint>",
        # ))
        trace_provider = TracerProvider(resource=resource, active_span_processor=span_processor)
        trace.set_tracer_provider(trace_provider)
                            
  3. 创建Span。
    tracer = trace.get_tracer(__name__) # 获取tracer
    with tracer.start_as_current_span("child_span") as child_span: # 创建名为child_span的span
        print("hello world")
  4. 使用OpenTelemetry Baggage API透传业务自定义标签。
    创建baggage_parent_span时通过指定attributes参数来设置属性。
    def baggage_and_attribute_usage():
        tracer = trace.get_tracer(__name__)
        global_ctx = baggage.set_baggage("key", "value_from_global_ctx")  # 使用baggage api,在不同span之间传递数据
        with tracer.start_as_current_span(name='baggage_parent_span', attributes={'attribute_key': 'value'}) as baggage_parent_span:
            parent_ctx = baggage.set_baggage("key", "value_from_parent_ctx")
            with tracer.start_as_current_span(name='baggage_child_span', context=parent_ctx) as baggage_child_span:
                child_ctx = baggage.set_baggage("key", "value_from_child_ctx")
    
        # 获取不同contex下key对应的值
        print(baggage.get_baggage("key", global_ctx))
        print(baggage.get_baggage("key", parent_ctx))
        print(baggage.get_baggage("key", child_ctx))
    展开查看完整示例代码
    from opentelemetry import trace, baggage
    from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter as OTLPSpanGrpcExporter
    from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter as OTLPSpanHttpExporter
    from opentelemetry.sdk.resources import SERVICE_NAME, Resource, HOST_NAME
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    
    def inner_method():
        tracer = trace.get_tracer(__name__)
        with tracer.start_as_current_span("child_span") as child_span:
            print("hello world")
    
    
    def outer_method():
        tracer = trace.get_tracer(__name__)
        with tracer.start_as_current_span("parent_span") as parent_span:
            inner_method()
    
    def baggage_and_attribute_usage():
        tracer = trace.get_tracer(__name__)
        global_ctx = baggage.set_baggage("key", "value_from_global_ctx")  # 使用baggage api,在不同span之间传递数据
        with tracer.start_as_current_span(name='baggage_parent_span', attributes={'attribute_key': 'value'}) as baggage_parent_span:
            parent_ctx = baggage.set_baggage("key", "value_from_parent_ctx")
            with tracer.start_as_current_span(name='baggage_child_span', context=parent_ctx) as baggage_child_span:
                child_ctx = baggage.set_baggage("key", "value_from_child_ctx")
    
        print(baggage.get_baggage("key", global_ctx))
        print(baggage.get_baggage("key", parent_ctx))
        print(baggage.get_baggage("key", child_ctx))
    
    
    
    def init_opentelemetry():
        # 设置服务名、主机名
        resource = Resource(attributes={
            SERVICE_NAME: "<service-name>",
            HOST_NAME: "<host-name>"
        })
        # 使用GRPC协议上报
        span_processor = BatchSpanProcessor(OTLPSpanGrpcExporter(
            endpoint="<endpoint>",
            headers=("Authentication=<token>")
        ))
        # 使用HTTP协议上报
        # span_processor = BatchSpanProcessor(OTLPSpanHttpExporter(
        #     endpoint="<endpoint>",
        # ))
        trace_provider = TracerProvider(resource=resource, active_span_processor=span_processor)
        trace.set_tracer_provider(trace_provider)
    
    
    if __name__ == '__main__':
        init_opentelemetry()
        outer_method()
        baggage_and_attribute_usage()
  5. 运行程序。
    python manual.py

方法二:在Django应用中自动埋点并上报数据

  1. 下载所需包。
    pip install django
    pip install opentelemetry-sdk
    pip install opentelemetry-instrumentation-django
    pip install requests
  2. 创建HelloWorld应用。
    1. 在项目中创建helloworld文件夹。
      python manage.py startapp helloworld
    2. helloworld/views.py文件中添加以下代码。
      from django.http import HttpResponse
      from datetime import datetime
      
      # Create your views here.
      def hello_world_view(request):
          result = "Hello World! Current Time =" + str(get_time())
          return HttpResponse(result)
      
      def get_time():
          now = datetime.now()
          return now.strftime("%H:%M:%S")
    3. helloworld/urls.py文件中添加以下代码。
      from django.urls import path
      
      from . import views
      
      urlpatterns = [
          path('', views.hello_world_view, name='helloworld')
      ]
    4. 修改AutoAndManualDemo/urls.py文件,添加helloworld文件的路径。
      from django.contrib import admin
      from django.urls import path, include
      
      urlpatterns = [
          path('admin/', admin.site.urls),
          path('helloworld/', include('helloworld.urls')),
      ]
  3. 修改manage.py文件内容。
    1. 引入包。
      from opentelemetry.instrumentation.django import DjangoInstrumentor
    2. main方法中添加以下代码。
      DjangoInstrumentor().instrument()
  4. 运行项目。
    python manage.py runserver --noreload
    说明 --noreload参数用于防止manage.main方法执行两次。
    如果在运行时出现ImportError(symbol not found in flat namespace '_CFRelease')报错,请执行以下命令下载Grpcio包,然后重新运行项目。
    pip install grpcio

方法三:在自动埋点的基础上手动埋点

如果您需要在使用OpenTelemetry获得自动埋点能力的同时,添加自定义业务埋点,请在方法二的基础上完成以下操作。

  1. 下载包。
    pip install opentelemetry-exporter-otlp
  2. 修改manage.py文件,在应用初始化的代码中添加以下内容。
    • 请根据接入方式(gRPC或者HTTP)将代码中的<token><endpoint>替换成前提条件中获取的接入点信息。
    • 请根据实际情况替换代码中的<service-name>(服务名)和<host-name>(主机名)。
    from opentelemetry import trace
    from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter  # 通过gRPC接入
    # from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter # 通过HTTP接入
    from opentelemetry.sdk.resources import SERVICE_NAME, Resource, HOST_NAME
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
    
    
    
    resource = Resource(attributes={
            SERVICE_NAME: "<service-name>",
            HOST_NAME: "<host-name>"
    })
    trace.set_tracer_provider(TracerProvider(resource=resource))
    trace.get_tracer_provider().add_span_processor(
        BatchSpanProcessor(OTLPSpanExporter(
            endpoint="<endpoint>",
            headers="Authentication=<token>" # 通过gRPC接入时需要headers参数,通过HTTP接入时不需要此参数
    )))  # 通过 OTLPSpanExporter 上报Trace
    trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))  # 在控制台输出Trace
  3. 修改helloworld/views.py文件内容。
    获取Tracer并手动创建Span,同时设置Span名称。
    from django.http import HttpResponse
    from opentelemetry import trace
    from datetime import datetime
    
    
    # Create your views here.
    def hello_world_view(request):
        tracer = trace.get_tracer(__name__)
    
        with tracer.start_as_current_span("hello_world_span") as hello_world_span:
            result = "Hello World! Current Time =" + str(get_time())
            return HttpResponse(result)
    
    
    def get_time():
        now = datetime.now()
        tracer = trace.get_tracer(__name__)
        # 创建新的span
        with tracer.start_as_current_span("time_span") as time_span:
            return now.strftime("%H:%M:%S")
  4. 运行项目。
    python manage.py runserver --noreload
    说明 --noreload参数用于防止manage.main方法执行两次。
    如果在运行时出现ImportError(symbol not found in flat namespace '_CFRelease')报错,请执行以下命令下载Grpcio包,然后重新运行项目。
    pip install grpcio
  5. 在浏览器中访问127.0.0.1:8000/helloworld,链路数据便会上报至可观测链路 OpenTelemetry 版控制台。

查看监控数据

可观测链路 OpenTelemetry 版控制台应用列表页面选择目标应用,查看链路数据。