全部產品
Search
文件中心

Simple Log Service:通過OpenTelemetry接入C++ Trace資料

更新時間:Oct 25, 2024

本文介紹通過OpenTelemetry C++ SDK將C++應用的Trace資料接入到Log Service的操作步驟。

前提條件

  • 已建立Trace執行個體。更多資訊,請參見建立Trace執行個體

  • 已準備相關的開發環境,該環境需要支援編譯及運行Opentelemetry C++ SDK。

    • 如果您使用的是CMake編譯器,則其版本需為3.1及以上。

    • 如果您使用的是GCC或G++編譯器,則其版本需要為4.8及以上。

    • 如果您使用的是MSVC,則其版本需要為vs2015及以上(建議為vs2019)。

  • 支援的C++版本如下所示。

    • ISO/IEC 14882:2011 (C++11, C++0x)

    • ISO/IEC 14882:2014 (C++14, C++1y)

    • ISO/IEC 14882:2017 (C++17, C++1z)

    • ISO/IEC 14882:2020 (C++20)

  • 更多依賴及版本資訊,請參見opentelemetry-cpp

步驟一:SDK整合

您可以通過源碼或包管理器整合SDK。更多資訊,請參見Install opentelemetry-cpp

使用源碼整合(作為獨立的CMake專案編譯)

前提條件

  • 支援在Windows、macOS、Linux平台進行編譯。

  • 已安裝支援C++11及以上版本的C++編譯器。

  • 已安裝Git。

  • 已安裝CMake。

  • 已安裝GoogleTest。

  • 已安裝Google Benchmark。

操作步驟

  1. 擷取opentelemetry-cpp原始碼。

    $ cd <your-path>
    $ git clone --recurse-submodules https://github.com/open-telemetry/opentelemetry-cpp
  2. 建立CMake build配置。

    $ cd opentelemetry-cpp
    $ mkdir build && cd build && cmake ..
  3. 構建CMake targets。

    $ cmake --build . --target all
  4. 安裝API的標頭檔。

    $ cmake --install . --prefix /<install-root>/

使用源碼整合(整合到目標CMake專案中)

前置條件

  • 支援在Windows、macOS、Linux平台進行編譯。

  • 已安裝支援C++11及以上版本的C++編譯器。

  • 已安裝Git。

  • 已安裝CMake。

  • 已安裝GoogleTest。

  • 已安裝Google Benchmark。

程式碼範例

# CMakeLists.txt
find_package(opentelemetry-cpp CONFIG REQUIRED)
...
target_include_directories(foo PRIVATE ${OPENTELEMETRY_CPP_INCLUDE_DIRS})
target_link_libraries(foo PRIVATE ${OPENTELEMETRY_CPP_LIBRARIES})

使用包管理器整合

使用包管理器整合的方式請參見using package managers

步驟二:初始化SDK

初始化Opentelemetry C++ SDK後,您才能正常使用SDK。請按照如下操作,初始化SDK。

// 匯入以下標頭檔。
#include "opentelemetry/exporters/otlp/otlp_grpc_exporter_factory.h"
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/trace/provider.h"

#include "opentelemetry/sdk/trace/tracer_provider.h"

#include "opentelemetry/sdk/version/version.h"
#include "opentelemetry/trace/provider.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/resource/semantic_conventions.h"

namespace trace = opentelemetry::trace;
namespace trace_sdk = opentelemetry::sdk::trace;
namespace otlp = opentelemetry::exporter::otlp;
namespace resource = opentelemetry::sdk::resource;

namespace
{
		// 初始化Exporter。Exporter用於匯出Trace到Log ServiceLogstore。
    opentelemetry::exporter::otlp::OtlpGrpcExporterOptions opts;
    void InitTracer()
    {
        opts.endpoint = "https://${endpoint}";
        opts.use_ssl_credentials = true;
        opts.ssl_credentials_cacert_path = "<your root pem file path>"; // 需手動指定root pem檔案路徑。一般包含在grpc依賴庫路徑中。

        // Setup credentials info
        opts.metadata.insert(std::pair<std::string, std::string>("x-sls-otel-project", "${project}"));
        opts.metadata.insert(std::pair<std::string, std::string>("x-sls-otel-instance-id", "${instanceId}"));
        opts.metadata.insert(std::pair<std::string, std::string>("x-sls-otel-ak-id", "${access-key-id}"));
        opts.metadata.insert(std::pair<std::string, std::string>("x-sls-otel-ak-secret", "${access-key-secret}"));

        // Create OTLP exporter instance
        auto exporter = otlp::OtlpGrpcExporterFactory::Create(opts);
        auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter));

        // 初始化tracer provider。tracer provider用於暴露主要的API,對Span進行預先處理。
				// 自訂TraceId、SpanId建置規則,自訂採樣器等。您可以根據實際需要進行配置。
        resource::ResourceAttributes attributes = {
          {resource::SemanticConventions::kServiceName, "${service}"}, //一般為子模組名稱。
          {resource::SemanticConventions::kServiceNamespace, "${service.namespace}"}, //一般為模組或App名稱。
          {resource::SemanticConventions::kServiceVersion, "${version}"}, //一般為模組或App版本號碼。
          {resource::SemanticConventions::kHostName, "${host}"},
          {resource::SemanticConventions::kDeploymentEnvironment, "${environment}"}
        };
        auto resource = opentelemetry::sdk::resource::Resource::Create(attributes);

        std::shared_ptr<opentelemetry::trace::TracerProvider> provider =
            trace_sdk::TracerProviderFactory::Create(std::move(processor), std::move(resource));
        // Set the global trace provider
        trace::Provider::SetTracerProvider(provider);
    }

    void CleanupTracer()
    {
        // We call ForceFlush to prevent to cancel running exportings, It's optional.
        opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider> provider =
            trace::Provider::GetTracerProvider();
        if (provider)
        {
            static_cast<trace_sdk::TracerProvider*>(provider.get())->ForceFlush();
        }

        std::shared_ptr<opentelemetry::trace::TracerProvider> none;
        trace::Provider::SetTracerProvider(none);
    }
}  // namespace

