Qt是一种跨平台的C++开发框架,可用于开发GUI、网络、数据库、OpenGL等应用程序。本文介绍如何在Qt跨平台项目中集成OpenTelemetry C++ SDK以采集Qt Trace数据。
前提条件
已创建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)
已安装Git版本控制工具。
更多依赖及版本信息,请参见opentelemetry-cpp。
步骤一:配置Visual Studio
为了使OpenTelemetry C++ SDK与Qt项目一起编译,需要将Qt的编译工具切换为MSVC,即需要在Visual Studio中安装Qt Visual Studio Tools插件。
在Visual Studio顶部菜单栏中,选择扩展>管理扩展,然后搜索Qt Visual Studio Tools。
单击Qt Visual Studio Tools对应的下载。
待插件下载完成后,关闭Visual Studio的所有窗口。
在自动弹出的VSIX Installer对话框中,单击Modify,插件会自动完成安装。
确认插件安装完成。
重新打开Visual Studio项目,如果扩展菜单下有Qt VS Tools选项,则表示Qt Visual Studio Tools插件安装成功。
关于Qt Visual Studio Tools的更多信息,请参见Qt Visual Studio Tools。
步骤二:集成SDK
opentelemetry-cpp项目的构建编译依赖CMake工具,即需要将Qt的编译构建工具切换为CMake。本文以opentelemetry-cpp 1.9.0版本为例。
(推荐)通过源码集成
将opentelemetry-cpp源码克隆到Qt项目所在的文件夹中。
$ cd <your qt project directory> $ git clone --recurse-submodules https://github.com/open-telemetry/opentelemetry-cpp
打开Qt项目的CMakeLists.txt文件,添加如下内容。
# CMakeLists.txt add_subdirectory(opentelemetry-cpp) ... target_include_directories(OTelExample4QT2 PRIVATE ${CMAKE_SOURCE_DIR}/opentelemetry-cpp/api/include PRIVATE ${CMAKE_SOURCE_DIR}/opentelemetry-cpp/sdk/include PRIVATE ${CMAKE_SOURCE_DIR}/opentelemetry-cpp/exporters/ostream/include PRIVATE ${CMAKE_SOURCE_DIR}/opentelemetry-cpp/exporters/otlp/include PRIVATE ${CMAKE_SOURCE_DIR}/opentelemetry-cpp/ext/include) target_link_libraries(OTelExample4QT2 PRIVATE Qt${QT_VERSION_MAJOR}::Widgets opentelemetry_trace opentelemetry_common opentelemetry_http_client_curl opentelemetry_exporter_ostream_span opentelemetry_exporter_in_memory opentelemetry_exporter_ostream_span opentelemetry_exporter_otlp_grpc opentelemetry_exporter_otlp_grpc_client opentelemetry_exporter_otlp_grpc_log opentelemetry_exporter_otlp_grpc_metrics opentelemetry_exporter_otlp_http opentelemetry_exporter_otlp_http_client opentelemetry_exporter_otlp_http_metric opentelemetry_metrics opentelemetry_http_client_curl opentelemetry_otlp_recordable opentelemetry_proto opentelemetry_resources opentelemetry_trace opentelemetry_version)
在目标项目的编译构建配置页面,单击Current Configuration,确认编译构建opentelemetry-cpp项目成功。
如果Configuration中出现opentelemetry-cpp相关的配置项(例如WITH_ABSEIL等),表示编译构建成功。
如果Configuration中没有出现opentelemetry-cpp相关的配置项,请在页面右侧选择添加 > Boolean,添加
BUILD_TESTING=OFF
,然后单击执行CMake。完成该操作后,如果仍然没有出现opentelemetry-cpp相关的配置项,建议您根据项目错误提示进行排查。
建议opentelemetry-cpp相关的CMake配置只做如下改动。其中c-ares_DIR、re2_DIR、gRPC_DIR、absl_DIR、nlohmann_json_DIR等,建议使用默认值。
重要如果您的Qt项目已集成对应的库,请按照您的项目实际情况进行配置。
WITH_EXAMPLES:BOOL=OFF WITH_OTLP:BOOL=ON WITH_OTLP_GRPC:BOOL=ON WITH_OTLP_HTTP:BOOL=ON WITH_STL:BOOL=ON c-ares_DIR:PATH=<your c-ares path> re2_DIR:PATH=<your re2 path> gRPC_DIR:PATH=<your gRPC path> absl_DIR:PATH=<your absl path> WITH_ABSEIL:BOOL=ON nlohmann_json_DIR:PATH=<your nlohmann_json path> CURL_DIR:PATH=<your curl path> OPENSSL_ROOT_DIR:PATH=<your openssl path> OPENSSL_USE_STATIC_LIBS:BOOL=ON Protobuf_DIR:PATH=<your proto path> Protobuf_PROTOC_EXECUTABLE:FILEPATH=<your protoc exe filepath> PROTO_INCLUDE_DIR:FILEPATH=<your proto filepath> CMAKE_CXX_FLAGS=D_HAS_EXCEPTIONS=0 gRPC_CPP_PLUGIN_EXECUTABLE:FILEPATH=<your grpc plugin exe filepath> gRPC_ZLIB_PROVIDER=package ZLIB_ROOT=<your zlib install path> ZLIB_USE_STATIC_LIBS=True ZLIB_LIBRARY_RELEASE=<your zlib release lib path> ZLIB_LIBRARY_DEBUG=<your zlib debug lib path>
至此,Qt项目的构建配置已完成。如果无法编译成功,请按照相关错误提示进行排查。
通过vcpkg包管理器集成
从vcpkg包获取到的SDK二进制文件,可能与您的项目存在兼容性问题,建议您充分测试后再使用。更多信息,请参见using-package-managers。
从vcpkg包管理器中获取二进制文件。
在您的工作目录中,打开一个command prompt或者terminal。
使用Git克隆vcpkg包。
$ git clone https://github.com/microsoft/vcpkg
执行bootstrap-vcpkg.bat脚本。
$ .\vcpkg\bootstrap-vcpkg.bat
进入到vcpkg目录,执行以下脚本。
$ .\vcpkg.exe install opentelemetry-cpp[otlp-http]:x64-windows --recurse
执行以上命令成功后,OpenTelemetry C++ SDK以及对应的依赖SDK将被安装到
vcpkg/installed/x64-winddows
目录下。目录说明,如下所示。bin/目录:包含动态链接库(.dll 文件)。
lib/目录:包含静态链接库文件(.lib 文件)。
include/目录:包含头文件(.h 文件)。
(可选)为了便于后续在Qt项目中使用依赖库,可以通过以下命令安装vcpkg cmake配置文件到系统变量中。
$ .\vcpkg.exe integrate --install
配置Qt项目。
确认Qt项目的编译工具已切换为MSVC。
具体操作,请参见步骤一:配置Visual Studio。
配置CMake options。
在目标项目的编译构建配置页面,单击Initial Configuration,
新增
CMAKE_TOOLCHAIN_FILE
。CMAKE_TOOLCHAIN_FILE
的值需设置为vcpkg目录下的vcpkg.cmake文件。该文件目录为<vcpkg root>/scripts/buildsystems/vcpkg.cmake
。
编译项目,确认是否有成功。
如果有报错,请先排查问题。例如确认编译工具是否已切换为MSVC、是否已正确配置CMAKE_TOOLCHAIN_FILE。
配置CMakeLists.txt。
在CMakeLists.txt文件中加入以下配置。
# opentelemetry-cpp find_package(curl CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED) find_package(grpc CONFIG REQUIRED) find_package(protobuf CONFIG REQUIRED) find_package(opentelemetry-cpp CONFIG REQUIRED) # end # opentelemetry-cpp target_include_directories( ${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR} ${VCPKG_INCLUDE_DIR} ${OPENTELEMETRY_CPP_INCLUDE_DIRS} ) target_link_directories( ${PROJECT_NAME} PUBLIC ${VCPKG_LIB_DIR} ${OPENTELEMETRY_CPP_LIBRARY_DIRS} ) # ${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets部分需要根据项目的实际情况进行配置 target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${OPENTELEMETRY_CPP_LIBRARIES}) # en
至此,Qt项目的构建配置已完成。如果无法编译成功,请按照相关错误提示进行排查。
步骤三:接入验证
在Qt项目中加入以下代码,然后运行项目。
#include "mainwindow.h" #include <QApplication> #include "opentelemetry/exporters/ostream/span_exporter_factory.h" #include "opentelemetry/exporters/otlp/otlp_http.h" #include "opentelemetry/exporters/otlp/otlp_http_exporter_factory.h" #include "opentelemetry/exporters/otlp/otlp_http_exporter_options.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" #include "opentelemetry/sdk/common/global_log_handler.h" namespace trace = opentelemetry::trace; namespace trace_sdk = opentelemetry::sdk::trace; namespace otlp = opentelemetry::exporter::otlp; namespace trace_exporter = opentelemetry::exporter::trace; namespace resource = opentelemetry::sdk::resource; namespace { opentelemetry::exporter::otlp::OtlpHttpExporterOptions opts; void InitTracer() { opts.url = "https://<your project>.<your endpoint>/opentelemetry/v1/traces"; opts.console_debug = true; opts.content_type = otlp::HttpRequestContentType::kBinary; // Setup credentials info opts.http_headers.insert(std::pair<std::string, std::string>("x-sls-otel-project", "<your project>")); opts.http_headers.insert(std::pair<std::string, std::string>("x-sls-otel-instance-id", "<your instanceId>")); opts.http_headers.insert(std::pair<std::string, std::string>("x-sls-otel-ak-id", "<your accesskey id>")); opts.http_headers.insert(std::pair<std::string, std::string>("x-sls-otel-ak-secret", "<your accesskey secret>")); // Create OTLP exporter instance auto exporter = otlp::OtlpHttpExporterFactory::Create(opts); auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter)); resource::ResourceAttributes attributes = { {resource::SemanticConventions::kServiceName, "test"}, {resource::SemanticConventions::kServiceNamespace, "OTelExample4QT"}, {resource::SemanticConventions::kServiceVersion, "1.0.0"}, {resource::SemanticConventions::kHostName, "Win64"}, {resource::SemanticConventions::kDeploymentEnvironment, "dev"} }; 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 namespace trace = opentelemetry::trace; namespace nostd = opentelemetry::nostd; namespace { nostd::shared_ptr<trace::Tracer> get_tracer() { auto provider = trace::Provider::GetTracerProvider(); return provider->GetTracer("foo_library", OPENTELEMETRY_SDK_VERSION); } void basic_f1() { auto span = get_tracer()->StartSpan("basic_f1"); // do your stuff // ... span->End(); } void basic_f1_with_attributes() { auto span = get_tracer()->StartSpan("basic_f1_with_attributes"); span->SetAttribute("ags", 12); span->SetAttribute("sex", "man"); span->SetAttribute("height", 154.5); span->AddEvent("message: success"); span->SetStatus(trace::StatusCode::kError); span->End(); } void basic_active_f1() { auto span_child = get_tracer()->StartSpan("operation B"); // do your stuff // ... span_child->End(); } void basic_active() { auto span = get_tracer()->StartSpan("operation A"); auto scope = get_tracer()->WithActiveSpan(span); basic_active_f1(); span->End(); } void f1() { auto scoped_span = trace::Scope(get_tracer()->StartSpan("f1")); } void f2() { auto scoped_span = trace::Scope(get_tracer()->StartSpan("f2")); f1(); f1(); } } // namespace void foo_library() { basic_f1(); basic_active(); basic_f1_with_attributes(); auto scoped_span = trace::Scope(get_tracer()->StartSpan("library")); f2(); } int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); InitTracer(); foo_library(); CleanupTracer(); return a.exec(); }
在日志服务控制台的Trace服务应用中,查看Trace数据。
添加过滤条件
service : "test"
,查看已接入的Qt Trace数据。