本文介紹通過OpenTelemetry Python SDK將Python應用的Trace資料接入到Log Service的操作步驟。
前提條件
- 已建立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} | Log ServiceProject的接入地址,格式為https://${project}.${region-endpoint}:Port,其中:
說明
| https://test-project.cn-hangzhou.log.aliyuncs.com:10010 |
${project} | Log ServiceProject名稱。 | test-project |
${instance} | Trace服務執行個體ID。更多資訊,請參見建立Trace執行個體。 | test-traces |
${access-key-id} | 阿里雲帳號AccessKey ID。 建議您使用只具備Log ServiceProject寫入許可權的RAM使用者的AccessKey(包括AccessKey ID和AccessKey Secret)。授予RAM使用者向指定Project寫入資料許可權的具體操作,請參見授權。如何擷取AccessKey的具體操作,請參見存取金鑰。 | 無 |
${access-key-secret} | 阿里雲帳號AccessKey Secret。 建議您使用只具備Log ServiceProject寫入許可權的RAM使用者的AccessKey。 | 無 |
步驟2:接入資料
您可以通過半自動或手動方式接入Trace資料到Log Service。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!")