手动仪表化

OpenTelemetry C++ 的手动仪表化

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.

设置

按照 入门指南 中的说明来构建 OpenTelemetry C++。

跟踪

初始化跟踪

auto provider = opentelemetry::trace::Provider::GetTracerProvider();
auto tracer = provider->GetTracer("foo_library", "1.0.0");

第一步获取的 TracerProvider 是一个单例对象,通常由 OpenTelemetry C++ SDK 提供。它用于为 API 接口提供具体的实现。如果没有使用 SDK,API 将提供一个默认的空操作 TracerProvider 的实现。

第二步获取的 Tracer 用于创建和启动 Spans。

启动 Span

auto span = tracer->StartSpan("HandleRequest");

这将创建一个 span,将其名字设置为 "HandleRequest",并将其开始时间设置为当前时间。请参考 API 文档以了解其他可以使用的操作,以便通过附加数据丰富 spans。

将 span 标记为活动的

auto scope = tracer->WithActiveSpan(span);

这将标记一个 span 为活动 span,并返回一个 Scope 对象。该 scope 对象控制 span 的活动时间。span 会在 scope 对象的生命周期内保持活动状态。

活动 span 的概念很重要,因为在没有显式指定父 span 的情况下,任何创建的 span 都将作为当前活动 span 的子 span。没有父 span 的 span 称为根 span。

创建嵌套的 Spans

auto outer_span = tracer->StartSpan("Outer operation");
auto outer_scope = tracer->WithActiveSpan(outer_span);
{
    auto inner_span = tracer->StartSpan("Inner operation");
    auto inner_scope = tracer->WithActiveSpan(inner_span);
    // ... 执行内部操作
    inner_span->End();
}
// ... 执行外部操作
outer_span->End();

Spans 可以嵌套,并与其他 spans 之间存在父子关系。当一个给定的 span 处于活动状态时,新创建的 span 继承了活动 span 的跟踪 ID 和其他上下文属性。

上下文传播

// 设置全局的传播器
opentelemetry::context::propagation::GlobalTextMapPropagator::SetGlobalPropagator(
    nostd::shared_ptr<opentelemetry::context::propagation::TextMapPropagator>(
        new opentelemetry::trace::propagation::HttpTraceContext()));

// 获取全局的传播器
HttpTextMapCarrier<opentelemetry::ext::http::client::Headers> carrier;
auto propagator =
    opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator();

// 注入上下文到头部
auto current_ctx = opentelemetry::context::RuntimeContext::GetCurrent();
propagator->Inject(carrier, current_ctx);

// 从头部提取上下文
auto current_ctx = opentelemetry::context::RuntimeContext::GetCurrent();
auto new_context = propagator->Extract(carrier, current_ctx);
auto remote_span = opentelemetry::trace::propagation::GetSpan(new_context);

Context 包含当前活动 Span 的元数据,包括 Span ID、Trace ID 和标志位。上下文传播是分布式跟踪中的一种重要机制,用于通过 HTTP 头部在服务边界之间传递这个上下文。OpenTelemetry 使用基于文本的方法,通过 W3C Trace Context HTTP 头部传播上下文。

进一步阅读

指标

初始化导出器和读取器

初始化一个导出器和一个读取器。在这个例子中,我们初始化一个默认打印到标准输出的 OStream 导出器。读取器会定期从聚合存储中收集指标并进行导出。

std::unique_ptr<opentelemetry::sdk::metrics::MetricExporter> exporter{new opentelemetry::exporters::OStreamMetricExporter};
std::unique_ptr<opentelemetry::sdk::metrics::MetricReader> reader{
    new opentelemetry::sdk::metrics::PeriodicExportingMetricReader(std::move(exporter), options)};

初始化 Meter 提供程序

初始化一个 Meter 提供程序并添加读取器。我们将在未来使用它来获取 Meter 对象。

auto provider = std::shared_ptr<opentelemetry::metrics::MeterProvider>(new opentelemetry::sdk::metrics::MeterProvider());
auto p = std::static_pointer_cast<opentelemetry::sdk::metrics::MeterProvider>(provider);
p->AddMetricReader(std::move(reader));

创建计数器

