Skip to content

Commit

Permalink
Merge branch 'main' into nonrecordable-span
Browse files Browse the repository at this point in the history
  • Loading branch information
lalitb authored Jul 1, 2021
2 parents 9cd7a38 + 8556485 commit fc7247c
Show file tree
Hide file tree
Showing 9 changed files with 346 additions and 22 deletions.
2 changes: 1 addition & 1 deletion api/include/opentelemetry/context/runtime_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ inline Token::~Token()
}

// The ThreadLocalContextStorage class is a derived class from
// RuntimeContextStorage and provides a wrapper for propogating context through
// RuntimeContextStorage and provides a wrapper for propagating context through
// cpp thread locally. This file must be included to use the RuntimeContext
// class if another implementation has not been registered.
class ThreadLocalContextStorage : public RuntimeContextStorage
Expand Down
3 changes: 3 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ if(WITH_OTLP_GRPC OR WITH_OTLP_HTTP)
add_subdirectory(otlp)
add_subdirectory(grpc)
endif()
if(WITH_ETW)
add_subdirectory(etw_threads)
endif()
if(WITH_JAEGER)
add_subdirectory(jaeger)
endif()
Expand Down
6 changes: 6 additions & 0 deletions examples/etw_threads/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
32 changes: 32 additions & 0 deletions examples/etw_threads/README.md
Original file line number Diff line number Diff line change
@@ -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.
154 changes: 154 additions & 0 deletions examples/etw_threads/main.cc
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit fc7247c

Please sign in to comment.