diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/jaegertracing/opentelemetry-cpp/examples | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/jaegertracing/opentelemetry-cpp/examples')
82 files changed, 3641 insertions, 0 deletions
diff --git a/src/jaegertracing/opentelemetry-cpp/examples/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/CMakeLists.txt new file mode 100644 index 000000000..2367918c7 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/CMakeLists.txt @@ -0,0 +1,27 @@ +add_subdirectory(common) +include_directories(common) +if(WITH_OTLP_GRPC OR WITH_OTLP_HTTP) + add_subdirectory(otlp) +endif() +if(WITH_OTLP_GRPC) + add_subdirectory(grpc) +endif() +if(WITH_ETW) + add_subdirectory(etw_threads) +endif() +if(WITH_JAEGER) + add_subdirectory(jaeger) +endif() +if(WITH_ZIPKIN) + add_subdirectory(zipkin) +endif() +if(WITH_PROMETHEUS AND NOT WITH_METRICS_PREVIEW) + add_subdirectory(prometheus) +endif() +add_subdirectory(plugin) +add_subdirectory(simple) +add_subdirectory(batch) +add_subdirectory(metrics_simple) +add_subdirectory(multithreaded) +add_subdirectory(multi_processor) +add_subdirectory(http) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/batch/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/batch/BUILD new file mode 100644 index 000000000..2dedf6b29 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/batch/BUILD @@ -0,0 +1,13 @@ +cc_binary( + name = "example_simple", + srcs = [ + "main.cc", + ], + linkopts = ["-lpthread"], + tags = ["ostream"], + deps = [ + "//api", + "//exporters/ostream:ostream_span_exporter", + "//sdk/src/trace", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/batch/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/batch/CMakeLists.txt new file mode 100644 index 000000000..d1146d59b --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/batch/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) + +add_executable(batch_span_processor_example main.cc) + +target_link_libraries(batch_span_processor_example ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_exporter_ostream_span opentelemetry_trace) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/batch/main.cc b/src/jaegertracing/opentelemetry-cpp/examples/batch/main.cc new file mode 100644 index 000000000..9a4606ef5 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/batch/main.cc @@ -0,0 +1,90 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" +// Using an exporter that simply dumps span data to stdout. +#include "opentelemetry/exporters/ostream/span_exporter.h" +#include "opentelemetry/sdk/trace/batch_span_processor.h" + +#include <chrono> +#include <thread> + +constexpr int kNumSpans = 10; +namespace trace_api = opentelemetry::trace; +namespace resource = opentelemetry::sdk::resource; +namespace exporter_trace = opentelemetry::exporter::trace; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace nostd = opentelemetry::nostd; + +namespace +{ + +void initTracer() +{ + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new exporter_trace::OStreamSpanExporter); + + // CONFIGURE BATCH SPAN PROCESSOR PARAMETERS + + trace_sdk::BatchSpanProcessorOptions options{}; + // We make the queue size `KNumSpans`*2+5 because when the queue is half full, a preemptive notif + // is sent to start an export call, which we want to avoid in this simple example. + options.max_queue_size = kNumSpans * 2 + 5; + // Time interval (in ms) between two consecutive exports. + options.schedule_delay_millis = std::chrono::milliseconds(3000); + // We export `kNumSpans` after every `schedule_delay_millis` milliseconds. + options.max_export_batch_size = kNumSpans; + + resource::ResourceAttributes attributes = {{"service", "test_service"}, {"version", (uint32_t)1}}; + auto resource = resource::Resource::Create(attributes); + + auto processor = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::BatchSpanProcessor(std::move(exporter), options)); + + auto provider = nostd::shared_ptr<trace_api::TracerProvider>( + new trace_sdk::TracerProvider(std::move(processor), resource)); + // Set the global trace provider. + trace_api::Provider::SetTracerProvider(provider); +} + +nostd::shared_ptr<trace_api::Tracer> get_tracer() +{ + auto provider = trace_api::Provider::GetTracerProvider(); + return provider->GetTracer("foo_library"); +} + +void StartAndEndSpans() +{ + for (int i = 1; i <= kNumSpans; ++i) + { + get_tracer()->StartSpan("Span " + std::to_string(i)); + } +} + +} // namespace + +int main() +{ + // Removing this line will leave the default noop TracerProvider in place. + initTracer(); + + std::cout << "Creating first batch of " << kNumSpans << " spans and waiting 3 seconds ...\n"; + StartAndEndSpans(); + std::this_thread::sleep_for(std::chrono::milliseconds(3000 + 50)); + // The spans should now be exported. + std::cout << "....Exported!\n\n\n"; + + // Do the same again + std::cout << "Creating second batch of " << kNumSpans << " spans and waiting 3 seconds ...\n"; + StartAndEndSpans(); + std::this_thread::sleep_for(std::chrono::milliseconds(3000 + 50)); + std::cout << "....Exported!\n\n\n"; + + // Shutdown and drain queue + StartAndEndSpans(); + printf("Shutting down and draining queue.... \n"); + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + // We immediately let the program terminate which invokes the processor destructor + // which in turn invokes the processor Shutdown(), which finally drains the queue of ALL + // its spans. +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/common/CMakeLists.txt new file mode 100644 index 000000000..c2fdca259 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(foo_library) +if(WITH_LOGS_PREVIEW) + add_subdirectory(logs_foo_library) +endif() +add_subdirectory(metrics_foo_library) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/BUILD new file mode 100644 index 000000000..beffe5ca1 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/BUILD @@ -0,0 +1,16 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "common_foo_library", + srcs = [ + "foo_library.cc", + ], + hdrs = [ + "foo_library.h", + ], + defines = ["BAZEL_BUILD"], + deps = [ + "//api", + "//sdk:headers", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/CMakeLists.txt new file mode 100644 index 000000000..a13512ffe --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(common_foo_library foo_library.h foo_library.cc) +target_link_libraries(common_foo_library PUBLIC ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_api) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/foo_library.cc b/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/foo_library.cc new file mode 100644 index 000000000..a0dec3c76 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/foo_library.cc @@ -0,0 +1,37 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/version/version.h" +#include "opentelemetry/trace/provider.h" + +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 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() +{ + auto scoped_span = trace::Scope(get_tracer()->StartSpan("library")); + + f2(); +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/foo_library.h b/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/foo_library.h new file mode 100644 index 000000000..daebb2603 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/foo_library/foo_library.h @@ -0,0 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +void foo_library(); diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/BUILD new file mode 100644 index 000000000..956c7a569 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/BUILD @@ -0,0 +1,16 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "common_logs_foo_library", + srcs = [ + "foo_library.cc", + ], + hdrs = [ + "foo_library.h", + ], + defines = ["BAZEL_BUILD"], + deps = [ + "//api", + "//sdk:headers", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/CMakeLists.txt new file mode 100644 index 000000000..df14f5c98 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(common_logs_foo_library foo_library.h foo_library.cc) +target_link_libraries(common_logs_foo_library PUBLIC ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_api) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/foo_library.cc b/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/foo_library.cc new file mode 100644 index 000000000..9e4158406 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/foo_library.cc @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 +#ifdef ENABLE_LOGS_PREVIEW +# include <map> +# include <string> +# include "opentelemetry/logs/provider.h" +# include "opentelemetry/sdk/version/version.h" +# include "opentelemetry/trace/provider.h" + +namespace logs = opentelemetry::logs; +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); +} + +nostd::shared_ptr<logs::Logger> get_logger() +{ + auto provider = logs::Provider::GetLoggerProvider(); + return provider->GetLogger("foo_library_logger", "", "foo_library"); +} +} // namespace + +void foo_library() +{ + auto span = get_tracer()->StartSpan("span 1"); + auto scoped_span = trace::Scope(get_tracer()->StartSpan("foo_library")); + auto ctx = span->GetContext(); + auto logger = get_logger(); + logger->Log(opentelemetry::logs::Severity::kDebug, "body", {}, ctx.trace_id(), ctx.span_id(), + ctx.trace_flags(), + opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now())); +} +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/foo_library.h b/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/foo_library.h new file mode 100644 index 000000000..daebb2603 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/logs_foo_library/foo_library.h @@ -0,0 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +void foo_library(); diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/BUILD new file mode 100644 index 000000000..bc8494973 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/BUILD @@ -0,0 +1,17 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "common_metrics_foo_library", + srcs = [ + "foo_library.cc", + ], + hdrs = [ + "foo_library.h", + ], + defines = ["BAZEL_BUILD"], + deps = [ + "//api", + "//sdk:headers", + "//sdk/src/metrics", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/CMakeLists.txt new file mode 100644 index 000000000..4f2bca2a0 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(common_metrics_foo_library foo_library.h foo_library.cc) +target_link_libraries(common_metrics_foo_library PUBLIC opentelemetry_api) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/foo_library.cc b/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/foo_library.cc new file mode 100644 index 000000000..2fcbd660e --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/foo_library.cc @@ -0,0 +1,87 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW +# include "foo_library.h" +# include <chrono> +# include <map> +# include <thread> +# include <vector> +# include "opentelemetry/context/context.h" +# include "opentelemetry/metrics/provider.h" + +namespace nostd = opentelemetry::nostd; +namespace metrics_api = opentelemetry::metrics; + +namespace +{ + +std::map<std::string, std::string> get_random_attr() +{ + static const std::vector<std::pair<std::string, std::string>> labels = {{"key1", "value1"}, + {"key2", "value2"}, + {"key3", "value3"}, + {"key4", "value4"}, + {"key5", "value5"}}; + return std::map<std::string, std::string>{labels[rand() % (labels.size() - 1)], + labels[rand() % (labels.size() - 1)]}; +} + +class MeasurementFetcher +{ +public: + static void Fetcher(opentelemetry::metrics::ObserverResult<double> &observer_result, void *state) + { + double val = (rand() % 700) + 1.1; + std::map<std::string, std::string> labels = get_random_attr(); + auto labelkv = opentelemetry::common::KeyValueIterableView<decltype(labels)>{labels}; + observer_result.Observe(val /*, labelkv*/); + } +}; +} // namespace + +void foo_library::counter_example(const std::string &name) +{ + std::string counter_name = name + "_counter"; + auto provider = metrics_api::Provider::GetMeterProvider(); + nostd::shared_ptr<metrics_api::Meter> meter = provider->GetMeter(name, "1.2.0"); + auto double_counter = meter->CreateDoubleCounter(counter_name); + + while (true) + { + double val = (rand() % 700) + 1.1; + double_counter->Add(val); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } +} + +void foo_library::observable_counter_example(const std::string &name) +{ + std::string counter_name = name + "_observable_counter"; + auto provider = metrics_api::Provider::GetMeterProvider(); + nostd::shared_ptr<metrics_api::Meter> meter = provider->GetMeter(name, "1.2.0"); + meter->CreateDoubleObservableCounter(counter_name, MeasurementFetcher::Fetcher); + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } +} + +void foo_library::histogram_example(const std::string &name) +{ + std::string histogram_name = name + "_histogram"; + auto provider = metrics_api::Provider::GetMeterProvider(); + nostd::shared_ptr<metrics_api::Meter> meter = provider->GetMeter(name, "1.2.0"); + auto histogram_counter = meter->CreateDoubleHistogram(histogram_name); + auto context = opentelemetry::context::Context{}; + while (true) + { + double val = (rand() % 700) + 1.1; + std::map<std::string, std::string> labels = get_random_attr(); + auto labelkv = opentelemetry::common::KeyValueIterableView<decltype(labels)>{labels}; + histogram_counter->Record(val, labelkv, context); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } +} + +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/foo_library.h b/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/foo_library.h new file mode 100644 index 000000000..2f84bcc34 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/common/metrics_foo_library/foo_library.h @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW +# include <string> + +class foo_library +{ +public: + static void counter_example(const std::string &name); + static void histogram_example(const std::string &name); + static void observable_counter_example(const std::string &name); +}; +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/examples/etw_threads/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/etw_threads/CMakeLists.txt new file mode 100644 index 000000000..fd6ac7644 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/etw_threads/CMakeLists.txt @@ -0,0 +1,6 @@ +project(etw_threadpool) + +add_executable(etw_threadpool main.cc) + +target_link_libraries(etw_threadpool ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_api opentelemetry_exporter_etw) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/etw_threads/README.md b/src/jaegertracing/opentelemetry-cpp/examples/etw_threads/README.md new file mode 100644 index 000000000..a004a9f55 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/etw_threads/README.md @@ -0,0 +1,32 @@ +# ETW Exporter multithreaded context propagation example + +## Preface + +This example shows how to pass context from main dispatcher thread to worker threads. +While this example is convenient to run in Visual Studio with ETW exporter, the same +logic should apply to any other exporter. Only the initial portion that obtains ETW +Tracer is unique to ETW, the rest can be reused. + +## How to debug events in Visual Studio 2019 or newer + +Specify your component instrumentation name, which should match the destination ETW +Provider Name or GUID. Example uses "OpenTelemetry-ETW-TLD" for the instrument / +instrumentation name. + +In Visual Studio IDE: + +- navigate to `View -> Other Windows -> Diagnostic Events...` +- click `Configure...` gear on top. +- specify `OpenTelemetry-ETW-TLD` in the list of providers to monitor. +- run example. +- `Diagnostic Events` view shows you the event flow in realtime. + +## Explanation of the code flow + +`main` function acts as a dispatcher to manage thread pool called `pool`. `beep_bop` +span is started in the `main`. Then in a loop up to `kMaxThreads` get started +concurrently. Each thread executing `beep` function with a parent scope of `main`. +`beep` subsequently calls into `bop` function, with a parent scope of `beep` span. +Entire execution of all threads is grouped under the main span called `beep_bop`. +At the end of execution, the `main` function joins all pending threads and ends +the main span. diff --git a/src/jaegertracing/opentelemetry-cpp/examples/etw_threads/main.cc b/src/jaegertracing/opentelemetry-cpp/examples/etw_threads/main.cc new file mode 100644 index 000000000..d25883d1d --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/etw_threads/main.cc @@ -0,0 +1,154 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Include common Trace Provider API and processor +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +#include "opentelemetry/exporters/etw/etw_tracer_exporter.h" + +#include <iostream> +#include <thread> + +#include <cstdio> +#ifndef LOG_DEBUG +# include <mutex> + +/** + * @brief Thread-safe logger routine. + * @param format + * @param args + * @return + */ +static inline int log_vprintf(const char *format, va_list args) +{ + static std::mutex cout_mutex; + std::lock_guard<std::mutex> lk(cout_mutex); + return vprintf(format, args); +}; + +/** + * @brief Thread-safe logger routine. + * @param format + * @param + * @return + */ +static inline int log_printf(const char *format, ...) +{ + int result; + va_list ap; + va_start(ap, format); + result = log_vprintf(format, ap); + va_end(ap); + return result; +}; + +// Debug macros +# define LOG_DEBUG(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_TRACE(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_INFO(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_WARN(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_ERROR(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) +#endif + +using namespace OPENTELEMETRY_NAMESPACE; + +using namespace opentelemetry::exporter::etw; + +// Specify destination ETW Provider Name or GUID. +// +// In Visual Studio: +// - View -> Other Windows -> Diagnostic Events... +// - Click Configure (gear on top). +// - Specify "OpenTelemetry-ETW-TLD" in the list of providers. +// +// Event view shows event flow in realtime. +const char *kGlobalProviderName = "OpenTelemetry-ETW-TLD"; + +std::string providerName = kGlobalProviderName; + +// One provider can be used to associate with different destinations. +exporter::etw::TracerProvider provider; + +// Code below is generic and may be reused with any other TracerProvider. +// In ETW provider case - instrumentation name must match destination +// ETW provider name. +nostd::shared_ptr<trace::Tracer> tracer = provider.GetTracer(providerName, "1.0"); + +// Obtain numeric thread id +static inline uint64_t gettid() +{ + std::stringstream ss; + ss << std::this_thread::get_id(); + uint64_t id = std::stoull(ss.str()); + return id; +} + +// bop gets called by beep. +void bop() +{ + LOG_TRACE("bop worker tid=%u", gettid()); + auto span = tracer->StartSpan("bop"); + span->AddEvent("BopEvent", {{"tid", gettid()}}); + span->SetAttribute("attrib", 2); + span->End(); +} + +// beep gets called in its own thread. +// It is running in a thread pool, invoked via lambda by dispatcher. +void beep() +{ + LOG_TRACE("beep worker tid=%u", gettid()); + auto span = tracer->StartSpan("beep"); + span->AddEvent("BeepEvent", {{"tid", gettid()}}); + span->SetAttribute("attrib", 1); + { + auto bopScope = tracer->WithActiveSpan(span); + bop(); + } + span->End(); +} + +// Max number of threads to spawn +constexpr int kMaxThreads = 10; + +int main(int arc, char **argv) +{ + std::thread pool[kMaxThreads]; + + // Main dispatcher span: parent of all child thread spans. + auto mainSpan = tracer->StartSpan("beep_bop"); + mainSpan->SetAttribute("attrib", 0); + + // Start several threads to perform beep-bop actions. + LOG_TRACE("beep-boop dispatcher tid=%u", gettid()); + for (auto i = 0; i < kMaxThreads; i++) + { + pool[i] = std::thread([&]() { + // This code runs in its own worker thread. + auto beepScope = tracer->WithActiveSpan(mainSpan); + // call beep -> bop + beep(); + }); + }; + + // Join all worker threads in the pool + for (auto &th : pool) + { + try + { + if (th.joinable()) + th.join(); + } + catch (...) + { + // thread might have been gracefully terminated already + } + } + + // End span + mainSpan->End(); + + return 0; +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/grpc/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/grpc/BUILD new file mode 100644 index 000000000..4b2de49cb --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/grpc/BUILD @@ -0,0 +1,63 @@ +package(default_visibility = ["//visibility:public"]) + +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library") + +proto_library( + name = "messages_proto", + srcs = ["protos/messages.proto"], +) + +cc_proto_library( + name = "messages_cc_proto", + deps = [":messages_proto"], +) + +cc_grpc_library( + name = "messages_cc_grpc", + srcs = [":messages_proto"], + grpc_only = True, + deps = [":messages_cc_proto"], +) + +cc_library( + name = "tracer_common", + srcs = ["tracer_common.h"], + defines = ["BAZEL_BUILD"], + tags = ["ostream"], + deps = [ + "//exporters/ostream:ostream_span_exporter", + ], +) + +cc_binary( + name = "client_grpc", + srcs = [ + "client.cc", + ], + defines = ["BAZEL_BUILD"], + tags = ["ostream"], + deps = [ + "messages_cc_grpc", + ":tracer_common", + "//api", + "//sdk/src/trace", + "@com_github_grpc_grpc//:grpc++", + ], +) + +cc_binary( + name = "server_grpc", + srcs = [ + "server.cc", + ], + defines = ["BAZEL_BUILD"], + tags = ["ostream"], + deps = [ + "messages_cc_grpc", + ":tracer_common", + "//api", + "//sdk/src/trace", + "@com_github_grpc_grpc//:grpc++", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/grpc/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/grpc/CMakeLists.txt new file mode 100644 index 000000000..4b701999e --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/grpc/CMakeLists.txt @@ -0,0 +1,45 @@ +# Proto file +get_filename_component(proto_file "./protos/messages.proto" ABSOLUTE) +get_filename_component(proto_file_path "${proto_file}" PATH) + +message("PATH:${proto_file_path}:${proto_file}") +# Generated sources +set(example_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/messages.pb.cc") +set(example_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/messages.pb.h") +set(example_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/messages.grpc.pb.cc") +set(example_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/messages.grpc.pb.h") + +add_custom_command( + OUTPUT "${example_proto_srcs}" "${example_proto_hdrs}" "${example_grpc_srcs}" + "${example_grpc_hdrs}" + COMMAND + ${PROTOBUF_PROTOC_EXECUTABLE} ARGS "--grpc_out=${CMAKE_CURRENT_BINARY_DIR}" + "--cpp_out=${CMAKE_CURRENT_BINARY_DIR}" "--proto_path=${proto_file_path}" + "--plugin=protoc-gen-grpc=${gRPC_CPP_PLUGIN_EXECUTABLE}" "${proto_file}") + +add_library(example_grpc_proto ${example_grpc_srcs} ${example_grpc_hdrs} + ${example_proto_srcs} ${example_proto_hdrs}) + +include(${PROJECT_SOURCE_DIR}/cmake/proto-options-patch.cmake) +patch_protobuf_targets(example_grpc_proto) + +include_directories( + ${CMAKE_SOURCE_DIR}/exporters/ostream/include ${CMAKE_SOURCE_DIR}/ext/include + ${CMAKE_SOURCE_DIR}/api/include/ ${CMAKE_SOURCE_DIR/}) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +if(TARGET protobuf::libprotobuf) + target_link_libraries(example_grpc_proto gRPC::grpc++ protobuf::libprotobuf) +else() + target_include_directories(example_grpc_proto ${Protobuf_INCLUDE_DIRS}) + target_link_libraries(example_grpc_proto ${Protobuf_LIBRARIES}) +endif() + +foreach(_target client server) + add_executable(${_target} "${_target}.cc") + target_link_libraries( + ${_target} example_grpc_proto protobuf::libprotobuf gRPC::grpc++ + opentelemetry_trace opentelemetry_exporter_ostream_span) + patch_protobuf_targets(${_target}) +endforeach() diff --git a/src/jaegertracing/opentelemetry-cpp/examples/grpc/README.md b/src/jaegertracing/opentelemetry-cpp/examples/grpc/README.md new file mode 100644 index 000000000..96d1dc279 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/grpc/README.md @@ -0,0 +1,107 @@ +# OpenTelemetry C++ Example + +## gRPC + +This is a simple example that demonstrates tracing a gRPC request from client to +server. There is an experimental directory in this example - the code within has +been commented out to prevent any conflicts. The example shows several aspects +of tracing such as: + +* Using the `TracerProvider` +* Implementing the TextMapCarrier +* Context injection/extraction +* Span Attributes +* Span Semantic Conventions +* Using the ostream exporter +* Nested spans +* W3c Trace Context Propagation (Very soon!) + +### Running the example + +1. The example uses gRPC C++ as well as Google's protocol buffers. Make sure you + have installed both of these packages on your system, in such a way that + CMake would know how to find them with this command: + + ``find_package(gRPC)`` + +2. Build and Deploy the opentelementry-cpp as described in + [INSTALL.md](../../INSTALL.md). Building the project will build all of the + examples and create new folders containing their executables within the + 'build' directory NOT the 'examples' directory. + +3. Start the server from your `build/examples/grpc` directory. Both the server + and client are configured to use 8800 as the default port, but if you would + like to use another port, you can specify that as an argument. + + ```console + $ ./server [port_num] + Server listening on port: 0.0.0.0:8800 + ``` + +4. In a separate terminal window, run the client to make a single request: + + ```console + $ ./client [port_num] + ... + ``` + +5. You should see console exporter output for both the client and server + sessions. + * Client console + + ```console + { + name : GreeterClient/Greet + trace_id : f5d16f8399be0d2c6b39d992634ffdbb + span_id : 9c79a2dd744d7d2d + tracestate : + parent_span_id: 0000000000000000 + start : 1622603339918985700 + duration : 4960500 + description : + span kind : Client + status : Ok + attributes : + rpc.grpc.status_code: 0 + net.peer.port: 8080 + net.peer.ip: 0.0.0.0 + rpc.method: Greet + rpc.service: grpc-example.GreetService + rpc.system: grpc + events : + } + ``` + + * Server console + + ```console + { + name : GreeterService/Greet + trace_id : f5d16f8399be0d2c6b39d992634ffdbb + span_id : 1e8a7d2d46e08573 + tracestate : + parent_span_id: 9c79a2dd744d7d2d + start : 1622603339923163800 + duration : 76400 + description : + span kind : Server + status : Ok + attributes : + rpc.grpc.status_code: 0 + rpc.method: Greet + rpc.service: GreeterService + rpc.system: grpc + events : + { + name : Processing client attributes + timestamp : 1622603339923180800 + attributes : + } + { + name : Response sent to client + timestamp : 1622603339923233700 + attributes : + } + links : + } + ``` diff --git a/src/jaegertracing/opentelemetry-cpp/examples/grpc/client.cc b/src/jaegertracing/opentelemetry-cpp/examples/grpc/client.cc new file mode 100644 index 000000000..5a182f19a --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/grpc/client.cc @@ -0,0 +1,117 @@ +// Make sure to include GRPC headers first because otherwise Abseil may create +// ambiguity with `nostd::variant` if compiled with Visual Studio 2015. Other +// modern compilers are unaffected. +#include <grpcpp/grpcpp.h> +#ifdef BAZEL_BUILD +# include "examples/grpc/protos/messages.grpc.pb.h" +#else +# include "messages.grpc.pb.h" +#endif + +#include <iostream> +#include <memory> +#include <string> +#include "opentelemetry/trace/experimental_semantic_conventions.h" +#include "tracer_common.h" + +using grpc::Channel; +using grpc::ClientContext; +using grpc::ClientReader; +using grpc::Status; + +using grpc_example::Greeter; +using grpc_example::GreetRequest; +using grpc_example::GreetResponse; + +namespace +{ +namespace context = opentelemetry::context; +using namespace opentelemetry::trace; +class GreeterClient +{ +public: + GreeterClient(std::shared_ptr<Channel> channel) : stub_(Greeter::NewStub(channel)) {} + + std::string Greet(std::string ip, uint16_t port) + { + // Build gRPC Context objects and protobuf message containers + GreetRequest request; + GreetResponse response; + ClientContext context; + request.set_request("Nice to meet you!"); + + StartSpanOptions options; + options.kind = SpanKind::kClient; + + std::string span_name = "GreeterClient/Greet"; + auto span = get_tracer("grpc")->StartSpan( + span_name, + {{OTEL_GET_TRACE_ATTR(AttrRpcSystem), "grpc"}, + {OTEL_GET_TRACE_ATTR(AttrRpcService), "grpc-example.GreetService"}, + {OTEL_GET_TRACE_ATTR(AttrRpcMethod), "Greet"}, + {OTEL_GET_TRACE_ATTR(AttrNetPeerIp), ip}, + {OTEL_GET_TRACE_ATTR(AttrNetPeerPort), port}}, + options); + + auto scope = get_tracer("grpc-client")->WithActiveSpan(span); + + // inject current context to grpc metadata + auto current_ctx = context::RuntimeContext::GetCurrent(); + GrpcClientCarrier carrier(&context); + auto prop = context::propagation::GlobalTextMapPropagator::GetGlobalPropagator(); + prop->Inject(carrier, current_ctx); + + // Send request to server + Status status = stub_->Greet(&context, request, &response); + if (status.ok()) + { + span->SetStatus(StatusCode::kOk); + span->SetAttribute(OTEL_GET_TRACE_ATTR(AttrRpcGrpcStatusCode), status.error_code()); + // Make sure to end your spans! + span->End(); + return response.response(); + } + else + { + std::cout << status.error_code() << ": " << status.error_message() << std::endl; + span->SetStatus(StatusCode::kError); + span->SetAttribute(OTEL_GET_TRACE_ATTR(AttrRpcGrpcStatusCode), status.error_code()); + // Make sure to end your spans! + span->End(); + return "RPC failed"; + } + } + +private: + std::unique_ptr<Greeter::Stub> stub_; +}; // GreeterClient class + +void RunClient(uint16_t port) +{ + GreeterClient greeter( + grpc::CreateChannel("0.0.0.0:" + std::to_string(port), grpc::InsecureChannelCredentials())); + std::string response = greeter.Greet("0.0.0.0", port); + std::cout << "grpc_server says: " << response << std::endl; +} +} // namespace + +int main(int argc, char **argv) +{ + initTracer(); + // set global propagator + context::propagation::GlobalTextMapPropagator::SetGlobalPropagator( + opentelemetry::nostd::shared_ptr<context::propagation::TextMapPropagator>( + new propagation::HttpTraceContext())); + constexpr uint16_t default_port = 8800; + uint16_t port; + if (argc > 1) + { + port = atoi(argv[1]); + } + else + { + port = default_port; + } + RunClient(port); + return 0; +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/grpc/protos/messages.proto b/src/jaegertracing/opentelemetry-cpp/examples/grpc/protos/messages.proto new file mode 100644 index 000000000..e0d69959b --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/grpc/protos/messages.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package grpc_example; + +service Greeter { + rpc Greet(GreetRequest) returns (GreetResponse) {} +} + +message GreetRequest { + string request = 1; +} + +message GreetResponse { + string response = 1; +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/grpc/server.cc b/src/jaegertracing/opentelemetry-cpp/examples/grpc/server.cc new file mode 100644 index 000000000..2671cc0b6 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/grpc/server.cc @@ -0,0 +1,125 @@ +#ifdef BAZEL_BUILD +# include "examples/grpc/protos/messages.grpc.pb.h" +#else +# include "messages.grpc.pb.h" +#endif + +#include "opentelemetry/trace/context.h" +#include "opentelemetry/trace/experimental_semantic_conventions.h" +#include "opentelemetry/trace/span_context_kv_iterable_view.h" +#include "tracer_common.h" + +#include <grpcpp/grpcpp.h> +#include <grpcpp/server.h> +#include <grpcpp/server_builder.h> +#include <grpcpp/server_context.h> + +#include <chrono> +#include <fstream> +#include <map> +#include <sstream> +#include <string> +#include <thread> + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::ServerWriter; +using grpc::Status; + +using grpc_example::Greeter; +using grpc_example::GreetRequest; +using grpc_example::GreetResponse; + +using Span = opentelemetry::trace::Span; +using SpanContext = opentelemetry::trace::SpanContext; +using namespace opentelemetry::trace; + +namespace context = opentelemetry::context; + +namespace +{ +class GreeterServer final : public Greeter::Service +{ +public: + Status Greet(ServerContext *context, + const GreetRequest *request, + GreetResponse *response) override + { + for (auto elem : context->client_metadata()) + { + std::cout << "ELEM: " << elem.first << " " << elem.second << "\n"; + } + + // Create a SpanOptions object and set the kind to Server to inform OpenTel. + StartSpanOptions options; + options.kind = SpanKind::kServer; + + // extract context from grpc metadata + GrpcServerCarrier carrier(context); + + 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(); + + std::string span_name = "GreeterService/Greet"; + auto span = + get_tracer("grpc")->StartSpan(span_name, + {{OTEL_GET_TRACE_ATTR(AttrRpcSystem), "grpc"}, + {OTEL_GET_TRACE_ATTR(AttrRpcService), "GreeterService"}, + {OTEL_GET_TRACE_ATTR(AttrRpcMethod), "Greet"}, + {OTEL_GET_TRACE_ATTR(AttrRpcGrpcStatusCode), 0}}, + options); + auto scope = get_tracer("grpc")->WithActiveSpan(span); + + // Fetch and parse whatever HTTP headers we can from the gRPC request. + span->AddEvent("Processing client attributes"); + + std::string req = request->request(); + std::cout << std::endl << "grpc_client says: " << req << std::endl; + std::string message = "The pleasure is mine."; + // Send response to client + response->set_response(message); + span->AddEvent("Response sent to client"); + + span->SetStatus(StatusCode::kOk); + // Make sure to end your spans! + span->End(); + return Status::OK; + } +}; // GreeterServer class + +void RunServer(uint16_t port) +{ + std::string address("0.0.0.0:" + std::to_string(port)); + GreeterServer service; + ServerBuilder builder; + + builder.RegisterService(&service); + builder.AddListeningPort(address, grpc::InsecureServerCredentials()); + + std::unique_ptr<Server> server(builder.BuildAndStart()); + std::cout << "Server listening on port: " << address << std::endl; + server->Wait(); + server->Shutdown(); +} +} // namespace + +int main(int argc, char **argv) +{ + initTracer(); + constexpr uint16_t default_port = 8800; + uint16_t port; + if (argc > 1) + { + port = atoi(argv[1]); + } + else + { + port = default_port; + } + + RunServer(port); + return 0; +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/grpc/tracer_common.h b/src/jaegertracing/opentelemetry-cpp/examples/grpc/tracer_common.h new file mode 100644 index 000000000..13474a732 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/grpc/tracer_common.h @@ -0,0 +1,98 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#include "opentelemetry/exporters/ostream/span_exporter.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +#include "opentelemetry/context/propagation/global_propagator.h" +#include "opentelemetry/context/propagation/text_map_propagator.h" +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/trace/propagation/http_trace_context.h" + +#include <grpcpp/grpcpp.h> +#include <cstring> +#include <iostream> +#include <vector> + +using grpc::ClientContext; +using grpc::ServerContext; + +namespace +{ +class GrpcClientCarrier : public opentelemetry::context::propagation::TextMapCarrier +{ +public: + GrpcClientCarrier(ClientContext *context) : context_(context) {} + GrpcClientCarrier() = default; + virtual opentelemetry::nostd::string_view Get( + opentelemetry::nostd::string_view key) const noexcept override + { + return ""; + } + + virtual void Set(opentelemetry::nostd::string_view key, + opentelemetry::nostd::string_view value) noexcept override + { + std::cout << " Client ::: Adding " << key << " " << value << "\n"; + context_->AddMetadata(key.data(), value.data()); + } + + ClientContext *context_; +}; + +class GrpcServerCarrier : public opentelemetry::context::propagation::TextMapCarrier +{ +public: + GrpcServerCarrier(ServerContext *context) : context_(context) {} + GrpcServerCarrier() = default; + virtual opentelemetry::nostd::string_view Get( + opentelemetry::nostd::string_view key) const noexcept override + { + auto it = context_->client_metadata().find(key.data()); + if (it != context_->client_metadata().end()) + { + return it->second.data(); + } + return ""; + } + + virtual void Set(opentelemetry::nostd::string_view key, + opentelemetry::nostd::string_view value) noexcept override + { + // Not required for server + } + + ServerContext *context_; +}; + +void initTracer() +{ + auto exporter = std::unique_ptr<opentelemetry::sdk::trace::SpanExporter>( + new opentelemetry::exporter::trace::OStreamSpanExporter); + auto processor = std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>( + new opentelemetry::sdk::trace::SimpleSpanProcessor(std::move(exporter))); + std::vector<std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>> processors; + processors.push_back(std::move(processor)); + // Default is an always-on sampler. + auto context = std::make_shared<opentelemetry::sdk::trace::TracerContext>(std::move(processors)); + auto provider = opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider>( + new opentelemetry::sdk::trace::TracerProvider(context)); + // Set the global trace provider + opentelemetry::trace::Provider::SetTracerProvider(provider); + + // set global propagator + opentelemetry::context::propagation::GlobalTextMapPropagator::SetGlobalPropagator( + opentelemetry::nostd::shared_ptr<opentelemetry::context::propagation::TextMapPropagator>( + new opentelemetry::trace::propagation::HttpTraceContext())); +} + +opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer> get_tracer(std::string tracer_name) +{ + auto provider = opentelemetry::trace::Provider::GetTracerProvider(); + return provider->GetTracer(tracer_name); +} + +} // namespace diff --git a/src/jaegertracing/opentelemetry-cpp/examples/http/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/http/BUILD new file mode 100644 index 000000000..ac36bc0ce --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/http/BUILD @@ -0,0 +1,42 @@ +cc_binary( + name = "example_http_client", + srcs = [ + "client.cc", + "tracer_common.h", + ], + copts = [ + "-DWITH_CURL", + ], + linkopts = select({ + "//bazel:windows": [ + "-DEFAULTLIB:advapi32.lib", + "-DEFAULTLIB:crypt32.lib", + "-DEFAULTLIB:Normaliz.lib", + ], + "//conditions:default": [], + }), + tags = ["ostream"], + deps = [ + "//api", + "//exporters/ostream:ostream_span_exporter", + "//ext:headers", + "//ext/src/http/client/curl:http_client_curl", + "//sdk/src/trace", + ], +) + +cc_binary( + name = "example_http_server", + srcs = [ + "server.cc", + "server.h", + "tracer_common.h", + ], + tags = ["ostream"], + deps = [ + "//api", + "//exporters/ostream:ostream_span_exporter", + "//ext:headers", + "//sdk/src/trace", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/http/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/http/CMakeLists.txt new file mode 100644 index 000000000..a1181c93a --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/http/CMakeLists.txt @@ -0,0 +1,20 @@ +find_package(CURL) + +if(NOT CURL_FOUND) + message(WARNING "Skipping http client/server example build: CURL not found") +else() + include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include + ${CMAKE_SOURCE_DIR}/ext/include ${CMAKE_SOURCE_DIR/}) + + add_executable(http_client client.cc) + add_executable(http_server server.cc) + + target_link_libraries( + http_client ${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace + opentelemetry_http_client_curl opentelemetry_exporter_ostream_span + ${CURL_LIBRARIES}) + + target_link_libraries( + http_server ${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace + opentelemetry_http_client_curl opentelemetry_exporter_ostream_span) +endif() diff --git a/src/jaegertracing/opentelemetry-cpp/examples/http/README.md b/src/jaegertracing/opentelemetry-cpp/examples/http/README.md new file mode 100644 index 000000000..70285170f --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/http/README.md @@ -0,0 +1,112 @@ +# OpenTelemetry C++ Example + +## HTTP + +This is a simple example that demonstrates tracing an HTTP request from client +to server. The example shows several aspects of tracing such as: + +* Using the `TracerProvider` +* Using the `GlobalPropagator` +* Span Attributes +* Span Events +* Using the ostream exporter +* Nested spans (TBD) +* W3C Trace Context Propagation + +### Running the example + +1. The example uses HTTP server and client provided as part of this repo: + * [HTTP + Client](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/ext/include/opentelemetry/ext/http/client) + * [HTTP + Server](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/ext/include/opentelemetry/ext/http/server) + +2. Build and Deploy the opentelementry-cpp as described in + [INSTALL.md](../../INSTALL.md) + +3. Start the server from the `examples/http` directory + + ```console + $ http_server 8800 + Server is running..Press ctrl-c to exit... + ``` + +4. In a separate terminal window, run the client to make a single request: + + ```console + $ ./http_client 8800 + ... + ... + ``` + +5. You should see console exporter output for both the client and server + sessions. + * Client console + + ```console + + { + name : /helloworld + trace_id : baa922bc0da6f79d46373371f4416463 + span_id : 83bed4da7a01267d + tracestate : + parent_span_id: 0000000000000000 + start : 1620287026111457000 + duration : 5164400 + description : + span kind : Client + status : Unset + attributes : + http.header.Date: Thu, 06 May 2021 07:43:46 GMT + http.header.Content-Length: 0 + http.status_code: 200 + http.method: GET + http.header.Host: localhost + http.header.Content-Type: text/plain + http.header.Connection: keep-alive + http.scheme: http + http.url: h**p://localhost:8800/helloworld + events : + links : + + } + ``` + + * Server console + + ```console + + { + name : /helloworld + trace_id : baa922bc0da6f79d46373371f4416463 + span_id : c3e7e23042eb670e + tracestate : + parent_span_id: 83bed4da7a01267d + start : 1620287026115443300 + duration : 50700 + description : + span kind : Server + status : Unset + attributes : + http.header.Traceparent: 00-baa922bc0da6f79d46373371f4416463-83bed4da7a01267d-01 + http.header.Accept: */* + http.request_content_length: 0 + http.header.Host: localhost:8800 + http.scheme: http + http.client_ip: 127.0.0.1:50792 + http.method: GET + net.host.port: 8800 + http.server_name: localhost + events : + { + name : Processing request + timestamp : 1620287026115464000 + attributes : + } + links : + + } + ``` + + As seen from example above, `trace_id` and `parent_span_id` is propagated + from client to server. diff --git a/src/jaegertracing/opentelemetry-cpp/examples/http/client.cc b/src/jaegertracing/opentelemetry-cpp/examples/http/client.cc new file mode 100644 index 000000000..91161e221 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/http/client.cc @@ -0,0 +1,95 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/ext/http/client/http_client_factory.h" +#include "opentelemetry/ext/http/common/url_parser.h" +#include "opentelemetry/trace/experimental_semantic_conventions.h" +#include "tracer_common.h" + +namespace +{ + +using namespace opentelemetry::trace; +namespace http_client = opentelemetry::ext::http::client; +namespace context = opentelemetry::context; +namespace nostd = opentelemetry::nostd; + +void sendRequest(const std::string &url) +{ + auto http_client = http_client::HttpClientFactory::CreateSync(); + + // start active span + StartSpanOptions options; + options.kind = SpanKind::kClient; // client + opentelemetry::ext::http::common::UrlParser url_parser(url); + + std::string span_name = url_parser.path_; + auto span = get_tracer("http-client") + ->StartSpan(span_name, + {{OTEL_GET_TRACE_ATTR(AttrHttpUrl), url_parser.url_}, + {OTEL_GET_TRACE_ATTR(AttrHttpScheme), url_parser.scheme_}, + {OTEL_GET_TRACE_ATTR(AttrHttpMethod), "GET"}}, + options); + auto scope = get_tracer("http-client")->WithActiveSpan(span); + + // inject current context into http header + auto current_ctx = context::RuntimeContext::GetCurrent(); + HttpTextMapCarrier<http_client::Headers> carrier; + auto prop = context::propagation::GlobalTextMapPropagator::GetGlobalPropagator(); + prop->Inject(carrier, current_ctx); + + // send http request + http_client::Result result = http_client->Get(url, carrier.headers_); + if (result) + { + // set span attributes + auto status_code = result.GetResponse().GetStatusCode(); + span->SetAttribute(OTEL_GET_TRACE_ATTR(AttrHttpStatusCode), status_code); + result.GetResponse().ForEachHeader( + [&span](nostd::string_view header_name, nostd::string_view header_value) { + span->SetAttribute("http.header." + std::string(header_name.data()), header_value); + return true; + }); + + if (status_code >= 400) + { + span->SetStatus(StatusCode::kError); + } + } + else + { + span->SetStatus( + StatusCode::kError, + "Response Status :" + + std::to_string( + static_cast<typename std::underlying_type<http_client::SessionState>::type>( + result.GetSessionState()))); + } + // end span and export data + span->End(); +} + +} // namespace + +int main(int argc, char *argv[]) +{ + initTracer(); + constexpr char default_host[] = "localhost"; + constexpr char default_path[] = "/helloworld"; + constexpr uint16_t default_port = 8800; + uint16_t port; + + // The port the validation service listens to can be specified via the command line. + if (argc > 1) + { + port = atoi(argv[1]); + } + else + { + port = default_port; + } + + std::string url = "http://" + std::string(default_host) + ":" + std::to_string(port) + + std::string(default_path); + sendRequest(url); +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/http/server.cc b/src/jaegertracing/opentelemetry-cpp/examples/http/server.cc new file mode 100644 index 000000000..46772dc05 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/http/server.cc @@ -0,0 +1,94 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "server.h" +#include "opentelemetry/trace/context.h" +#include "opentelemetry/trace/experimental_semantic_conventions.h" +#include "tracer_common.h" + +#include <iostream> +#include <thread> + +namespace +{ + +using namespace opentelemetry::trace; +namespace context = opentelemetry::context; + +uint16_t server_port = 8800; +constexpr const char *server_name = "localhost"; + +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 + const HttpTextMapCarrier<std::map<std::string, std::string>> carrier( + (std::map<std::string, std::string> &)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, + {{OTEL_GET_TRACE_ATTR(AttrHttpServerName), server_name}, + {OTEL_GET_TRACE_ATTR(AttrNetHostPort), server_port}, + {OTEL_GET_TRACE_ATTR(AttrHttpMethod), request.method}, + {OTEL_GET_TRACE_ATTR(AttrHttpScheme), "http"}, + {OTEL_GET_TRACE_ATTR(AttrHttpRequestContentLength), + static_cast<uint64_t>(request.content.length())}, + {OTEL_GET_TRACE_ATTR(AttrHttpClientIp), 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; + 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 = 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...\n"; + while (1) + { + std::this_thread::sleep_for(std::chrono::seconds(100)); + } + http_server.Stop(); + root_span->End(); + return 0; +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/http/server.h b/src/jaegertracing/opentelemetry-cpp/examples/http/server.h new file mode 100644 index 000000000..2b94bf3a6 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/http/server.h @@ -0,0 +1,53 @@ +// 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
\ No newline at end of file diff --git a/src/jaegertracing/opentelemetry-cpp/examples/http/tracer_common.h b/src/jaegertracing/opentelemetry-cpp/examples/http/tracer_common.h new file mode 100644 index 000000000..619aed622 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/http/tracer_common.h @@ -0,0 +1,87 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#include "opentelemetry/exporters/ostream/span_exporter.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.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 <iostream> +#include <vector> +#include "opentelemetry/ext/http/client/http_client.h" +#include "opentelemetry/nostd/shared_ptr.h" + +namespace +{ + +template <typename T> +class HttpTextMapCarrier : public opentelemetry::context::propagation::TextMapCarrier +{ +public: + HttpTextMapCarrier<T>(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() +{ + auto exporter = std::unique_ptr<opentelemetry::sdk::trace::SpanExporter>( + new opentelemetry::exporter::trace::OStreamSpanExporter); + auto processor = std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>( + new opentelemetry::sdk::trace::SimpleSpanProcessor(std::move(exporter))); + std::vector<std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>> processors; + processors.push_back(std::move(processor)); + // Default is an always-on sampler. + auto context = std::make_shared<opentelemetry::sdk::trace::TracerContext>(std::move(processors)); + auto provider = opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider>( + new opentelemetry::sdk::trace::TracerProvider(context)); + // Set the global trace provider + opentelemetry::trace::Provider::SetTracerProvider(provider); + + // set global propagator + opentelemetry::context::propagation::GlobalTextMapPropagator::SetGlobalPropagator( + opentelemetry::nostd::shared_ptr<opentelemetry::context::propagation::TextMapPropagator>( + new opentelemetry::trace::propagation::HttpTraceContext())); +} + +opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer> get_tracer(std::string tracer_name) +{ + auto provider = opentelemetry::trace::Provider::GetTracerProvider(); + return provider->GetTracer(tracer_name); +} + +} // namespace diff --git a/src/jaegertracing/opentelemetry-cpp/examples/jaeger/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/jaeger/BUILD new file mode 100644 index 000000000..23f42f93b --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/jaeger/BUILD @@ -0,0 +1,13 @@ +cc_binary( + name = "example_jaeger", + srcs = [ + "main.cc", + ], + tags = ["jaeger"], + deps = [ + "//api", + "//examples/common/foo_library:common_foo_library", + "//exporters/jaeger:opentelemetry_exporter_jaeger_trace", + "//sdk/src/trace", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/jaeger/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/jaeger/CMakeLists.txt new file mode 100644 index 000000000..713521c3a --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/jaeger/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories(${CMAKE_SOURCE_DIR}/exporters/jaeger/include) + +add_executable(example_jaeger main.cc) +target_link_libraries( + example_jaeger ${CMAKE_THREAD_LIBS_INIT} common_foo_library + opentelemetry_trace opentelemetry_exporter_jaeger_trace) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/jaeger/README.md b/src/jaegertracing/opentelemetry-cpp/examples/jaeger/README.md new file mode 100644 index 000000000..42ac4e125 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/jaeger/README.md @@ -0,0 +1,18 @@ +# Jaeger Exporter Example + +This is an example of how to use the Jaeger exporter. + +The application in `main.cc` initializes an `JaegerExporter` instance and uses it +to register a tracer provider from the [OpenTelemetry +SDK](https://github.com/open-telemetry/opentelemetry-cpp). The application then +calls a `foo_library` which has been instrumented using the [OpenTelemetry +API](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/api). + +Resulting spans are exported to the Jaeger agent using the Jaeger exporter. + +Note that the Jaeger exporter connects to the agent at `localhost:6831` by +default. + +Once you have the Collector running, see +[CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on building and +running the example. diff --git a/src/jaegertracing/opentelemetry-cpp/examples/jaeger/main.cc b/src/jaegertracing/opentelemetry-cpp/examples/jaeger/main.cc new file mode 100644 index 000000000..d0f507fd4 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/jaeger/main.cc @@ -0,0 +1,46 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/exporters/jaeger/jaeger_exporter.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +#ifdef BAZEL_BUILD +# include "examples/common/foo_library/foo_library.h" +#else +# include "foo_library/foo_library.h" +#endif + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace jaeger = opentelemetry::exporter::jaeger; + +namespace +{ +opentelemetry::exporter::jaeger::JaegerExporterOptions opts; +void InitTracer() +{ + // Create Jaeger exporter instance + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new jaeger::JaegerExporter(opts)); + auto processor = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + auto provider = + nostd::shared_ptr<trace::TracerProvider>(new trace_sdk::TracerProvider(std::move(processor))); + // Set the global trace provider + trace::Provider::SetTracerProvider(provider); +} +} // namespace + +int main(int argc, char *argv[]) +{ + if (argc == 2) + { + opts.endpoint = argv[1]; + } + // Removing this line will leave the default noop TracerProvider in place. + InitTracer(); + + foo_library(); +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/BUILD new file mode 100644 index 000000000..95d6490ba --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/BUILD @@ -0,0 +1,28 @@ +cc_binary( + name = "metrics_simple_example", + srcs = [ + "main.cc", + ], + linkopts = ["-pthread"], + tags = ["ostream"], + deps = [ + "//api", + "//exporters/ostream:ostream_metrics_exporter_deprecated", + "//sdk/src/_metrics:metrics_deprecated", + ], +) + +cc_binary( + name = "metrics_ostream_example", + srcs = [ + "metrics_ostream.cc", + ], + linkopts = ["-pthread"], + tags = ["ostream"], + deps = [ + "//api", + "//examples/common/metrics_foo_library:common_metrics_foo_library", + "//exporters/ostream:ostream_metric_exporter", + "//sdk/src/metrics", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/CMakeLists.txt new file mode 100644 index 000000000..a2088fd51 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/CMakeLists.txt @@ -0,0 +1,13 @@ +include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) +if(WITH_METRICS_PREVIEW) + add_executable(simple_metrics main.cc) + target_link_libraries( + simple_metrics ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics_deprecated + opentelemetry_exporter_ostream_metrics_deprecated) +else() + add_executable(metrics_ostream_example metrics_ostream.cc) + target_link_libraries( + metrics_ostream_example ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics + opentelemetry_exporter_ostream_metrics opentelemetry_resources + common_metrics_foo_library) +endif() diff --git a/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/README.md b/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/README.md new file mode 100644 index 000000000..b2c5dc0a7 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/README.md @@ -0,0 +1,86 @@ +# Simple Metrics Example + +This example initializes the metrics pipeline with 2 different instrument types. +Here are more detailed explanations of each part. + +1: Initialize an exporter and a reader. In this case, we initialize an OStream +Exporter which will print to stdout by default. +The reader periodically collects metrics from the collector and exports them. + +```cpp +std::unique_ptr<metric_sdk::MetricExporter> exporter{new exportermetrics::OStreamMetricExporter}; +std::unique_ptr<metric_sdk::MetricReader> reader{ + new metric_sdk::PeriodicExportingMetricReader(std::move(exporter), options)}; +``` + +2: Initialize a MeterProvider and add the reader. +We will use this to obtain Meter objects in the future. + +```cpp +auto provider = std::shared_ptr<metrics_api::MeterProvider>(new opentelemetry::metrics::MeterProvider()); +auto p = std::static_pointer_cast<metric_sdk::MeterProvider>(provider); +p->AddMetricReader(std::move(reader)); +``` + +3: Create and add a view to the provider. + +```cpp +std::unique_ptr<metric_sdk::InstrumentSelector> instrument_selector{ + new metric_sdk::InstrumentSelector(metric_sdk::InstrumentType::kCounter, "name_counter")}; +std::unique_ptr<metric_sdk::MeterSelector> meter_selector{ + new metric_sdk::MeterSelector(name, version, schema)}; +std::unique_ptr<metric_sdk::View> sum_view{ + new metric_sdk::View{name, "description", metric_sdk::AggregationType::kSum}}; +p->AddView(std::move(instrument_selector), std::move(meter_selector), std::move(sum_view)); +``` + +4: Then create a +[Counter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#counter) +instrument from it. Every Meter pointer returned by the +MeterProvider points to the same Meter. This means that the Meter will be able +to combine metrics captured from different functions without having to +constantly pass the Meter around the library. + +```cpp +nostd::shared_ptr<metrics_api::Meter> meter = provider->GetMeter(name, "1.2.0"); +auto double_counter = meter->CreateDoubleCounter(counter_name); +// Create a label set which annotates metric values +std::map<std::string, std::string> labels = {{"key", "value"}}; +auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels}; +double_counter->Add(val, labelkv); +``` + +5: To use histogram instrument, a view with proper `InstrumentType` and `AggregationType` +has to be added to the provider. + +```cpp +std::unique_ptr<metric_sdk::InstrumentSelector> histogram_instrument_selector{ + new metric_sdk::InstrumentSelector(metric_sdk::InstrumentType::kHistogram, "histogram_name")}; +std::unique_ptr<metric_sdk::MeterSelector> histogram_meter_selector{ + new metric_sdk::MeterSelector(name, version, schema)}; +std::unique_ptr<metric_sdk::View> histogram_view{ + new metric_sdk::View{name, "description", metric_sdk::AggregationType::kHistogram}}; +p->AddView(std::move(histogram_instrument_selector), std::move(histogram_meter_selector), + std::move(histogram_view)); + +auto histogram_counter = meter->CreateDoubleHistogram("histogram_name"); +auto context = opentelemetry::context::Context{}; +histogram_counter->Record(val, labelkv, context); +``` + +See [CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on building and +running the example. + +## Additional Documentation + +[API +Design](https://github.com/open-o11y/docs/blob/master/cpp-metrics/api-design.md) + +[SDK +Design](https://github.com/open-o11y/docs/blob/master/cpp-metrics/sdk-design.md) + +[OStreamExporters +Design](https://github.com/open-o11y/docs/blob/master/cpp-ostream/ostream-exporter-design.md) + +[OpenTelemetry C++ Metrics +Overview](https://github.com/open-o11y/docs/blob/master/cpp-metrics/README.md) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/main.cc b/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/main.cc new file mode 100644 index 000000000..3a18a52f3 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/main.cc @@ -0,0 +1,118 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_METRICS_PREVIEW +# include "opentelemetry/_metrics/provider.h" +# include "opentelemetry/exporters/ostream/metrics_exporter.h" +# include "opentelemetry/sdk/_metrics/controller.h" +# include "opentelemetry/sdk/_metrics/meter.h" +# include "opentelemetry/sdk/_metrics/meter_provider.h" +# include "opentelemetry/sdk/_metrics/ungrouped_processor.h" + +namespace metric_sdk = opentelemetry::sdk::metrics; +namespace nostd = opentelemetry::nostd; +namespace common = opentelemetry::common; +namespace exportermetrics = opentelemetry::exporter::metrics; +namespace metrics_api = opentelemetry::metrics; + +int main() +{ + // Initialize and set the global MeterProvider + auto provider = nostd::shared_ptr<metrics_api::MeterProvider>(new metric_sdk::MeterProvider); + metrics_api::Provider::SetMeterProvider(provider); + + // Get the Meter from the MeterProvider + nostd::shared_ptr<metrics_api::Meter> meter = provider->GetMeter("Test", "0.1.0"); + + // Create the controller with Stateless Metrics Processor + metric_sdk::PushController ControllerStateless( + meter, + std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter), + std::shared_ptr<metric_sdk::MetricsProcessor>( + new metric_sdk::UngroupedMetricsProcessor(false)), + .05); + + // Create and instrument + auto intupdowncounter = meter->NewIntUpDownCounter("UpDownCounter", "None", "none", true); + auto intcounter = meter->NewIntCounter("Counter", "none", "none", true); + + // Create a labelset + std::map<std::string, std::string> labels = {{"key", "value"}}; + auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels}; + + // Create arrays of instrument and values to add to them + metrics_api::SynchronousInstrument<int> *iinstr_arr[] = {intupdowncounter.get(), + intcounter.get()}; + int ivalues_arr[] = {10, 5}; + + // Change the arrays to be nostd::spans + nostd::span<metrics_api::SynchronousInstrument<int> *> instrument_span{iinstr_arr}; + nostd::span<const int, 2> instrument_values{ivalues_arr}; + + /** + * First way of updating an instrument, RecordBatch. We can update multiple instruments at once by + * using a span of instruments and a span of values. This RecordBatch will update the ith + * instrument with the ith value. + **/ + std::cout << "Example 1" << std::endl; + ControllerStateless.start(); + + // Updating multiple instruments with the same labelset + meter->RecordIntBatch(labelkv, instrument_span, instrument_values); + + ControllerStateless.stop(); + /** + * Second way of updating an instrument, bind then add. In this method the user binds an + *instrument to a labelset Then add to the bounded instrument, then unbind. + **/ + std::cout << "Example 2" << std::endl; + ControllerStateless.start(); + + auto boundintupdowncounter = intupdowncounter->bindUpDownCounter(labelkv); + boundintupdowncounter->add(50); + boundintupdowncounter->unbind(); + + ControllerStateless.stop(); + /** + * The Third and final way is to add a value with a labelset at the same time. This also shows + * The difference between using a Stateless and Stateful Processor + */ + + // Start exporting from the Controller with Stateless Processor + std::cout << "-----" + << " Stateless Processor " + << "-----" << std::endl; + ControllerStateless.start(); + for (int i = 0; i < 20; i++) + { + intupdowncounter->add(i, labelkv); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + ControllerStateless.stop(); + + // Do the same thing for stateful to see the difference + metric_sdk::PushController ControllerStateful( + meter, + std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter), + std::shared_ptr<metric_sdk::MetricsProcessor>( + new metric_sdk::UngroupedMetricsProcessor(true)), + .05); + + // Start exporting from the Controller with Stateful Processor + std::cout << "-----" + << " Stateful Processor " + << "-----" << std::endl; + ControllerStateful.start(); + for (int i = 0; i < 20; i++) + { + intupdowncounter->add(i, labelkv); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + ControllerStateful.stop(); +} +#else +int main() +{ + // empty +} +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/metrics_ostream.cc b/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/metrics_ostream.cc new file mode 100644 index 000000000..585856f91 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/metrics_simple/metrics_ostream.cc @@ -0,0 +1,119 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW +# include <memory> +# include <thread> +# include "opentelemetry/exporters/ostream/metric_exporter.h" +# include "opentelemetry/metrics/provider.h" +# include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h" +# include "opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h" +# include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h" +# include "opentelemetry/sdk/metrics/meter.h" +# include "opentelemetry/sdk/metrics/meter_provider.h" + +# ifdef BAZEL_BUILD +# include "examples/common/metrics_foo_library/foo_library.h" +# else +# include "metrics_foo_library/foo_library.h" +# endif + +namespace metric_sdk = opentelemetry::sdk::metrics; +namespace nostd = opentelemetry::nostd; +namespace common = opentelemetry::common; +namespace exportermetrics = opentelemetry::exporter::metrics; +namespace metrics_api = opentelemetry::metrics; + +namespace +{ + +void initMetrics(const std::string &name) +{ + std::unique_ptr<metric_sdk::MetricExporter> exporter{new exportermetrics::OStreamMetricExporter}; + + std::string version{"1.2.0"}; + std::string schema{"https://opentelemetry.io/schemas/1.2.0"}; + + // Initialize and set the global MeterProvider + metric_sdk::PeriodicExportingMetricReaderOptions options; + options.export_interval_millis = std::chrono::milliseconds(1000); + options.export_timeout_millis = std::chrono::milliseconds(500); + std::unique_ptr<metric_sdk::MetricReader> reader{ + new metric_sdk::PeriodicExportingMetricReader(std::move(exporter), options)}; + auto provider = std::shared_ptr<metrics_api::MeterProvider>(new metric_sdk::MeterProvider()); + auto p = std::static_pointer_cast<metric_sdk::MeterProvider>(provider); + p->AddMetricReader(std::move(reader)); + + // counter view + std::string counter_name = name + "_counter"; + std::unique_ptr<metric_sdk::InstrumentSelector> instrument_selector{ + new metric_sdk::InstrumentSelector(metric_sdk::InstrumentType::kCounter, counter_name)}; + std::unique_ptr<metric_sdk::MeterSelector> meter_selector{ + new metric_sdk::MeterSelector(name, version, schema)}; + std::unique_ptr<metric_sdk::View> sum_view{ + new metric_sdk::View{name, "description", metric_sdk::AggregationType::kSum}}; + p->AddView(std::move(instrument_selector), std::move(meter_selector), std::move(sum_view)); + + // observable counter view + std::string observable_counter_name = name + "_observable_counter"; + std::unique_ptr<metric_sdk::InstrumentSelector> observable_instrument_selector{ + new metric_sdk::InstrumentSelector(metric_sdk::InstrumentType::kObservableCounter, + observable_counter_name)}; + std::unique_ptr<metric_sdk::MeterSelector> observable_meter_selector{ + new metric_sdk::MeterSelector(name, version, schema)}; + std::unique_ptr<metric_sdk::View> observable_sum_view{ + new metric_sdk::View{name, "description", metric_sdk::AggregationType::kSum}}; + p->AddView(std::move(observable_instrument_selector), std::move(observable_meter_selector), + std::move(observable_sum_view)); + + // histogram view + std::string histogram_name = name + "_histogram"; + std::unique_ptr<metric_sdk::InstrumentSelector> histogram_instrument_selector{ + new metric_sdk::InstrumentSelector(metric_sdk::InstrumentType::kHistogram, histogram_name)}; + std::unique_ptr<metric_sdk::MeterSelector> histogram_meter_selector{ + new metric_sdk::MeterSelector(name, version, schema)}; + std::unique_ptr<metric_sdk::View> histogram_view{ + new metric_sdk::View{name, "description", metric_sdk::AggregationType::kHistogram}}; + p->AddView(std::move(histogram_instrument_selector), std::move(histogram_meter_selector), + std::move(histogram_view)); + metrics_api::Provider::SetMeterProvider(provider); +} +} // namespace + +int main(int argc, char **argv) +{ + std::string example_type; + if (argc >= 2) + { + example_type = argv[1]; + } + + std::string name{"ostream_metric_example"}; + initMetrics(name); + + if (example_type == "counter") + { + foo_library::counter_example(name); + } + else if (example_type == "observable_counter") + { + foo_library::observable_counter_example(name); + } + else if (example_type == "histogram") + { + foo_library::histogram_example(name); + } + else + { + std::thread counter_example{&foo_library::counter_example, name}; + std::thread observable_counter_example{&foo_library::observable_counter_example, name}; + std::thread histogram_example{&foo_library::histogram_example, name}; + + counter_example.join(); + observable_counter_example.join(); + histogram_example.join(); + } +} +#else +int main() {} +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/BUILD new file mode 100644 index 000000000..3388d3942 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/BUILD @@ -0,0 +1,17 @@ +cc_binary( + name = "example_multi_processor", + srcs = [ + "main.cc", + ], + tags = [ + "memory", + "ostream", + ], + deps = [ + "//api", + "//examples/common/foo_library:common_foo_library", + "//exporters/memory:in_memory_span_exporter", + "//exporters/ostream:ostream_span_exporter", + "//sdk/src/trace", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/CMakeLists.txt new file mode 100644 index 000000000..a1e4ac9ea --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include + ${CMAKE_SOURCE_DIR}/exporters/memory/include) + +add_executable(example_multi_processor main.cc) +target_link_libraries( + example_multi_processor ${CMAKE_THREAD_LIBS_INIT} common_foo_library + opentelemetry_trace opentelemetry_exporter_ostream_span) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/README.md b/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/README.md new file mode 100644 index 000000000..c53939762 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/README.md @@ -0,0 +1,15 @@ +# Multi Processor Trace Example + +In this example, the application in `main.cc` initializes and registers a tracer +provider from the [OpenTelemetry +SDK](https://github.com/open-telemetry/opentelemetry-cpp). The `TracerProvider` +is connected to two `processor-exporter` pipelines - for exporting +simultaneously to `StdoutSpanExporter` and `InMemorySpanExporter`. The +application then calls a `foo_library` which has been instrumented using the +[OpenTelemetry +API](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/api). +Resulting telemetry is directed to stdout through the StdoutSpanExporter, and +saved as a variable (vector of spans) through `InMemorySpanExporter`. + +See [CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on building and +running the example. diff --git a/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/main.cc b/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/main.cc new file mode 100644 index 000000000..2b722b668 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/multi_processor/main.cc @@ -0,0 +1,89 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_context.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +// Using an exporter that simply dumps span data to stdout. +#ifdef BAZEL_BUILD +# include "examples/common/foo_library/foo_library.h" +#else +# include "foo_library/foo_library.h" +#endif +#include "opentelemetry/exporters/memory/in_memory_span_exporter.h" +#include "opentelemetry/exporters/ostream/span_exporter.h" + +using opentelemetry::exporter::memory::InMemorySpanExporter; +namespace trace_api = opentelemetry::trace; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace nostd = opentelemetry::nostd; + +namespace +{ +InMemorySpanExporter *initTracer() +{ + auto exporter1 = std::unique_ptr<trace_sdk::SpanExporter>( + new opentelemetry::exporter::trace::OStreamSpanExporter); + auto processor1 = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter1))); + + InMemorySpanExporter *memory_span_exporter = new InMemorySpanExporter(); + auto exporter2 = std::unique_ptr<trace_sdk::SpanExporter>(memory_span_exporter); + + // fetch the exporter for dumping data later + + auto processor2 = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter2))); + + auto provider = nostd::shared_ptr<trace_sdk::TracerProvider>( + new trace_sdk::TracerProvider(std::move(processor1))); + provider->AddProcessor(std::move(processor2)); + // Set the global trace provider + trace_api::Provider::SetTracerProvider(std::move(provider)); + + return memory_span_exporter; +} + +void dumpSpans(std::vector<std::unique_ptr<trace_sdk::SpanData>> &spans) +{ + char span_buf[trace_api::SpanId::kSize * 2]; + char trace_buf[trace_api::TraceId::kSize * 2]; + char parent_span_buf[trace_api::SpanId::kSize * 2]; + std::cout << "\nSpans from memory :" << std::endl; + + for (auto &span : spans) + { + std::cout << "\n\tSpan: " << std::endl; + std::cout << "\t\tName: " << span->GetName() << std::endl; + span->GetSpanId().ToLowerBase16(span_buf); + span->GetTraceId().ToLowerBase16(trace_buf); + span->GetParentSpanId().ToLowerBase16(parent_span_buf); + std::cout << "\t\tTraceId: " << std::string(trace_buf, sizeof(trace_buf)) << std::endl; + std::cout << "\t\tSpanId: " << std::string(span_buf, sizeof(span_buf)) << std::endl; + std::cout << "\t\tParentSpanId: " << std::string(parent_span_buf, sizeof(parent_span_buf)) + << std::endl; + + std::cout << "\t\tDescription: " << span->GetDescription() << std::endl; + std::cout << "\t\tSpan kind:" + << static_cast<typename std::underlying_type<trace_api::SpanKind>::type>( + span->GetSpanKind()) + << std::endl; + std::cout << "\t\tSpan Status: " + << static_cast<typename std::underlying_type<trace_api::StatusCode>::type>( + span->GetStatus()) + << std::endl; + } +} +} // namespace + +int main() +{ + // Removing this line will leave the default noop TracerProvider in place. + InMemorySpanExporter *memory_span_exporter = initTracer(); + + foo_library(); + auto memory_spans = memory_span_exporter->GetData()->GetSpans(); + dumpSpans(memory_spans); +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/multithreaded/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/multithreaded/BUILD new file mode 100644 index 000000000..5cac7b6d3 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/multithreaded/BUILD @@ -0,0 +1,12 @@ +cc_binary( + name = "example_multithreaded", + srcs = [ + "main.cc", + ], + tags = ["ostream"], + deps = [ + "//api", + "//exporters/ostream:ostream_span_exporter", + "//sdk/src/trace", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/multithreaded/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/multithreaded/CMakeLists.txt new file mode 100644 index 000000000..0721f2e21 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/multithreaded/CMakeLists.txt @@ -0,0 +1,5 @@ +include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) + +add_executable(example_multithreaded main.cc) +target_link_libraries(example_multithreaded ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_trace opentelemetry_exporter_ostream_span) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/multithreaded/main.cc b/src/jaegertracing/opentelemetry-cpp/examples/multithreaded/main.cc new file mode 100644 index 000000000..17efbb8bf --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/multithreaded/main.cc @@ -0,0 +1,68 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/resource/resource.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/trace/scope.h" + +// Using an exporter that simply dumps span data to stdout. +#include "opentelemetry/exporters/ostream/span_exporter.h" + +#include <algorithm> +#include <thread> + +namespace trace_api = opentelemetry::trace; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace nostd = opentelemetry::nostd; + +namespace +{ +void initTracer() +{ + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>( + new opentelemetry::exporter::trace::OStreamSpanExporter); + auto processor = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + auto provider = nostd::shared_ptr<trace_api::TracerProvider>(new trace_sdk::TracerProvider( + std::move(processor), opentelemetry::sdk::resource::Resource::Create({}))); + // Set the global trace provider + trace_api::Provider::SetTracerProvider(provider); +} + +nostd::shared_ptr<trace_api::Tracer> get_tracer() +{ + auto provider = trace_api::Provider::GetTracerProvider(); + return provider->GetTracer("foo_library"); +} +} // namespace + +void run_threads() +{ + auto thread_span = get_tracer()->StartSpan(__func__); + + std::vector<std::thread> threads; + for (int thread_num = 0; thread_num < 5; ++thread_num) + { + // This shows how one can effectively use Scope objects to correctly + // parent spans across threads. + threads.push_back(std::thread([=] { + trace_api::Scope scope(thread_span); + auto thread_span = + get_tracer()->StartSpan(std::string("thread ") + std::to_string(thread_num)); + })); + } + + std::for_each(threads.begin(), threads.end(), [](std::thread &th) { th.join(); }); +} + +int main() +{ + initTracer(); + + auto root_span = get_tracer()->StartSpan(__func__); + trace_api::Scope scope(root_span); + + run_threads(); +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/otlp/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/otlp/BUILD new file mode 100644 index 000000000..795493faa --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/otlp/BUILD @@ -0,0 +1,73 @@ +cc_binary( + name = "example_otlp_grpc", + srcs = [ + "grpc_main.cc", + ], + tags = [ + "examples", + "otlp", + "otlp_grpc", + ], + deps = [ + "//api", + "//examples/common/foo_library:common_foo_library", + "//exporters/otlp:otlp_grpc_exporter", + "//sdk/src/trace", + ], +) + +cc_binary( + name = "example_otlp_http", + srcs = [ + "http_main.cc", + ], + tags = [ + "examples", + "otlp", + "otlp_http", + ], + deps = [ + "//api", + "//examples/common/foo_library:common_foo_library", + "//exporters/otlp:otlp_http_exporter", + "//sdk/src/trace", + ], +) + +cc_binary( + name = "example_otlp_http_log", + srcs = [ + "http_log_main.cc", + ], + tags = [ + "examples", + "otlp", + "otlp_http_log", + ], + deps = [ + "//api", + "//examples/common/logs_foo_library:common_logs_foo_library", + "//exporters/otlp:otlp_http_exporter", + "//exporters/otlp:otlp_http_log_exporter", + "//sdk/src/trace", + ], +) + +cc_binary( + name = "example_otlp_grpc_log", + srcs = [ + "grpc_log_main.cc", + ], + tags = [ + "examples", + "otlp", + "otlp_grpc_log", + ], + deps = [ + "//api", + "//examples/common/logs_foo_library:common_logs_foo_library", + "//exporters/otlp:otlp_grpc_exporter", + "//exporters/otlp:otlp_grpc_log_exporter", + "//sdk/src/trace", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/otlp/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/otlp/CMakeLists.txt new file mode 100755 index 000000000..52d9846a0 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/otlp/CMakeLists.txt @@ -0,0 +1,40 @@ +include_directories( + ${CMAKE_BINARY_DIR}/generated/third_party/opentelemetry-proto + ${CMAKE_SOURCE_DIR}/exporters/otlp/include) + +if(WITH_OTLP_GRPC) + add_executable(example_otlp_grpc grpc_main.cc) + target_link_libraries( + example_otlp_grpc ${CMAKE_THREAD_LIBS_INIT} common_foo_library + opentelemetry_trace opentelemetry_exporter_otlp_grpc gRPC::grpc++) + if(WITH_LOGS_PREVIEW) + add_executable(example_otlp_grpc_log grpc_log_main.cc) + target_link_libraries( + example_otlp_grpc_log + ${CMAKE_THREAD_LIBS_INIT} + common_logs_foo_library + opentelemetry_trace + opentelemetry_logs + opentelemetry_exporter_otlp_grpc + opentelemetry_exporter_otlp_grpc_log + gRPC::grpc++) + endif() +endif() + +if(WITH_OTLP_HTTP) + add_executable(example_otlp_http http_main.cc) + target_link_libraries( + example_otlp_http ${CMAKE_THREAD_LIBS_INIT} common_foo_library + opentelemetry_trace opentelemetry_exporter_otlp_http) + if(WITH_LOGS_PREVIEW) + add_executable(example_otlp_http_log http_log_main.cc) + target_link_libraries( + example_otlp_http_log + ${CMAKE_THREAD_LIBS_INIT} + common_logs_foo_library + opentelemetry_trace + opentelemetry_logs + opentelemetry_exporter_otlp_http + opentelemetry_exporter_otlp_http_log) + endif() +endif() diff --git a/src/jaegertracing/opentelemetry-cpp/examples/otlp/README.md b/src/jaegertracing/opentelemetry-cpp/examples/otlp/README.md new file mode 100644 index 000000000..91f86f8f5 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/otlp/README.md @@ -0,0 +1,69 @@ +# OTLP Exporter Example + +This is an example of how to use the [OpenTelemetry +Protocol](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/README.md) +(OTLP) exporter. + +The application in `grpc_main.cc` initializes an `OtlpGrpcExporter` instance, +the application in `http_main.cc` initializes an `OtlpHttpExporter` instance. +The application in `http_log_main.cc` initializes an `OtlpHttpLogExporter` instance, +the application in `grpc_log_main.cc` initializes an `OtlpGrpcLogExporter` instance. +And they register a tracer provider from the [OpenTelemetry +SDK](https://github.com/open-telemetry/opentelemetry-cpp). The application then +calls a `foo_library` which has been instrumented using the [OpenTelemetry +API](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/api). + +To enable TLS authentication for OTLP grpc exporter, SslCredentials can be used +by specifying the path to client certificate pem file, or the string containing +this certificate via OtlpGrpcExporterOptions. The path to such a .pem file can be +provided as a command-line argument alongwith the collector endpoint to the main +binary invocation above. + +Resulting spans are exported to the **OpenTelemetry Collector** using the OTLP +exporter. The OpenTelemetry Collector can be configured to export to other +backends (see list of [supported +backends](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/README.md)). + +Follow below command to run the **OpenTelemetry Collector** with OTLP receiver +in docker which dumps the received data into console. See [Getting +Started](https://opentelemetry.io/docs/collector/about/) for more information. + +Open a terminal window at the root directory of this repo and launch the +OpenTelemetry Collector with an OTLP receiver by running: + +- On Unix based systems use: + +```console +docker run --rm -it -p 4317:4317 -p 4318:4318 -v $(pwd)/examples/otlp:/cfg otel/opentelemetry-collector:0.38.0 --config=/cfg/opentelemetry-collector-config/config.dev.yaml +``` + +- On Windows use: + +```console +docker run --rm -it -p 4317:4317 -p 4318:4318 -v "%cd%/examples/otlp":/cfg otel/opentelemetry-collector:0.38.0 --config=/cfg/opentelemetry-collector-config/config.dev.yaml +``` + +Note that the OTLP gRPC and HTTP exporters connects to the Collector at `localhost:4317` and `localhost:4318/v1/traces` respectively. This can be changed with first argument from command-line, for example: +`./example_otlp_grpc gateway.docker.internal:4317` and +`./example_otlp_http gateway.docker.internal:4318/v1/traces`. + +Once you have the Collector running, see +[CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on building and +running the example. + +## Additional notes regarding Abseil library + +gRPC internally uses a different version of Abseil than OpenTelemetry C++ SDK. + +One option to optimize your code is to build the SDK with system-provided +Abseil library. If you are using CMake, then `-DWITH_ABSEIL=ON` may be passed +during the build of SDK to reuse the same Abseil library as gRPC. If you are +using Bazel, then `--@io_opentelemetry_cpp/api:with_abseil=true` may be passed +to reuse your Abseil library in your project. + +If you do not want to pursue the above option, and in case if you run into +conflict between Abseil library and OpenTelemetry C++ `absl::variant` +implementation, please include either `grpcpp/grpcpp.h` or +`opentelemetry/exporters/otlp/otlp_grpc_exporter.h` BEFORE any other API +headers. This approach efficiently avoids the conflict between the two different +versions of Abseil. diff --git a/src/jaegertracing/opentelemetry-cpp/examples/otlp/grpc_log_main.cc b/src/jaegertracing/opentelemetry-cpp/examples/otlp/grpc_log_main.cc new file mode 100644 index 000000000..9a578c7fb --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/otlp/grpc_log_main.cc @@ -0,0 +1,77 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW +# include "opentelemetry/exporters/otlp/otlp_grpc_exporter.h" +# include "opentelemetry/exporters/otlp/otlp_grpc_log_exporter.h" +# include "opentelemetry/logs/provider.h" +# include "opentelemetry/sdk/logs/logger_provider.h" +# include "opentelemetry/sdk/logs/simple_log_processor.h" +# include "opentelemetry/sdk/trace/simple_processor.h" +# include "opentelemetry/sdk/trace/tracer_provider.h" +# include "opentelemetry/trace/provider.h" + +# include <string> + +# ifdef BAZEL_BUILD +# include "examples/common/logs_foo_library/foo_library.h" +# else +# include "logs_foo_library/foo_library.h" +# endif + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace otlp = opentelemetry::exporter::otlp; +namespace logs_sdk = opentelemetry::sdk::logs; +namespace logs = opentelemetry::logs; +namespace trace_sdk = opentelemetry::sdk::trace; + +namespace +{ +opentelemetry::exporter::otlp::OtlpGrpcExporterOptions opts; +void InitTracer() +{ + // Create OTLP exporter instance + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new otlp::OtlpGrpcExporter(opts)); + auto processor = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + auto provider = + nostd::shared_ptr<trace::TracerProvider>(new trace_sdk::TracerProvider(std::move(processor))); + // Set the global trace provider + trace::Provider::SetTracerProvider(provider); +} + +void InitLogger() +{ + // Create OTLP exporter instance + auto exporter = std::unique_ptr<logs_sdk::LogExporter>(new otlp::OtlpGrpcLogExporter(opts)); + auto sdkProvider = std::shared_ptr<logs_sdk::LoggerProvider>( + new logs_sdk::LoggerProvider(std::unique_ptr<logs_sdk::LogProcessor>( + new logs_sdk::SimpleLogProcessor(std::move(exporter))))); + auto apiProvider = nostd::shared_ptr<logs::LoggerProvider>(sdkProvider); + auto provider = nostd::shared_ptr<logs::LoggerProvider>(apiProvider); + opentelemetry::logs::Provider::SetLoggerProvider(provider); +} +} // namespace + +int main(int argc, char *argv[]) +{ + if (argc > 1) + { + opts.endpoint = argv[1]; + if (argc > 2) + { + opts.use_ssl_credentials = true; + opts.ssl_credentials_cacert_path = argv[2]; + } + } + InitLogger(); + InitTracer(); + foo_library(); +} +#else +int main() +{ + return 0; +} +#endif
\ No newline at end of file diff --git a/src/jaegertracing/opentelemetry-cpp/examples/otlp/grpc_main.cc b/src/jaegertracing/opentelemetry-cpp/examples/otlp/grpc_main.cc new file mode 100644 index 000000000..2e5eff486 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/otlp/grpc_main.cc @@ -0,0 +1,54 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Make sure to include GRPC exporter first because otherwise Abseil may create +// ambiguity with `nostd::variant`. See issue: +// https://github.com/open-telemetry/opentelemetry-cpp/issues/880 +#include "opentelemetry/exporters/otlp/otlp_grpc_exporter.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +#ifdef BAZEL_BUILD +# include "examples/common/foo_library/foo_library.h" +#else +# include "foo_library/foo_library.h" +#endif + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace otlp = opentelemetry::exporter::otlp; + +namespace +{ +opentelemetry::exporter::otlp::OtlpGrpcExporterOptions opts; +void InitTracer() +{ + // Create OTLP exporter instance + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new otlp::OtlpGrpcExporter(opts)); + auto processor = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + auto provider = + nostd::shared_ptr<trace::TracerProvider>(new trace_sdk::TracerProvider(std::move(processor))); + // Set the global trace provider + trace::Provider::SetTracerProvider(provider); +} +} // namespace + +int main(int argc, char *argv[]) +{ + if (argc > 1) + { + opts.endpoint = argv[1]; + if (argc > 2) + { + opts.use_ssl_credentials = true; + opts.ssl_credentials_cacert_path = argv[2]; + } + } + // Removing this line will leave the default noop TracerProvider in place. + InitTracer(); + + foo_library(); +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/otlp/http_log_main.cc b/src/jaegertracing/opentelemetry-cpp/examples/otlp/http_log_main.cc new file mode 100644 index 000000000..b56dcf5aa --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/otlp/http_log_main.cc @@ -0,0 +1,92 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW +# include "opentelemetry/exporters/otlp/otlp_http_exporter.h" +# include "opentelemetry/exporters/otlp/otlp_http_log_exporter.h" +# include "opentelemetry/logs/provider.h" +# include "opentelemetry/sdk/logs/logger_provider.h" +# include "opentelemetry/sdk/logs/simple_log_processor.h" +# include "opentelemetry/sdk/trace/simple_processor.h" +# include "opentelemetry/sdk/trace/tracer_provider.h" +# include "opentelemetry/trace/provider.h" + +# include <string> + +# ifdef BAZEL_BUILD +# include "examples/common/logs_foo_library/foo_library.h" +# else +# include "logs_foo_library/foo_library.h" +# endif + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace otlp = opentelemetry::exporter::otlp; +namespace logs_sdk = opentelemetry::sdk::logs; +namespace logs = opentelemetry::logs; +namespace trace_sdk = opentelemetry::sdk::trace; + +namespace +{ + +opentelemetry::exporter::otlp::OtlpHttpExporterOptions opts; +void InitTracer() +{ + // Create OTLP exporter instance + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new otlp::OtlpHttpExporter(opts)); + auto processor = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + auto provider = + nostd::shared_ptr<trace::TracerProvider>(new trace_sdk::TracerProvider(std::move(processor))); + // Set the global trace provider + trace::Provider::SetTracerProvider(provider); +} + +opentelemetry::exporter::otlp::OtlpHttpLogExporterOptions logger_opts; +void InitLogger() +{ + logger_opts.console_debug = true; + // Create OTLP exporter instance + auto exporter = + std::unique_ptr<logs_sdk::LogExporter>(new otlp::OtlpHttpLogExporter(logger_opts)); + auto sdkProvider = std::shared_ptr<logs_sdk::LoggerProvider>( + new logs_sdk::LoggerProvider(std::unique_ptr<logs_sdk::LogProcessor>( + new logs_sdk::SimpleLogProcessor(std::move(exporter))))); + auto apiProvider = nostd::shared_ptr<logs::LoggerProvider>(sdkProvider); + auto provider = nostd::shared_ptr<logs::LoggerProvider>(apiProvider); + opentelemetry::logs::Provider::SetLoggerProvider(provider); +} +} // namespace + +int main(int argc, char *argv[]) +{ + if (argc > 1) + { + opts.url = argv[1]; + logger_opts.url = argv[1]; + if (argc > 2) + { + std::string debug = argv[2]; + opts.console_debug = debug != "" && debug != "0" && debug != "no"; + } + + if (argc > 3) + { + std::string binary_mode = argv[3]; + if (binary_mode.size() >= 3 && binary_mode.substr(0, 3) == "bin") + { + opts.content_type = opentelemetry::exporter::otlp::HttpRequestContentType::kBinary; + logger_opts.content_type = opentelemetry::exporter::otlp::HttpRequestContentType::kBinary; + } + } + } + InitLogger(); + InitTracer(); + foo_library(); +} +#else +int main() +{ + return 0; +} +#endif
\ No newline at end of file diff --git a/src/jaegertracing/opentelemetry-cpp/examples/otlp/http_main.cc b/src/jaegertracing/opentelemetry-cpp/examples/otlp/http_main.cc new file mode 100644 index 000000000..8a0b07a14 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/otlp/http_main.cc @@ -0,0 +1,62 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/exporters/otlp/otlp_http_exporter.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +#include <string> + +#ifdef BAZEL_BUILD +# include "examples/common/foo_library/foo_library.h" +#else +# include "foo_library/foo_library.h" +#endif + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace otlp = opentelemetry::exporter::otlp; + +namespace +{ +opentelemetry::exporter::otlp::OtlpHttpExporterOptions opts; +void InitTracer() +{ + // Create OTLP exporter instance + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new otlp::OtlpHttpExporter(opts)); + auto processor = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + auto provider = + nostd::shared_ptr<trace::TracerProvider>(new trace_sdk::TracerProvider(std::move(processor))); + // Set the global trace provider + trace::Provider::SetTracerProvider(provider); +} +} // namespace + +int main(int argc, char *argv[]) +{ + if (argc > 1) + { + opts.url = argv[1]; + if (argc > 2) + { + std::string debug = argv[2]; + opts.console_debug = debug != "" && debug != "0" && debug != "no"; + } + + if (argc > 3) + { + std::string binary_mode = argv[3]; + if (binary_mode.size() >= 3 && binary_mode.substr(0, 3) == "bin") + { + opts.content_type = otlp::HttpRequestContentType::kBinary; + } + } + } + // Removing this line will leave the default noop TracerProvider in place. + InitTracer(); + + foo_library(); +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/otlp/opentelemetry-collector-config/config.dev.yaml b/src/jaegertracing/opentelemetry-cpp/examples/otlp/opentelemetry-collector-config/config.dev.yaml new file mode 100644 index 000000000..f10252b95 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/otlp/opentelemetry-collector-config/config.dev.yaml @@ -0,0 +1,24 @@ +exporters: + logging: + loglevel: DEBUG +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + cors_allowed_origins: + - '*' +service: + pipelines: + traces: + receivers: + - otlp + exporters: + - logging + logs: + receivers: + - otlp + exporters: + - logging diff --git a/src/jaegertracing/opentelemetry-cpp/examples/plugin/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/plugin/CMakeLists.txt new file mode 100644 index 000000000..081d08b0a --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/plugin/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(load) +add_subdirectory(plugin) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/plugin/load/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/plugin/load/BUILD new file mode 100644 index 000000000..8777c83a9 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/plugin/load/BUILD @@ -0,0 +1,12 @@ +cc_binary( + name = "load_plugin", + srcs = [ + "main.cc", + ], + linkopts = [ + "-ldl", + ], + deps = [ + "//api", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/plugin/load/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/plugin/load/CMakeLists.txt new file mode 100644 index 000000000..4677c2494 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/plugin/load/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(load_plugin_example main.cc) +target_link_libraries(load_plugin_example opentelemetry_api ${CMAKE_DL_LIBS}) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/plugin/load/main.cc b/src/jaegertracing/opentelemetry-cpp/examples/plugin/load/main.cc new file mode 100644 index 000000000..41a04baa4 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/plugin/load/main.cc @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/plugin/dynamic_load.h" + +#include <cstring> +#include <fstream> +#include <iostream> +#include <iterator> +#include <memory> +#include <string> + +int main(int argc, char *argv[]) +{ + if (argc != 3) + { + std::cerr << "Usage: load_plugin <plugin> <config>\n"; + return -1; + } + std::string error_message; + auto factory = opentelemetry::plugin::LoadFactory(argv[1], error_message); + if (factory == nullptr) + { + std::cerr << "Failed to load opentelemetry plugin: " << error_message << "\n"; + return -1; + } + std::ifstream config_in{argv[2]}; + if (!config_in.good()) + { + std::perror("Failed to open config file"); + return -1; + } + std::string config{std::istreambuf_iterator<char>{config_in}, std::istreambuf_iterator<char>{}}; + auto tracer = factory->MakeTracer(config, error_message); + if (tracer == nullptr) + { + std::cerr << "Failed to make tracer: " << error_message << "\n"; + return -1; + } + auto span = tracer->StartSpan("abc"); + return 0; +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/BUILD new file mode 100644 index 000000000..a26a0c6e2 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/BUILD @@ -0,0 +1,12 @@ +cc_binary( + name = "example_plugin.so", + srcs = [ + "factory_impl.cc", + "tracer.cc", + "tracer.h", + ], + linkshared = 1, + deps = [ + "//api", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/CMakeLists.txt new file mode 100644 index 000000000..c24a8d1a1 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(example_plugin SHARED tracer.cc factory_impl.cc) +target_link_libraries(example_plugin opentelemetry_api) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/factory_impl.cc b/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/factory_impl.cc new file mode 100644 index 000000000..b3bafe705 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/factory_impl.cc @@ -0,0 +1,49 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/plugin/factory.h" +#include "opentelemetry/plugin/hook.h" +#include "tracer.h" + +namespace nostd = opentelemetry::nostd; +namespace plugin = opentelemetry::plugin; + +class TracerHandle final : public plugin::TracerHandle +{ +public: + explicit TracerHandle(std::shared_ptr<Tracer> &&tracer) noexcept : tracer_{std::move(tracer)} {} + + // opentelemetry::plugin::TracerHandle + Tracer &tracer() const noexcept override { return *tracer_; } + +private: + std::shared_ptr<Tracer> tracer_; +}; + +class FactoryImpl final : public plugin::Factory::FactoryImpl +{ +public: + // opentelemetry::plugin::Factory::FactoryImpl + nostd::unique_ptr<plugin::TracerHandle> MakeTracerHandle( + nostd::string_view tracer_config, + nostd::unique_ptr<char[]> &error_message) const noexcept override + { + std::shared_ptr<Tracer> tracer{new (std::nothrow) Tracer{""}}; + if (tracer == nullptr) + { + return nullptr; + } + return nostd::unique_ptr<TracerHandle>{new (std::nothrow) TracerHandle{std::move(tracer)}}; + } +}; + +static nostd::unique_ptr<plugin::Factory::FactoryImpl> MakeFactoryImpl( + const plugin::LoaderInfo &loader_info, + nostd::unique_ptr<char[]> &error_message) noexcept +{ + (void)loader_info; + (void)error_message; + return nostd::unique_ptr<plugin::Factory::FactoryImpl>{new (std::nothrow) FactoryImpl{}}; +} + +OPENTELEMETRY_DEFINE_PLUGIN_HOOK(MakeFactoryImpl); diff --git a/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/tracer.cc b/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/tracer.cc new file mode 100644 index 000000000..517575c94 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/tracer.cc @@ -0,0 +1,75 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "tracer.h" +#include "opentelemetry/nostd/unique_ptr.h" + +#include <iostream> +#include <memory> + +namespace nostd = opentelemetry::nostd; +namespace common = opentelemetry::common; +namespace trace = opentelemetry::trace; +namespace context = opentelemetry::context; + +namespace +{ +class Span final : public trace::Span +{ +public: + Span(std::shared_ptr<Tracer> &&tracer, + nostd::string_view name, + const common::KeyValueIterable & /*attributes*/, + const trace::SpanContextKeyValueIterable & /*links*/, + const trace::StartSpanOptions & /*options*/) noexcept + : tracer_{std::move(tracer)}, name_{name}, span_context_{trace::SpanContext::GetInvalid()} + { + std::cout << "StartSpan: " << name << "\n"; + } + + ~Span() { std::cout << "~Span\n"; } + + // opentelemetry::trace::Span + void SetAttribute(nostd::string_view /*name*/, + const common::AttributeValue & /*value*/) noexcept override + {} + + void AddEvent(nostd::string_view /*name*/) noexcept override {} + + void AddEvent(nostd::string_view /*name*/, + common::SystemTimestamp /*timestamp*/) noexcept override + {} + + void AddEvent(nostd::string_view /*name*/, + common::SystemTimestamp /*timestamp*/, + const common::KeyValueIterable & /*attributes*/) noexcept override + {} + + void SetStatus(trace::StatusCode /*code*/, nostd::string_view /*description*/) noexcept override + {} + + void UpdateName(nostd::string_view /*name*/) noexcept override {} + + void End(const trace::EndSpanOptions & /*options*/) noexcept override {} + + bool IsRecording() const noexcept override { return true; } + + trace::SpanContext GetContext() const noexcept override { return span_context_; } + +private: + std::shared_ptr<Tracer> tracer_; + std::string name_; + trace::SpanContext span_context_; +}; +} // namespace + +Tracer::Tracer(nostd::string_view /*output*/) {} + +nostd::shared_ptr<trace::Span> Tracer::StartSpan(nostd::string_view name, + const common::KeyValueIterable &attributes, + const trace::SpanContextKeyValueIterable &links, + const trace::StartSpanOptions &options) noexcept +{ + return nostd::shared_ptr<trace::Span>{ + new (std::nothrow) Span{this->shared_from_this(), name, attributes, links, options}}; +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/tracer.h b/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/tracer.h new file mode 100644 index 000000000..af2a4c5e9 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/plugin/plugin/tracer.h @@ -0,0 +1,26 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include <memory> + +#include "opentelemetry/trace/tracer.h" + +class Tracer final : public opentelemetry::trace::Tracer, + public std::enable_shared_from_this<Tracer> +{ +public: + explicit Tracer(opentelemetry::nostd::string_view output); + + // opentelemetry::trace::Tracer + opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span> StartSpan( + opentelemetry::nostd::string_view name, + const opentelemetry::common::KeyValueIterable & /*attributes*/, + const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/, + const opentelemetry::trace::StartSpanOptions & /*options */) noexcept override; + + void ForceFlushWithMicroseconds(uint64_t /*timeout*/) noexcept override {} + + void CloseWithMicroseconds(uint64_t /*timeout*/) noexcept override {} +}; diff --git a/src/jaegertracing/opentelemetry-cpp/examples/prometheus/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/BUILD new file mode 100644 index 000000000..edbfde61e --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/BUILD @@ -0,0 +1,14 @@ +cc_binary( + name = "prometheus_example", + srcs = [ + "main.cc", + ], + linkopts = ["-pthread"], + tags = ["ostream"], + deps = [ + "//api", + "//examples/common/metrics_foo_library:common_metrics_foo_library", + "//exporters/prometheus:prometheus_exporter", + "//sdk/src/metrics", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/prometheus/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/CMakeLists.txt new file mode 100644 index 000000000..b377920de --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/CMakeLists.txt @@ -0,0 +1,5 @@ +include_directories(${CMAKE_SOURCE_DIR}/exporters/prometheus/include) +add_executable(prometheus_example main.cc) +target_link_libraries( + prometheus_example ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics + prometheus_exporter opentelemetry_resources common_metrics_foo_library) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/prometheus/README.md b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/README.md new file mode 100644 index 000000000..d7e284a0e --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/README.md @@ -0,0 +1,208 @@ +# Getting Started with Prometheus and Grafana + +- [Export metrics from the application](#export-metrics-from-the-application) + - [Check results in the browser](#check-results-in-the-browser) +- [Collect metrics using Prometheus](#collect-metrics-using-prometheus) + - [Configuration](#configuration) + - [Start Prometheus](#start-prometheus) + - [View results in Prometheus](#view-results-in-prometheus) +- [Explore metrics using Grafana](#explore-metrics-using-grafana) +- [Learn more](#learn-more) + +## Export metrics from the application + +It is highly recommended to go over the [ostream-metrics](../metrics_simple/README.md) +doc before following along this document. + +Run the application with: + +```sh +bazel run //examples/prometheus:prometheus_example +``` + +The main difference between the [ostream-metrics](../metrics_simple/README.md) +example with this one is that the line below is replaced: + +```cpp +std::unique_ptr<metric_sdk::MetricExporter> exporter{ + new exportermetrics::OStreamMetricExporter}; + +``` + +with + +```cpp +std::unique_ptr<metrics_sdk::MetricExporter> exporter{ + new metrics_exporter::PrometheusExporter(opts)}; +``` + +OpenTelemetry `PrometheusExporter` will export +data via the endpoint defined by +`metrics_exporter::PrometheusExporterOptions::url`, +which is `http://localhost:9464/` by default. + +```mermaid +graph LR + +subgraph SDK + MeterProvider + MetricReader[PeriodicExportingMetricReader] + PrometheusExporter["PrometheusExporter<br/>(http://localhost:9464/)"] +end + +subgraph API + Instrument["Meter(#quot;prometheus_metric_example#quot;, #quot;1.0#quot;)<br/>Histogram(#quot;prometheus_metric_example_histogram#quot;)"] +end + +Instrument --> | Measurements | MeterProvider + +MeterProvider --> | Metrics | MetricReader --> | Pull | PrometheusExporter +``` + +Also, for our learning purpose, we use a while-loop to keep recoring random +values until the program stops. + +```cpp +while (true) +{ + double val = (rand() % 700) + 1.1; + std::map<std::string, std::string> labels = get_random_attr(); + auto labelkv = opentelemetry::common::KeyValueIterableView<decltype(labels)>{labels}; + histogram_counter->Record(val, labelkv, context); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); +} +``` + +### Check results in the browser + +Start the application and keep it running. Now we should be able to see the +metrics at [http://localhost:9464/metrics](http://localhost:9464/metrics) from a +web browser: + +![Browser UI](https://user-images.githubusercontent.com/71217171/168492500-12bd1c99-33ab-4515-a294-17bc349b5d13.png) + +Now, we understand how we can configure `PrometheusExporter` to export metrics. +Next, we are going to learn about how to use Prometheus to collect the metrics. + +## Collect metrics using Prometheus + +Follow the [first steps](https://prometheus.io/docs/introduction/first_steps/) +to download the [latest release](https://prometheus.io/download/) of Prometheus. +It is also possible to use `prom/prometheus` docker image. + +### Configuration + +After downloading, extract it to a local location that's easy to +access. We will find the default Prometheus configuration YAML file in the +folder, named `prometheus.yml`. + +```yaml +global: + scrape_interval: 5s + scrape_timeout: 2s + evaluation_interval: 5s +alerting: + alertmanagers: + - follow_redirects: true + scheme: http + timeout: 5s + api_version: v2 + static_configs: + - targets: [localhost:9464] +scrape_configs: + - job_name: otel + static_configs: + - targets: ['localhost:9464'] +``` + +### Start Prometheus + +Follow the instructions from +[starting-prometheus](https://prometheus.io/docs/introduction/first_steps/#starting-prometheus) +to start the Prometheus server and verify it has been started successfully. + +Please note that we will need pass in `prometheus.yml` file as the argument +or mount as volume: + +```console +./prometheus --config.file=prometheus.yml +# OR: +docker run -p 9090:9090 -v $(pwd):/etc/prometheus --network="host" prom/prometheus +``` + +### View results in Prometheus + +To use the graphical interface for viewing our metrics with Prometheus, navigate +to [http://localhost:9090/graph](http://localhost:9090/graph), +and type `prometheus_metric_example_bucket` in the expression bar of the UI; +finally, click the execute button. + +We should be able to see the following chart from the browser: + +![Prometheus UI](https://user-images.githubusercontent.com/71217171/168492437-f9769db1-6f9e-49c6-8ef0-85f5e1188ba0.png) + +From the legend, we can see that the `instance` name and the `job` name are the +values we have set in `prometheus.yml`. + +Congratulations! + +Now we know how to configure Prometheus server and deploy OpenTelemetry +`PrometheusExporter` to export our metrics. Next, we are going to explore a tool +called Grafana, which has powerful visualizations for the metrics. + +## Explore metrics using Grafana + +[Install Grafana](https://grafana.com/docs/grafana/latest/installation/). + +Start the standalone Grafana server (`grafana-server.exe` or +`./bin/grafana-server`, depending on the operating system). Then, use the +browser to navigate to [http://localhost:3000/](http://localhost:3000/). +It is also possible to run `grafana/grafana` container: + +```sh +docker run -d -p 3000:3000 --network="host" grafana/grafana +``` + +Follow the instructions in the Grafana getting started +[doc](https://grafana.com/docs/grafana/latest/getting-started/getting-started/#step-2-log-in) +to log in. + +After successfully logging in, click on the Configuration icon +on the panel at the left hand side, and click on Prometheus. +Type in the default endpoint of Prometheus as suggested by the UI +as the value for the URI. + +```console +http://localhost:9090 +``` + +Then, click on the Explore icon on the left panel of +the website - we should be able to write some queries to explore our metrics +now! + +Feel free to find some handy PromQL +[here](https://promlabs.com/promql-cheat-sheet/). + +![Grafana +UI](https://user-images.githubusercontent.com/71217171/168492482-047a4429-4854-4b3c-a2dd-4d75362090d5.png) + +```mermaid +graph TD + +subgraph Prometheus + PrometheusScraper + PrometheusDatabase +end + +PrometheusExporter["PrometheusExporter<br/>(listening at #quot;http://localhost:9464/#quot;)"] -->|HTTP GET| PrometheusScraper{{"Prometheus scraper<br/>(polling #quot;http://localhost:9464/metrics#quot; every 5 seconds)"}} +PrometheusScraper --> PrometheusDatabase[("Prometheus TSDB (time series database)")] +PrometheusDatabase -->|http://localhost:9090/graph| PrometheusUI["Browser<br/>(Prometheus Dashboard)"] +PrometheusDatabase -->|http://localhost:9090/api/| Grafana[Grafana Server] +Grafana -->|http://localhost:3000/dashboard| GrafanaUI["Browser<br/>(Grafana Dashboard)"] +``` + +## Learn more + +- [What is Prometheus?](https://prometheus.io/docs/introduction/overview/) +- [Grafana support for + Prometheus](https://prometheus.io/docs/visualization/grafana/#creating-a-prometheus-graph) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/prometheus/main.cc b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/main.cc new file mode 100644 index 000000000..77a648f55 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/main.cc @@ -0,0 +1,118 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW +# include <memory> +# include <thread> +# include "opentelemetry/exporters/prometheus/exporter.h" +# include "opentelemetry/metrics/provider.h" +# include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h" +# include "opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h" +# include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h" +# include "opentelemetry/sdk/metrics/meter.h" +# include "opentelemetry/sdk/metrics/meter_provider.h" + +# ifdef BAZEL_BUILD +# include "examples/common/metrics_foo_library/foo_library.h" +# else +# include "metrics_foo_library/foo_library.h" +# endif + +namespace metrics_sdk = opentelemetry::sdk::metrics; +namespace nostd = opentelemetry::nostd; +namespace common = opentelemetry::common; +namespace metrics_exporter = opentelemetry::exporter::metrics; +namespace metrics_api = opentelemetry::metrics; + +namespace +{ + +void initMetrics(const std::string &name, const std::string &addr) +{ + metrics_exporter::PrometheusExporterOptions opts; + if (!addr.empty()) + { + opts.url = addr; + } + std::puts("PrometheusExporter example program running ..."); + + std::unique_ptr<metrics_sdk::MetricExporter> exporter{ + new metrics_exporter::PrometheusExporter(opts)}; + + std::string version{"1.2.0"}; + std::string schema{"https://opentelemetry.io/schemas/1.2.0"}; + + // Initialize and set the global MeterProvider + metrics_sdk::PeriodicExportingMetricReaderOptions options; + options.export_interval_millis = std::chrono::milliseconds(1000); + options.export_timeout_millis = std::chrono::milliseconds(500); + std::unique_ptr<metrics_sdk::MetricReader> reader{ + new metrics_sdk::PeriodicExportingMetricReader(std::move(exporter), options)}; + auto provider = std::shared_ptr<metrics_api::MeterProvider>(new metrics_sdk::MeterProvider()); + auto p = std::static_pointer_cast<metrics_sdk::MeterProvider>(provider); + p->AddMetricReader(std::move(reader)); + + // counter view + std::string counter_name = name + "_counter"; + std::unique_ptr<metrics_sdk::InstrumentSelector> instrument_selector{ + new metrics_sdk::InstrumentSelector(metrics_sdk::InstrumentType::kCounter, counter_name)}; + std::unique_ptr<metrics_sdk::MeterSelector> meter_selector{ + new metrics_sdk::MeterSelector(name, version, schema)}; + std::unique_ptr<metrics_sdk::View> sum_view{ + new metrics_sdk::View{name, "description", metrics_sdk::AggregationType::kSum}}; + p->AddView(std::move(instrument_selector), std::move(meter_selector), std::move(sum_view)); + + // histogram view + std::string histogram_name = name + "_histogram"; + std::unique_ptr<metrics_sdk::InstrumentSelector> histogram_instrument_selector{ + new metrics_sdk::InstrumentSelector(metrics_sdk::InstrumentType::kHistogram, histogram_name)}; + std::unique_ptr<metrics_sdk::MeterSelector> histogram_meter_selector{ + new metrics_sdk::MeterSelector(name, version, schema)}; + std::unique_ptr<metrics_sdk::View> histogram_view{ + new metrics_sdk::View{name, "description", metrics_sdk::AggregationType::kHistogram}}; + p->AddView(std::move(histogram_instrument_selector), std::move(histogram_meter_selector), + std::move(histogram_view)); + metrics_api::Provider::SetMeterProvider(provider); +} +} // namespace + +int main(int argc, char **argv) +{ + std::string example_type; + std::string addr{"localhost:8080"}; + if (argc == 1) + { + std::puts("usage: $prometheus_example <example type> <url>"); + } + + if (argc >= 2) + { + example_type = argv[1]; + } + if (argc > 2) + { + addr = argv[2]; + } + + std::string name{"prometheus_metric_example"}; + initMetrics(name, addr); + + if (example_type == "counter") + { + foo_library::counter_example(name); + } + else if (example_type == "histogram") + { + foo_library::histogram_example(name); + } + else + { + std::thread counter_example{&foo_library::counter_example, name}; + std::thread histogram_example{&foo_library::histogram_example, name}; + counter_example.join(); + histogram_example.join(); + } +} +#else +int main() {} +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/examples/prometheus/prometheus.yml b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/prometheus.yml new file mode 100644 index 000000000..17c42fda3 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/prometheus.yml @@ -0,0 +1,16 @@ +global: + scrape_interval: 5s + scrape_timeout: 2s + evaluation_interval: 5s +alerting: + alertmanagers: + - follow_redirects: true + scheme: http + timeout: 5s + api_version: v2 + static_configs: + - targets: [localhost:9464] +scrape_configs: + - job_name: otel + static_configs: + - targets: ['localhost:9464']
\ No newline at end of file diff --git a/src/jaegertracing/opentelemetry-cpp/examples/prometheus/run.sh b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/run.sh new file mode 100644 index 000000000..412c6ef45 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/prometheus/run.sh @@ -0,0 +1 @@ +docker run -p 9090:9090 -v $(pwd):/etc/prometheus --network="host" prom/prometheus
\ No newline at end of file diff --git a/src/jaegertracing/opentelemetry-cpp/examples/simple/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/simple/BUILD new file mode 100644 index 000000000..6a5a76646 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/simple/BUILD @@ -0,0 +1,15 @@ +cc_binary( + name = "example_simple", + srcs = [ + "main.cc", + ], + tags = [ + "examples", + "ostream", + ], + deps = [ + "//api", + "//examples/common/foo_library:common_foo_library", + "//exporters/ostream:ostream_span_exporter", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/simple/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/simple/CMakeLists.txt new file mode 100644 index 000000000..4368039c1 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/simple/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) + +add_executable(example_simple main.cc) +target_link_libraries( + example_simple ${CMAKE_THREAD_LIBS_INIT} common_foo_library + opentelemetry_trace opentelemetry_exporter_ostream_span) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/simple/README.md b/src/jaegertracing/opentelemetry-cpp/examples/simple/README.md new file mode 100644 index 000000000..b3c449c53 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/simple/README.md @@ -0,0 +1,12 @@ + +# Simple Trace Example + +In this example, the application in `main.cc` initializes and registers a tracer +provider from the [OpenTelemetry +SDK](https://github.com/open-telemetry/opentelemetry-cpp). The application then +calls a `foo_library` which has been instrumented using the [OpenTelemetry +API](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/api). +Resulting telemetry is directed to stdout through the StdoutSpanExporter. + +See [CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on building and +running the example. diff --git a/src/jaegertracing/opentelemetry-cpp/examples/simple/main.cc b/src/jaegertracing/opentelemetry-cpp/examples/simple/main.cc new file mode 100644 index 000000000..d022e5c23 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/simple/main.cc @@ -0,0 +1,41 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +// Using an exporter that simply dumps span data to stdout. +#ifdef BAZEL_BUILD +# include "examples/common/foo_library/foo_library.h" +#else +# include "foo_library/foo_library.h" +#endif +#include "opentelemetry/exporters/ostream/span_exporter.h" + +namespace trace_api = opentelemetry::trace; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace nostd = opentelemetry::nostd; +namespace +{ +void initTracer() +{ + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>( + new opentelemetry::exporter::trace::OStreamSpanExporter); + auto processor = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + auto provider = nostd::shared_ptr<trace_api::TracerProvider>( + new trace_sdk::TracerProvider(std::move(processor))); + + // Set the global trace provider + trace_api::Provider::SetTracerProvider(provider); +} +} // namespace + +int main() +{ + // Removing this line will leave the default noop TracerProvider in place. + initTracer(); + + foo_library(); +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/zipkin/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/examples/zipkin/CMakeLists.txt new file mode 100644 index 000000000..f55f363d7 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/zipkin/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories(${CMAKE_SOURCE_DIR}/exporters/zipkin/include) + +add_executable(example_zipkin main.cc) +target_link_libraries( + example_zipkin ${CMAKE_THREAD_LIBS_INIT} common_foo_library + opentelemetry_trace opentelemetry_exporter_zipkin_trace) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/zipkin/README.md b/src/jaegertracing/opentelemetry-cpp/examples/zipkin/README.md new file mode 100644 index 000000000..17d325ecb --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/zipkin/README.md @@ -0,0 +1,32 @@ +# Zipkin Exporter Example + +This is an example of how to use the Zipkin exporter. + +The application in `main.cc` initializes an `ZipkinExporter` instance and uses +it to register a tracer provider from the [OpenTelemetry +SDK](https://github.com/open-telemetry/opentelemetry-cpp). The application then +calls a `foo_library` which has been instrumented using the [OpenTelemetry +API](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/api). + +Resulting spans are exported to the Zipkin server using the Zipkin exporter. + +Note that the Zipkin exporter connects to the server at `localhost:9411` by +default. + +## Running Zipkin server locally + +The quick way to run the Zipkin server is using Docker container : + +``console + +$ docker run -d -p 9411:9411 openzipkin/zipkin + +`` + +## Running Zipkin example + +Build this example using instructions in [INSTALL.md](../../INSTALL.md). + +## Viewing the traces + +Please visit the Zipkin UI endpoint `http://localhost:9411` diff --git a/src/jaegertracing/opentelemetry-cpp/examples/zipkin/main.cc b/src/jaegertracing/opentelemetry-cpp/examples/zipkin/main.cc new file mode 100644 index 000000000..352114749 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/zipkin/main.cc @@ -0,0 +1,49 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/exporters/zipkin/zipkin_exporter.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +#ifdef BAZEL_BUILD +# include "examples/common/foo_library/foo_library.h" +#else +# include "foo_library/foo_library.h" +#endif + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace zipkin = opentelemetry::exporter::zipkin; +namespace resource = opentelemetry::sdk::resource; + +namespace +{ +zipkin::ZipkinExporterOptions opts; +void InitTracer() +{ + // Create zipkin exporter instance + resource::ResourceAttributes attributes = {{"service.name", "zipkin_demo_service"}}; + auto resource = resource::Resource::Create(attributes); + auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new zipkin::ZipkinExporter(opts)); + auto processor = std::unique_ptr<trace_sdk::SpanProcessor>( + new trace_sdk::SimpleSpanProcessor(std::move(exporter))); + auto provider = nostd::shared_ptr<trace::TracerProvider>( + new trace_sdk::TracerProvider(std::move(processor), resource)); + // Set the global trace provider + trace::Provider::SetTracerProvider(provider); +} +} // namespace + +int main(int argc, char *argv[]) +{ + if (argc == 2) + { + opts.endpoint = argv[1]; + } + // Removing this line will leave the default noop TracerProvider in place. + InitTracer(); + + foo_library(); +} diff --git a/src/jaegertracing/opentelemetry-cpp/examples/zpages/BUILD b/src/jaegertracing/opentelemetry-cpp/examples/zpages/BUILD new file mode 100644 index 000000000..4200398c9 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/zpages/BUILD @@ -0,0 +1,32 @@ +# Copyright 2020, OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package(default_visibility = ["//visibility:public"]) + +cc_binary( + name = "zpages_example", + srcs = [ + "zpages_example.cc", + ], + linkopts = select({ + "//bazel:windows": [], + "//conditions:default": ["-pthread"], + }), + tags = ["examples"], + deps = [ + "//ext:headers", + "//ext/src/zpages", + "//sdk/src/trace", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/examples/zpages/zpages_example.cc b/src/jaegertracing/opentelemetry-cpp/examples/zpages/zpages_example.cc new file mode 100644 index 000000000..2691a7315 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/examples/zpages/zpages_example.cc @@ -0,0 +1,60 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +/** + * This is a basic example for zpages that helps users get familiar with how to + * use this feature in OpenTelemetery + */ +#include <chrono> +#include <iostream> +#include <string> + +#include "opentelemetry/ext/zpages/zpages.h" // Required file include for zpages + +using opentelemetry::common::SteadyTimestamp; +namespace trace_api = opentelemetry::trace; + +int main(int argc, char *argv[]) +{ + + /** + * The following line initializes zPages and starts a webserver at + * http://localhost:30000/tracez/ where spans that are created in the application + * can be viewed. + * Note that the webserver is destroyed after the application ends execution. + */ + ZPages::Initialize(); + auto tracer = trace_api::Provider::GetTracerProvider()->GetTracer(""); + + std::cout << "This example for zPages creates a few types of spans and then " + << "creates a span every second for the duration of the application" + << "\n"; + + // Error span + std::map<std::string, opentelemetry::common::AttributeValue> attribute_map; + attribute_map["completed_search_for"] = "Unknown user"; + tracer->StartSpan("find user", attribute_map) + ->SetStatus(trace_api::StatusCode::kError, "User not found"); + + // Long time duration span + std::map<std::string, opentelemetry::common::AttributeValue> attribute_map2; + attribute_map2["completed_search_for"] = "John Doe"; + trace_api::StartSpanOptions start; + start.start_steady_time = SteadyTimestamp(nanoseconds(1)); + trace_api::EndSpanOptions end; + end.end_steady_time = SteadyTimestamp(nanoseconds(1000000000000)); + tracer->StartSpan("find user", attribute_map2, start)->End(end); + + // Running(deadlock) span + std::map<std::string, opentelemetry::common::AttributeValue> attribute_map3; + attribute_map3["searching_for"] = "Deleted user"; + auto running_span = tracer->StartSpan("find user", attribute_map3); + + // Create a completed span every second till user stops the loop + std::cout << "Presss CTRL+C to stop...\n"; + while (true) + { + std::this_thread::sleep_for(seconds(1)); + tracer->StartSpan("ping user")->End(); + } +} |