更新时间:2025-09-28 GMT+08:00
分享

快速接入Agent

  • 部署APM Agent时,必须确保接入APM的机器与APM服务网络连通,Agent才能正常工作。可使用“curl -kv”命令测试目标机器与APM服务器网络是否连通。例如,以检查华北-北京四区域,且接入方式为“OpenTelemetry”的连通性为例,请登录应用所部署的机器,并输入命令curl -kv 100.125.12.108:4317,其他区域或源代码的地址请参考探针接入地址
  • C++语言支持OpenTelemetry。

操作步骤

  1. 登录APM控制台
  2. 单击左侧,选择“管理与监管 > 应用性能管理 APM”,进入APM服务页面。
  3. 在左侧导航栏中选择“应用监控 > 应用列表”。
  4. 单击“接入应用”,进入接入应用页面。

    图1 接入应用

  5. 选择“区域”和“应用”单击“创建应用”,弹出“创建应用”弹窗,可以具体操作参见创建应用

    图2 基础信息

  6. “接入方式”选择OpenTelemetry。
  7. “服务端语言”选择C++。

    图3 接入方式

  8. 根据应用类型选择接入对应的接入方式,按照步骤接入。同一个应用下,组件名称不能重复。

    1. 环境要求。
      1. C++版本 ≥ 14(低版本opentelemetry-cpp需要≥ C++11)
      2. 请在 Supported C++ Versions and Development Platforms 中查看支持的C++版本和开发平台。
    2. 环境准备。
      1. 安装构建工具bazel,安装步骤可以参考bazel安装指导
      2. 通过构建OpenTelemetry C++ Library检查环境已经搭建好。
        git clone https://github.com/open-telemetry/opentelemetry-cpp.git
            cd opentelemetry-cpp
            bazel build //...
    3. 在项目中使用OpenTelemetry C++ Library。
      1. WORKSPACE文件。
        load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
        load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
        load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
        
        http_archive(
            name = "io_opentelemetry_cpp",
            sha256 = "<sha256>", # specify sha256 based on the URL specified in the urls parameter.
            strip_prefix = "opentelemetry-cpp-1.10.0",
            urls = [
                "https://github.com/open-telemetry/opentelemetry-cpp/archive/refs/tags/v1.10.0.tar.gz"
            ],
        )
        
        # Load OpenTelemetry dependencies after load.
        load("@io_opentelemetry_cpp//bazel:repository.bzl", "opentelemetry_cpp_deps")
        
        opentelemetry_cpp_deps()
        
        # (required after v1.8.0) Load extra dependencies required for OpenTelemetry
        load("@io_opentelemetry_cpp//bazel:extra_deps.bzl", "opentelemetry_extra_deps")
        
        opentelemetry_extra_deps()
        
        # Load gRPC dependencies after load.
        load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps")
        
        grpc_deps()
        
        # Load extra gRPC dependencies due to https://github.com/grpc/grpc/issues/20511
        load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps")
        
        grpc_extra_deps()
      2. BUILD文件。
        # Copyright The OpenTelemetry Authors
        # SPDX-License-Identifier: Apache-2.0
        
        cc_binary(
            name = "example_http_server",
            srcs = [
                "server.cc",
                "server.h",
            ],
            tags = ["ostream"],
            deps = [
                "@io_opentelemetry_cpp//api",
                "@io_opentelemetry_cpp//exporters/ostream:ostream_span_exporter",
                "@io_opentelemetry_cpp//ext:headers",
                "@io_opentelemetry_cpp//sdk/src/trace",
                "@io_opentelemetry_cpp//exporters/otlp:otlp_grpc_exporter",
            ],
        )
      3. 测试代码包含server.cc、server.h两个文件。

        server.cc

        #include "server.h"
          #include "opentelemetry/trace/context.h"
          #include "opentelemetry/trace/semantic_conventions.h"
        
          #include "opentelemetry/exporters/ostream/span_exporter_factory.h"
          #include "opentelemetry/sdk/trace/exporter.h"
          #include "opentelemetry/sdk/trace/processor.h"
          #include "opentelemetry/sdk/trace/simple_processor_factory.h"
          #include "opentelemetry/sdk/trace/tracer_context.h"
          #include "opentelemetry/sdk/trace/tracer_context_factory.h"
          #include "opentelemetry/sdk/trace/tracer_provider_factory.h"
          #include "opentelemetry/trace/provider.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 <cstring>
          #include <string>
          #include <unistd.h>
          #include <iostream>
          #include <vector>
          #include "opentelemetry/ext/http/client/http_client.h"
          #include "opentelemetry/nostd/shared_ptr.h"
        
          #include "opentelemetry/sdk/trace/tracer_provider.h"
          #include "opentelemetry/exporters/otlp/otlp_grpc_exporter_factory.h"
        
          #include <iostream>
          #include <thread>
        
          namespace trace = opentelemetry::trace;
          namespace trace_sdk = opentelemetry::sdk::trace;
          namespace otlp = opentelemetry::exporter::otlp;
        
          namespace {
        
            using namespace opentelemetry::trace;
            namespace context = opentelemetry::context;
            opentelemetry::exporter::otlp::OtlpGrpcExporterOptions opts;
        
            uint16_t server_port = 8800;
            constexpr const char *server_name = "localhost";
        
            std::string getHostName() {
                char hostname[256];
                if (gethostname(hostname, sizeof(hostname)) == 0) {
                    return hostname;
                } else {
                    return "default_hostname";
                }
            }
        
            template<typename T>
            class HttpTextMapCarrier : public opentelemetry::context::propagation::TextMapCarrier {
            public:
                HttpTextMapCarrier(T &headers) : headers_(headers) {}
        
                HttpTextMapCarrier() = default;
        
                virtual opentelemetry::nostd::string_view Get(opentelemetry::nostd::string_view key) const noexcept override {
                    std::string key_to_compare = key.data();
                    // Header's first letter seems to be  automatically capitaliazed by our test http-server, so
                    // compare accordingly.
                    if (key == opentelemetry::trace::propagation::kTraceParent) {
                        key_to_compare = "Traceparent";
                    } else if (key == opentelemetry::trace::propagation::kTraceState) {
                        key_to_compare = "Tracestate";
                    }
                    auto it = headers_.find(key_to_compare);
                    if (it != headers_.end()) {
                        return it->second;
                    }
                    return "";
                }
        
                virtual void Set(opentelemetry::nostd::string_view key, opentelemetry::nostd::string_view value) noexcept override {
                    headers_.insert(std::pair<std::string, std::string>(std::string(key), std::string(value)));
                }
        
                T headers_;
            };
        
            void InitTracer() {
                // Change this parameter based on the configuration of the access site.
        
        
              std::string endpoint = "http://**.**.**.**:***";
              std::string token = "8ecF***x";
              std::string serviceName = "应用名称.组件名称.环境名称";
        
        
              opts.endpoint = endpoint;
              opts.metadata.insert(std::pair<std::string, std::string>("authentication", token));
              // Create OTLP exporter instance
              auto exporter = otlp::OtlpGrpcExporterFactory::Create(opts);
              auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter));
        
              opentelemetry::sdk::resource::ResourceAttributes attributes = {
                  {"service.name", serviceName},
                  {"host.name",    getHostName()}
              };
              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);
            }
        
            opentelemetry::nostd::shared_ptr <opentelemetry::trace::Tracer> get_tracer(std::string tracer_name) {
              auto provider = opentelemetry::trace::Provider::GetTracerProvider();
              return provider->GetTracer(tracer_name);
            }
        
            class RequestHandler : public HTTP_SERVER_NS::HttpRequestCallback {
            public:
              virtual int onHttpRequest(HTTP_SERVER_NS::HttpRequest const &request, HTTP_SERVER_NS::HttpResponse &response) override {
                  StartSpanOptions options;
                  options.kind = SpanKind::kServer;  // server
                  std::string span_name = request.uri;
        
                  // extract context from http header
                  std::map <std::string, std::string> &request_headers =
                          const_cast<std::map <std::string, std::string> &>(request.headers);
                  const HttpTextMapCarrier<std::map < std::string, std::string>>
                  carrier(request_headers);
                  auto prop = context::propagation::GlobalTextMapPropagator::GetGlobalPropagator();
                  auto current_ctx = context::RuntimeContext::GetCurrent();
                  auto new_context = prop->Extract(carrier, current_ctx);
                  options.parent = GetSpan(new_context)->GetContext();
        
                  // start span with parent context extracted from http header
                  auto span = get_tracer("http-server")
                          ->StartSpan(span_name,
                          {{"server.address", server_name},
                          {"server.port",    server_port},
                          {"http.method",    request.method},
                          {"url.scheme",     "http"},
                          {"http.request.body.size",
                          static_cast<uint64_t>(request.content.length())},
                          {"client.address", request.client}},
                          options);
        
                  auto scope = get_tracer("http_server")->WithActiveSpan(span);
        
                  for (auto &kv : request.headers) {
                      span->SetAttribute("http.header." + std::string(kv.first.data()), kv.second);
                  }
                  if (request.uri == "/helloworld") {
                      span->AddEvent("Processing request");
                      response.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT;
                      response.body = "Welcome to the APM demo!";
                      span->End();
                      return 200;
                  }
                  span->End();
                  return 404;
              }
            };
          }  // namespace
        
          int main(int argc, char *argv[]) {
              InitTracer();
        
              // The port the validation service listens to can be specified via the command line.
              if (argc > 1) {
                server_port = (uint16_t) atoi(argv[1]);
              }
        
              HttpServer http_server(server_name, server_port);
              RequestHandler req_handler;
              http_server.AddHandler("/helloworld", &req_handler);
              auto root_span = get_tracer("http_server")->StartSpan(__func__);
              Scope scope(root_span);
              http_server.Start();
              std::cout << "Server is running..Press ctrl-c to exit...
        ";
              while (1) {
                std::this_thread::sleep_for(std::chrono::seconds(100));
              }
              http_server.Stop();
              root_span->End();
              CleanupTracer();
              return 0;
          }
        

        server.h

        // Copyright The OpenTelemetry Authors
        // SPDX-License-Identifier: Apache-2.0
        
        #pragma once
        
        #include <atomic>
        #include <string>
        #include "opentelemetry/ext/http/server/http_server.h"
        
        namespace {
        
            class HttpServer : public HTTP_SERVER_NS::HttpRequestCallback {
        
            protected:
                HTTP_SERVER_NS::HttpServer server_;
                std::string server_url_;
                uint16_t port_;
                std::atomic<bool> is_running_{false};
        
            public:
                HttpServer(std::string server_name = "test_server", uint16_t port = 8800) : port_(port) {
                    server_.setServerName(server_name);
                    server_.setKeepalive(false);
                }
        
                void AddHandler(std::string path, HTTP_SERVER_NS::HttpRequestCallback *request_handler) {
                    server_.addHandler(path, *request_handler);
                }
        
                void Start() {
                    if (!is_running_.exchange(true)) {
                        server_.addListeningPort(port_);
                        server_.start();
                    }
                }
        
                void Stop() {
                    if (is_running_.exchange(false)) {
                        server_.stop();
                    }
                }
        
                ~HttpServer() { Stop(); }
            };
        
        }  // namespace

相关文档