Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ cc_library(
"src/datadog/msgpack.cpp",
"src/datadog/msgpack.h",
"src/datadog/null_logger.h",
"src/datadog/otel_process_ctx.cpp",
"src/datadog/otel_process_ctx.h",
"src/datadog/otel_process_ctx_guard.cpp",
"src/datadog/otel_process_ctx_guard.h",
"src/datadog/parse_util.cpp",
"src/datadog/parse_util.h",
"src/datadog/platform_util.h",
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ target_sources(dd-trace-cpp-objects
src/datadog/limiter.cpp
src/datadog/logger.cpp
src/datadog/msgpack.cpp
src/datadog/otel_process_ctx.cpp
src/datadog/otel_process_ctx_guard.cpp
src/datadog/parse_util.cpp
src/datadog/propagation_style.cpp
src/datadog/random.cpp
Expand Down
13 changes: 13 additions & 0 deletions include/datadog/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class TraceSampler;
class SpanSampler;
class IDGenerator;
class InMemoryFile;
class OtelCtxGuard;

class Tracer {
std::shared_ptr<Logger> logger_;
Expand All @@ -51,6 +52,8 @@ class Tracer {
// read to determine if the process is instrumented with a tracer and to
// retrieve relevant tracing information.
std::shared_ptr<InMemoryFile> metadata_file_;
// Owns the published OpenTelemetry process context, if any.
std::unique_ptr<OtelCtxGuard> otel_guard_;
Baggage::Options baggage_opts_;
bool baggage_injection_enabled_;
bool baggage_extraction_enabled_;
Expand All @@ -65,6 +68,16 @@ class Tracer {
Tracer(const FinalizedTracerConfig& config,
const std::shared_ptr<const IDGenerator>& generator);

~Tracer();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declaring a user-defined destructor suppresses the implicit move constructor and move assignment.

Moreover, the implicit copy is now problematic because it will lead to several calls to otel_process_ctx_drop_current(). More precisely, the problem is that:

  • otel_process_ctx_publish() is called from the constructor (via store_config(), line 228);
  • otel_process_ctx_drop_current() is called in then destructor (line 124).

They operate on a process-global singleton (published_state in otel_process_ctx.cpp). So the destructor's drop is global, and it fires for every Tracer instance destroyed, including copies and temporaries.

This notably breaks the implementation of nginx-datadog that uses move and return by value on Tracer.

I suggest adding a move-only RAII guard, held by a unique_ptr, so that to transfer the ownership on move. Copy constructor and assignment should be deleted. This is just an idea, maybe a better solution could come from thinking about the whole Otel process context handling.

By the way, TEST_TRACER("move semantics"), line 1885 of test_tracer.cpp is wrong: when the move constructor doesn't exist, it binds to the copy constructor. This test should be fixed!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ughhh thanks for spotting this, my C++-fu is not strong enough to have spotted this one.

In c561524 I've added a guard and a mutex that enforces thread-safe last-writer-wins semantics for the process context.

And in 0575cde I've tightened the "move semantics" test to not surprise us again in the future.


// Move-only. The otel context guarded by OtelCtxGuard is a process-wide
// singleton; duplicating ownership would lead to spurious drops, so copies
// are disallowed.
Tracer(Tracer&&) noexcept;
Tracer& operator=(Tracer&&) noexcept;
Tracer(const Tracer&) = delete;
Tracer& operator=(const Tracer&) = delete;

// Create a new trace and return the root span of the trace. Optionally
// specify a `config` indicating the attributes of the root span.
Span create_span();
Expand Down
3 changes: 3 additions & 0 deletions include/datadog/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

namespace datadog::tracing {

// This library's name
extern const char *const tracer_library_name;

// The release version at or before this code revision, e.g. "v0.1.12".
// That is, this code is at least as recent as `tracer_version`, but may be
// more recent.
Expand Down
5 changes: 3 additions & 2 deletions src/datadog/error.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include <datadog/error.h>
#include <datadog/version.h>

#include <ostream>

namespace datadog {
namespace tracing {

std::ostream& operator<<(std::ostream& stream, const Error& error) {
return stream << "[dd-trace-cpp error code " << int(error.code) << "] "
<< error.message;
return stream << "[" << tracer_library_name << " error code "
<< int(error.code) << "] " << error.message;
}

Error Error::with_prefix(StringView prefix) const {
Expand Down
Loading
Loading