opentelemetry-cpp/examples/etw_threads/main.cc

155 lines
3.8 KiB
C++

// 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;
}