从 Meter 创建一个 Counter 仪表,并记录测量值。每个 MeterProvider 返回的 Meter 指针指向同一个 Meter。这意味着 Meter 可以将从不同函数捕获的指标进行合并,而不必不断地将 Meter 传递给库。

auto meter = provider->GetMeter(name, "1.2.0");
auto double_counter = meter->CreateDoubleCounter(counter_name);
// 创建一个标签集来注释度量指标的值
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
double_counter->Add(val, labelkv);

创建直方图

从 Meter 创建一个 Histogram 仪表,并记录测量值。

auto meter = provider->GetMeter(name, "1.2.0");
auto histogram_counter = meter->CreateDoubleHistogram("histogram_name");
histogram_counter->Record(val, labelkv);

创建可观测的计数器

从 Meter 创建一个可观测的计数器仪表,并添加回调函数。回调函数用于在度量统计期间记录测量值。确保在统计期间保持 Instrument 对象处于活动状态。

auto meter = provider->GetMeter(name, "1.2.0");
auto counter = meter->CreateDoubleObservableCounter(counter_name);
counter->AddCallback(MeasurementFetcher::Fetcher, nullptr);

创建 View

将计数器仪表映射到 Sum 聚合

创建一个视图,将计数器仪表映射到 Sum 聚合。将此视图添加到提供程序中。视图的创建是可选的,除非我们想要添加自定义的聚合配置和属性处理器。度量 SDK 将隐式创建一个缺失的视图,以在仪表和聚合之间进行默认映射。

std::unique_ptr<opentelemetry::sdk::metrics::InstrumentSelector> instrument_selector{
    new opentelemetry::sdk::metrics::InstrumentSelector(opentelemetry::sdk::metrics::InstrumentType::kCounter, "counter_name")};
std::unique_ptr<opentelemetry::sdk::metrics::MeterSelector> meter_selector{
    new opentelemetry::sdk::metrics::MeterSelector(name, version, schema)};
std::unique_ptr<opentelemetry::sdk::metrics::View> sum_view{
    new opentelemetry::sdk::metrics::View{name, "description", opentelemetry::sdk::metrics::AggregationType::kSum}};
p->AddView(std::move(instrument_selector), std::move(meter_selector), std::move(sum_view));

将直方图仪表映射到直方图聚合

std::unique_ptr<opentelemetry::sdk::metrics::InstrumentSelector> histogram_instrument_selector{
    new opentelemetry::sdk::metrics::InstrumentSelector(opentelemetry::sdk::metrics::InstrumentType::kHistogram, "histogram_name")};
std::unique_ptr<opentelemetry::sdk::metrics::MeterSelector> histogram_meter_selector{
    new opentelemetry::sdk::metrics::MeterSelector(name, version, schema)};
std::unique_ptr<opentelemetry::sdk::metrics::View> histogram_view{
    new opentelemetry::sdk::metrics::View{name, "description", opentelemetry::sdk::metrics::AggregationType::kHistogram}};
p->AddView(std::move(histogram_instrument_selector), std::move(histogram_meter_selector),
    std::move(histogram_view));

将可观测的计数器仪表映射到 Sum 聚合

std::unique_ptr<opentelemetry::sdk::metrics::InstrumentSelector> observable_instrument_selector{
    new opentelemetry::sdk::metrics::InstrumentSelector(opentelemetry::sdk::metrics::InstrumentType::kObservableCounter,
                                     "observable_counter_name")};
std::unique_ptr<opentelemetry::sdk::metrics::MeterSelector> observable_meter_selector{
  new opentelemetry::sdk::metrics::MeterSelector(name, version, schema)};
std::unique_ptr<opentelemetry::sdk::metrics::View> observable_sum_view{
  new opentelemetry::sdk::metrics::View{name, "description", opentelemetry::sdk::metrics::AggregationType::kSum}};
p->AddView(std::move(observable_instrument_selector), std::move(observable_meter_selector),
         std::move(observable_sum_view));

进一步阅读

日志

日志 API 和 SDK 目前正在开发中。

下一步

您还需要配置一个适当的导出器来将您的遥测数据导出到一个或多个遥测后端。请参阅 配置导出器

最后修改 December 13, 2023: improve glossary translation (46f8201b)