// 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 #include #include #ifndef LOG_DEBUG # include /** * @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 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 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; }