手动仪表化
Manual instrumentation is the act of adding observability code to an app yourself.
If you’re instrumenting an app, you need to use the OpenTelemetry SDK for your language. You’ll then use the SDK to initialize OpenTelemetry and the API to instrument your code. This will emit telemetry from your app, and any library you installed that also comes with instrumentation.
If you’re instrumenting a library, only install the OpenTelemetry API package for your language. Your library will not emit telemetry on its own. It will only emit telemetry when it is part of an app that uses the OpenTelemetry SDK. For more on instrumenting libraries, see Libraries.
For more information about the OpenTelemetry API and SDK, see the specification.
设置
首先,确保你安装了 API 和 SDK 包:
pip install opentelemetry-api
pip install opentelemetry-sdk
跟踪
获取跟踪器
要开始进行跟踪,您需要初始化一个 TracerProvider
,
并可选择将其设置为全局默认。
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
BatchSpanProcessor,
ConsoleSpanExporter,
)
provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
# 设置全局默认的跟踪器提供者
trace.set_tracer_provider(provider)
# 从全局跟踪器提供者创建一个跟踪器
tracer = trace.get_tracer("my.tracer.name")
创建跟踪
要创建一个跟踪,通常希望它作为当前跟踪开始。
def do_work():
with tracer.start_as_current_span("span-name") as span:
# 执行一些 span 将跟踪的工作
print("doing some work...")
# 当 'with' 代码块超出其作用域时,'span' 被关闭
您也可以使用 start_span
创建一个跟踪而不让其成为当前跟踪。这通常用于跟踪并发或异步操作。
创建嵌套跟踪
如果您有一个清晰的子操作需要作为另一个操作的一部分进行跟踪,可以创建代表关系的 跟踪。
def do_work():
with tracer.start_as_current_span("parent") as parent:
# 执行一些 parent 跟踪的工作
print("doing some work...")
# 创建一个以跟踪的形式跟踪嵌套工作
with tracer.start_as_current_span("child") as child:
# 执行一些 child 跟踪的工作
print("doing some nested work...")
# 当嵌套 span 超出其作用域时,它会被关闭
# 当此 span 超出其作用域时也会被关闭
当您在跟踪可视化工具中查看跟踪时,child
将作为一个嵌套在 parent
下的跟踪。
使用装饰器创建跟踪
通常使用一个跟踪来跟踪整个函数的执行。在这种情况下,有一个可以用来简化代码的装饰器:
@tracer.start_as_current_span("do_work")
def do_work():
print("doing some work...")
使用装饰器的效果等同于在 do_work()
函数内部创建跟踪,并在 do_work()
完成时结束跟踪。
要使用装饰器,您必须在函数声明的全局范围内可用的 tracer
实例。
获取当前跟踪
有时候,在某一时刻访问当前跟踪可能会有所帮助,以便你可以为其添加更多的信息。
from opentelemetry import trace
current_span = trace.get_current_span()
# 为 'current_span' 添加一些信息
向跟踪添加属性
属性允许您将键/值对附加到跟踪上,从而使其携带有关其正在跟踪的当前操作的更多信息。
from opentelemetry import trace
current_span = trace.get_current_span()
current_span.set_attribute("operation.value", 1)
current_span.set_attribute("operation.name", "Saying hello!")
current_span.set_attribute("operation.other-stuff", [1, 2, 3])
添加语义属性
语义属性是预定义的属性,是常见数据类型的公认命名约定。 使用语义属性可以在系统中规范化此类信息。
要在 Python 中使用语义属性,请确保已安装语义约定包:
pip install opentelemetry-semantic-conventions
然后可以在代码中使用它:
from opentelemetry import trace
from opentelemetry.semconv.trace import SpanAttributes
# ...
current_span = trace.get_current_span()
current_span.set_attribute(SpanAttributes.HTTP_METHOD, "GET")
current_span.set_attribute(SpanAttributes.HTTP_URL, "https://opentelemetry.io/")
添加事件
事件是在 跟踪 生命周期中表示"发生某事"的人类可读消息。可以将其视为原始日志。
from opentelemetry import trace
current_span = trace.get_current_span()
current_span.add_event("Gonna try it!")
# 做某事
current_span.add_event("Did it!")
添加链接
跟踪可以创建一个或多个与其他跟踪相关联的跟踪链接。链接需要一个跟踪上下文来创建。
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("span-1"):
# 做一些 'span-1' 跟踪的工作。
ctx = trace.get_current_span().get_span_context()
link_from_span_1 = trace.Link(ctx)
with tracer.start_as_current_span("span-2", links=[link_from_span_1]):
# 做一些 'span-2' 跟踪的工作。
# 'span-2' 中的链接与 'span-1' 相关联,但它们不是父子关系。
pass
设置跟踪状态
可以在跟踪上设置一个状态,
通常用于指定一个跟踪尚未成功完成 - StatusCode.ERROR
。
在极少数情况下,您可以使用 StatusCode.OK
覆盖错误状态,但不要将 StatusCode.OK
设置为已成功完成的跟踪。
可以在跟踪结束之前的任何时间设置状态:
from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode
current_span = trace.get_current_span()
try:
# 可能会发生错误的事情
except:
current_span.set_status(Status(StatusCode.ERROR))
在跟踪中记录异常
记录异常发生时的错误信息是一个好习惯。建议与设置跟踪状态一起使用。
from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode
current_span = trace.get_current_span()
try:
# 可能会发生错误的事情
# 在代码中,建议捕获一个更具体的异常
except Exception as ex:
current_span.set_status(Status(StatusCode.ERROR))
current_span.record_exception(ex)
更改默认的传播格式
默认情况下,OpenTelemetry Python 将使用以下传播格式:
- W3C Trace Context
- W3C Baggage
如果您需要更改默认值,可以通过环境变量或代码进行更改:
使用环境变量
您可以将 OTEL_PROPAGATORS
环境变量设置为以逗号分隔的列表。接受的值包括:
"tracecontext"
:W3C Trace Context"baggage"
:W3C Baggage"b3"
:B3 Single"b3multi"
:B3 Multi"jaeger"
:Jaeger"xray"
:AWS X-Ray(第三方)"ottrace"
:OT Trace(第三方)"none"
:不配置自动传播器。
默认配置等同于 OTEL_PROPAGATORS="tracecontext,baggage"
。
使用 SDK API
或者,您可以在代码中更改格式。
例如,如果您需要使用 Zipkin 的 B3 传播格式,可以安装 B3 包:
pip install opentelemetry-propagator-b3
然后在跟踪初始化代码中设置 B3 传播器:
from opentelemetry.propagate import set_global_textmap
from opentelemetry.propagators.b3 import B3Format
set_global_textmap(B3Format())
请注意,环境变量将覆盖代码中的配置。
更多阅读
指标
要开始收集指标,您需要初始化一个 MeterProvider
,
并可选择将其设置为全局默认。
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import (
ConsoleMetricExporter,
PeriodicExportingMetricReader,
)
metric_reader = PeriodicExportingMetricReader(ConsoleMetricExporter())
provider = MeterProvider(metric_readers=[metric_reader])
# 设置全局默认的 MeterProvider
metrics.set_meter_provider(provider)
# 从全局 MeterProvider 创建一个 Meter
meter = metrics.get_meter("my.meter.name")
创建和使用同步仪表
仪表被用于对应用程序进行测量。 同步仪表 与应用程序或业务处理逻辑一起使用,例如处理请求或调用其他服务时。
首先,创建您的仪表。通常,在模块或类级别创建仪表,然后在业务逻辑中与其一起使用。 以下示例使用 Counter 仪表来计算已完成的工作项数:
work_counter = meter.create_counter(
"work.counter", unit="1", description="计算完成的工作量"
)
使用 Counter 的 add 操作,下面的代码通过将工作项的类型作为属性来增加计数值。
def do_work(work_item):
# 计算正在处理的工作
work_counter.add(1, {"work.type": work_item.work_type})
print("doing some work...")
创建和使用异步仪表
异步仪表 允许用户注册回调函数,在需要时调用以进行测量。这对于周期性测量无法直接仪表化的值很有用。 异步仪表使用零个或多个回调函数创建,这些回调函数在度量收集期间将被调用。每个回调函数接受来自 SDK 的选项并返回自己的观测结果。
下面的示例使用异步仪表来报告通过 HTTP 端点从配置服务器获取的当前配置版本。 首先编写一个回调函数来进行观测:
from typing import Iterable
from opentelemetry.metrics import CallbackOptions, Observation
def scrape_config_versions(options: CallbackOptions) -> Iterable[Observation]:
r = requests.get(
"http://configserver/version_metadata", timeout=options.timeout_millis / 10**3
)
for metadata in r.json():
yield Observation(
metadata["version_num"], {"config.name": metadata["version_num"]}
)
请注意,OpenTelemetry 会将包含超时的选项传递给回调函数。回调函数应尊重此超时以避免无限期阻塞。最后,创建带有回调函数的仪表来注册它:
meter.create_observable_gauge(
"config.version",
callbacks=[scrape_config_versions],
description="每个配置的活动配置版本",
)
更多阅读
日志
日志的 API 和 SDK 目前正在开发中。
下一步
您还需要配置适当的导出器以将您的遥测数据导出到一个或多个遥测后端。