變數

說明

樣本

${endpoint}

Log ServiceProject的接入地址,格式為${project}.${region-endpoint}:{Port}。詳細說明如下:

  • ${project}:Log ServiceProject名稱。

  • ${region-endpoint}:Log ServiceProject所在地區的訪問網域名稱,支援公網和阿里雲內網(傳統網路、VPC)。更多資訊,請參見服務入口

  • {Port}:網路連接埠,固定為10010。

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。

${service.namespace}

服務歸屬的命名空間。

order

${service}

服務名。根據您的實際情境配置。

payment

${version}

服務版本號碼。建議按照va.b.c格式定義。

v0.1.2

${host}

主機名稱。

localhost

${environment}

部署環境。例如測試環境、生產環境。根據您的實際情境配置。

pre

步驟三:使用SDK

建立Tracer

建議根據不同的業務情境建立Tracer。建立Tracer時需要傳入library name,利於按照library區分不同的Trace資料。

namespace trace = opentelemetry::trace;
namespace nostd = opentelemetry::nostd;

namespace
{
    nostd::shared_ptr<trace::Tracer> get_tracer()
    {
        auto provider = trace::Provider::GetTracerProvider();
        return provider->GetTracer("<your library name>", OPENTELEMETRY_SDK_VERSION);
    }
}  // namespace

建立基本Span

Span代表事務中的操作,每個Span都封裝了操作名稱、起止時間戳記、屬性資訊、事件資訊和Context資訊等。

auto span = get_tracer()->StartSpan("basic_f1");
// do your stuff
// ...
span->End();

建立嵌套Span

當您希望為嵌套操作關聯Span時,OpenTelemetry支援在進程內和跨遠程進程進行跟蹤。例如針對methodA調用methodB ,您可以通過以下方式建立嵌套Span。

void method_a() 
{
    auto span = get_tracer()->StartSpan("operation A");
    auto scope = get_tracer()->WithActiveSpan(span);

    method_b();

    span->End();
}

void method_b()
{
    auto span_child = get_tracer()->StartSpan("operation B");
    // do your stuff
    // ...
    span_child->End();
}

OpenTemetry API還提供了一種自動化的方式來傳播parentSpan,樣本如下:

void method_a() 
{
    auto scoped_span = trace::Scope(get_tracer()->StartSpan("operation A"));
    method_b();
}

void method_b()
{
    auto scoped_span = trace::Scope(get_tracer()->StartSpan("operation B"));
}

建立帶屬性的Span

您可以通過屬性在Span上提供特定操作的上下文資訊。例如執行結果、關聯的其他商務資訊等。

auto span = get_tracer()->StartSpan("<my operation>");
span->SetAttribute("age", 12);
span->SetAttribute("sex", "man");
// do your stuff
// ...
span->SetAttribute("height", 154.5);
span->End();

建立帶事件的Span

您可以通過攜帶多個事件的方式對Span進行注釋。

auto span = get_tracer()->StartSpan("<my operation>");
// do your stuff
// ...
span->AddEvent("message: success");
span->End();

給Span添加狀態

Span包含trace::StatusCode::kUnsettrace::StatusCode::kOktrace::StatusCode::kError三個狀態,分別表示預設狀態、成功狀態、操作包含錯誤。

auto span = get_tracer()->StartSpan("<my operation>");
// do your stuff
// ...
span->SetStatus(trace::StatusCode::kError);
span->End();

傳播上下文資訊

OpenTelemetry提供了一種基於文本的方法,傳播上下文資訊。

#include "opentelemetry/trace/context.h"
#include "opentelemetry/context/propagation/global_propagator.h"
#include "opentelemetry/context/propagation/text_map_propagator.h"
#include "opentelemetry/trace/propagation/http_trace_context.h"
#include "opentelemetry/nostd/shared_ptr.h"

// 以HttpTraceContext為例,示範context propagation的基本用法。
// 在SDK初始化時,完成global propagator配置。
opentelemetry::context::propagation::GlobalTextMapPropagator::SetGlobalPropagator(
    opentelemetry::nostd::shared_ptr<opentelemetry::context::propagation::TextMapPropagator>(
    new opentelemetry::trace::propagation::HttpTraceContext()));


// 在client側發起網路請求時,注入Header資訊。
opentelemetry::context::propagation::TextMapCarrier carrier; // 實際使用時,需要替換為目標TextMapCarrier。
auto propagator = opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator();

// 注入Header資訊。
auto current_ctx = opentelemetry::context::RuntimeContext::GetCurrent();
propagator->Inject(carrier, current_ctx);

// 在server側,提取Header資訊。
auto current_ctx = opentelemetry::context::RuntimeContext::GetCurrent();
auto new_context = propagator->Extract(carrier, current_ctx);
auto remote_span = opentelemetry::trace::GetSpan(new_context);

目前,OpenTelemetry SDK支援按照W3C Trace Context標準傳播上下文資訊。更多資訊,請參見W3CTraceContextPropagator類

更多OpenTelemetry SDK使用資訊,請參考官方文檔

後續步驟