本文介绍通过OpenTelemetry Python SDK将Python应用的Trace数据接入到日志服务的操作步骤。
前提条件
- 已创建Trace实例。更多信息,请参见创建Trace实例。
已安装Python 3.7及以上版本。
已在Python上安装OpenTelemetry Python SDK。
如果未安装,可使用以下命令进行安装。
pip install opentelemetry-api==1.12.0 pip install opentelemetry-sdk==1.12.0 pip install opentelemetry-exporter-otlp==1.12.0
接入流程
初始化OpenTelemetry Provider。
判断是否符合半自动接入条件。
如果符合,则您可以使用半自动方式接入Trace数据。
当半自动方式无法覆盖您的所有场景时,余下场景您需要使用手动方式接入Trace数据。
如果不符合,则您可以使用手动方式接入Trace数据。
步骤1:初始化OpenTelemetry Provider
您可以通过如下代码完成OpenTelemetry Provider的初始化。其中,代码中的变量需根据实际情况替换。关于变量的详细说明,请参见变量说明。
# For Opentelemetry
import socket
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
class OpenTelemetrySLSProvider(object):
def __init__(self, namespace="", service="", version="", endpoint='stdout',
project=None, instance=None, access_key_id=None, access_key_secret=None):
'''
:param namespace: Your service namespace
:param service: Your Application Service Name
:param version: Your Application Version
:param endpoint: console or https://sls_endpoint:10010
:param project: SLS project
:param instance: SLS OTEL InstanceId
:param access_key_id: Aliyun AccesskeyId
:param access_key_secret: Aliyun AccesskeySecret
'''
self.sls_otel_endpoint = endpoint
self.sls_otel_project = project
self.sls_otel_akid = access_key_id
self.sls_otel_aksecret = access_key_secret
self.sls_otel_instanceid = instance
self.local_mode = False
if endpoint == "stdout":
self.local_mode = True
self.resource = Resource(attributes={
"host.name": socket.gethostname(),
"service.name": service,
"service.namespace": namespace,
"service.version": version})
else:
self.resource = Resource(attributes={
"host.name": socket.gethostname(),
"service.namespace": namespace,
"service.name": service,
"service.version": version,
"sls.otel.project": self.sls_otel_project,
"sls.otel.akid": self.sls_otel_akid,
"sls.otel.aksecret": self.sls_otel_aksecret,
"sls.otel.instanceid": self.sls_otel_instanceid
})
def initTracer(self):
trace.set_tracer_provider(TracerProvider(resource=self.resource))
if self.local_mode:
trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
else:
otlp_exporter = OTLPSpanExporter(endpoint=self.sls_otel_endpoint)
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(otlp_exporter))
# debug mode
#sls_ot_provider = OpenTelemetrySLSProvider(service="example", version="v0.1.0")
# write to sls
sls_ot_provider = OpenTelemetrySLSProvider(namespace="${service.namespace}", service="${service}", version="${version}",
endpoint='${endpoint}',
project="${project}",
instance="${instance}",
access_key_id="${access-key-id}",
access_key_secret="${access-key-secret}"
)
表 1. 变量说明
变量 | 说明 | 示例 |
${service.namespace} | 服务归属的命名空间。 | order |
${service} | 服务名。根据您的实际场景取值即可。 | payment |
${version} | 服务版本号。建议按照va.b.c格式定义。 | v0.1.2 |
${endpoint} | 日志服务Project的接入地址,格式为https://${project}.${region-endpoint}:Port,其中:
说明
| https://test-project.cn-hangzhou.log.aliyuncs.com:10010 |
${project} | 日志服务Project名称。 | test-project |
${instance} | Trace服务实例ID。更多信息,请参见创建Trace实例。 | test-traces |
${access-key-id} | 阿里云账号AccessKey ID。 建议您使用只具备日志服务Project写入权限的RAM用户的AccessKey(包括AccessKey ID和AccessKey Secret)。授予RAM用户向指定Project写入数据权限的具体操作,请参见授权。如何获取AccessKey的具体操作,请参见访问密钥。 | 无 |
${access-key-secret} | 阿里云账号AccessKey Secret。 建议您使用只具备日志服务Project写入权限的RAM用户的AccessKey。 | 无 |
步骤2:接入数据
您可以通过半自动或手动方式接入Trace数据到日志服务。OpenTelemetry Python SDK提供多种类型的instrumentation包,支持常用框架的半自动埋点,如果您使用的是指定的instrumentation包,则支持通过半自动方式接入数据。
半自动埋点
此处以flask和requests为例。
安装instrumentation包。
pip install requests pip install flask pip install opentelemetry-instrumentation-flask pip install opentelemetry-instrumentation-requests
运行代码。
如下代码中的变量需根据实际情况替换。更多信息,请参见变量说明。
# for flask import flask import requests # for Opentelemetry instrumentation import socket from opentelemetry.instrumentation.flask import FlaskInstrumentor from opentelemetry.instrumentation.requests import RequestsInstrumentor # For Opentelemetry pip install opentelemetry-instrumentation-requests from opentelemetry import trace from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( OTLPSpanExporter, ) from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.sdk.trace.export import ConsoleSpanExporter from opentelemetry.sdk.trace.export import SimpleSpanProcessor class OpenTelemetrySLSProvider(object): def __init__(self, namespace="", service="", version="", endpoint='stdout', project=None, instance=None, access_key_id=None, access_key_secret=None): ''' :param namespace: Your service namespace :param service: Your Application Service Name :param version: Your Application Version :param endpoint: console or https://sls_endpoint:10010 :param project: SLS project :param instance: SLS OTEL InstanceId :param access_key_id: Aliyun AccesskeyId :param access_key_secret: Aliyun AccesskeySecret ''' self.sls_otel_endpoint = endpoint self.sls_otel_project = project self.sls_otel_akid = access_key_id self.sls_otel_aksecret = access_key_secret self.sls_otel_instanceid = instance self.local_mode = False if endpoint == "stdout": self.local_mode = True self.resource = Resource(attributes={ "host.name": socket.gethostname(), "service.name": service, "service.namespace": namespace, "service.version": version}) else: self.resource = Resource(attributes={ "host.name": socket.gethostname(), "service.name": service, "service.version": version, "service.namespace": namespace, "sls.otel.project": self.sls_otel_project, "sls.otel.akid": self.sls_otel_akid, "sls.otel.aksecret": self.sls_otel_aksecret, "sls.otel.instanceid": self.sls_otel_instanceid }) def initTracer(self): trace.set_tracer_provider(TracerProvider(resource=self.resource)) if self.local_mode: trace.get_tracer_provider().add_span_processor( SimpleSpanProcessor(ConsoleSpanExporter())) else: otlp_exporter = OTLPSpanExporter(endpoint=self.sls_otel_endpoint) trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(otlp_exporter)) # write to sls sls_ot_provider = OpenTelemetrySLSProvider(namespace="${service.namespace}", service="${service}", version="${version}", endpoint='${endpoint}', project="${project}", instance="${instance}", access_key_id="${access-key-id}", access_key_secret="${access-key-secret}" ) # for console debug #sls_ot_provider = OpenTelemetrySLSProvider(service="example", version="v0.1.0") sls_ot_provider.initTracer() # flask init app = flask.Flask(__name__) # instrumentation init FlaskInstrumentor().instrument_app(app) RequestsInstrumentor().instrument() @app.route("/") def hello(): tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("request_server"): requests.get("http://www.taobao.com") return "hello" app.run(debug=True, port=5000)
访问服务,触发Trace数据生成并发送。
127.0.0.1:5000/hello
手动埋点
运行如下代码,其中代码中的变量需根据实际情况替换。关于代码的详细说明,请参见变量说明。
# ot-manual-example.py import time # For Opentelemetry import socket from opentelemetry import trace from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.sdk.trace.export import ConsoleSpanExporter from opentelemetry.sdk.trace.export import SimpleSpanProcessor class OpenTelemetrySLSProvider(object): def __init__(self, namespace="", service="", version="", endpoint='stdout', project=None, instance=None, access_key_id=None, access_key_secret=None): ''' :param service: Your service namespace :param service: Your Application Service Name :param version: Your Application Version :param endpoint: console or https://sls_endpoint:10010 :param project: SLS project :param instance: SLS OTEL InstanceId :param access_key_id: Aliyun AccesskeyId :param access_key_secret: Aliyun AccesskeySecret ''' self.sls_otel_endpoint = endpoint self.sls_otel_project = project self.sls_otel_akid = access_key_id self.sls_otel_aksecret = access_key_secret self.sls_otel_instanceid = instance self.local_mode = False if endpoint == "stdout": self.local_mode = True self.resource = Resource(attributes={ "host.name": socket.gethostname(), "service.name": service, "service.namespace": namespace, "service.version": version}) else: self.resource = Resource(attributes={ "host.name": socket.gethostname(), "service.name": service, "service.version": version, "service.namespace": namespace, "sls.otel.project": self.sls_otel_project, "sls.otel.akid": self.sls_otel_akid, "sls.otel.aksecret": self.sls_otel_aksecret, "sls.otel.instanceid": self.sls_otel_instanceid }) def initTracer(self): trace.set_tracer_provider(TracerProvider(resource=self.resource)) if self.local_mode: trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter())) else: otlp_exporter = OTLPSpanExporter(endpoint=self.sls_otel_endpoint) trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(otlp_exporter)) # write to sls sls_ot_provider = OpenTelemetrySLSProvider(namespace="${service.namespace}", service="${service}", version="${version}", endpoint='${endpoint}', project="${project}", instance="${instance}", access_key_id="${access-key-id}", access_key_secret="${access-key-secret}" ) # for console debug #sls_ot_provider = OpenTelemetrySLSProvider(service="example", version="v0.1.0") # Trace Example sls_ot_provider.initTracer() tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("foo"): print("Hello world!") labels = {"environment": "staging"} time.sleep(60)
常见问题
如何检查是否正确安装OpenTelemetry SDK?
以如下代码为例,将如下代码保存为tracing.py,执行tracing.py命令,如果正常输出则表示Python OpenTelemetry相关的基础依赖安装正确。
# tracing-example-1.py
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
ConsoleSpanExporter,
SimpleSpanProcessor,
)
trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(
SimpleSpanProcessor(ConsoleSpanExporter())
)
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("foo"):
print("Hello world!")