本文介紹通過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。
操作步驟
擷取opentelemetry-cpp原始碼。
$ cd <your-path> $ git clone --recurse-submodules https://github.com/open-telemetry/opentelemetry-cpp建立CMake build配置。
$ cd opentelemetry-cpp $ mkdir build && cd build && cmake ..構建CMake targets。
$ cmake --build . --target all安裝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變數 | 說明 | 樣本 |
| Log ServiceProject的接入地址,格式為
| test-project.cn-hangzhou.log.aliyuncs.com:10010 |
| Log ServiceProject名稱。 | test-project |
| Trace服務執行個體ID。更多資訊,請參見建立Trace執行個體。 | test-traces |
| 阿里雲帳號AccessKey ID。 | 無 |
| 阿里雲帳號AccessKey Secret。 重要 建議您使用只具備Log ServiceProject寫入許可權的RAM使用者的AccessKey。 | 無 |
| 服務歸屬的命名空間。 | order |
| 服務名。根據您的實際情境配置。 | payment |
| 服務版本號碼。建議按照va.b.c格式定義。 | v0.1.2 |
| 主機名稱。 | localhost |
| 部署環境。例如測試環境、生產環境。根據您的實際情境配置。 | 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::kUnset、trace::StatusCode::kOk、trace::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使用資訊,請參考官方文檔。