diff --git a/MODULE.bazel b/MODULE.bazel index ca9af3fd..3b455135 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "dd-trace-cpp", - version = "2.0.1", + version = "2.1.2", ) bazel_dep(name = "abseil-cpp", version = "20260107.1", repo_name = "com_google_absl") diff --git a/docs/README.md b/docs/README.md index 41d91c18..99adaf43 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,4 +3,5 @@ This directory contains documentation of the Datadog C++ Tracer, including: - [Design](design.md) +- [Conventions and Rationale](conventions.md) - [Development Processes](development.md) diff --git a/docs/conventions.md b/docs/conventions.md new file mode 100644 index 00000000..353954a9 --- /dev/null +++ b/docs/conventions.md @@ -0,0 +1,50 @@ +# Datadog C++ Tracer Conventions and Rationale + +## C++ Version + +We use **C++17** to ensure maximum compatibility. + +## Build Systems + +**CMake** is the primary build system supported, as documented in [the main Readme](../README.md). It is +how downstreams consumers, such as the Datadog Nginx module, embed the library (see +[nginx-datadog/CMakeLists.txt](https://github.com/DataDog/nginx-datadog/blob/c29a57f/CMakeLists.txt#L121)). + +**Bazel** is used internally for CI and by the Envoy integration (see +[envoy/source/extensions/tracers/datadog/BUILD](https://github.com/envoyproxy/envoy/blob/9d47ea91cc/source/extensions/tracers/datadog/BUILD#L52)). + +## C Standard Libaries + +We support **glibc** (GUN C Library) and [**musl**](https://en.wikipedia.org/wiki/Musl) (notably used by Alpine Linux). + +## C++ Standard Library vs Abseil + +Envoy uses [**Abseil**](https://abseil.io) instead of the C++ `std` types. It builds `dd-trace-cpp` +with the [-DDD_USE_ABSEIL_FOR_ENVOY +flag](https://github.com/envoyproxy/envoy/blob/9d47ea91cc/source/extensions/tracers/datadog/BUILD#L35-L38), +which is used in +[optional.h](https://github.com/DataDog/dd-trace-cpp/blob/v2.1.1/include/datadog/optional.h#L28-L49) +and +[string_view.h](https://github.com/DataDog/dd-trace-cpp/blob/v2.1.1/include/datadog/string_view.h#L30-L45). + +## Header Files Organization + +We separate public and private APIs. Public headers live in `include/datadog` and are the only ones exported. Internal headers live in `src` and are not installed. + +## Testing Frameworks + +**Catch2** is used for unit tests. + +**Google Benchmark** is used for performance benchmarks. + +## Naming Conventions + +- `class TypeName;` +- `.member_function();` +- `free_function();` +- `f(int func_arg);` +- `int local_var;` +- `int private_member_;` +- `int public_member;` +- `enum Color { red, green, blue };` +- `which_one` diff --git a/docs/decisions.md b/docs/decisions.md deleted file mode 100644 index f9bea6fa..00000000 --- a/docs/decisions.md +++ /dev/null @@ -1,41 +0,0 @@ -Here are some topics that were discussed during the design of this library. - -- Which version of C++ do we require? - - C++17 -- Which C core libraries do we produce binaries for? - - glibc - - musl -- Which build systems do we support? - - CMake - - Bazel -- Which unit testing framework? - - Catch2 - - Google Test -- Error handling options: - - `std::variant` - - homebrew a `std::expected` - - `throw Error(...)` - - `RCode do_thing(T& output)` - - `struct Result { Error error; T value; }` -- Is a `Span` RAII with respect to start/finish? -- When we begin calculating trace metrics within the tracer, we'll need to hit a `/stats` HTTP - endpoint. - - Does it live on the same thread as the `Collector`? - - Do we invent a library-specific `HTTPClient` interface? -- Do we keep using cURL for the default `Collector`? - - In-tree C++ library instead? -- Naming conventions: - - `class TypeName;` - - `.member_function();` - - `free_function();` - - `f(int func_arg);` - - `int local_var;` - - `int private_member_;` - - `int public_member;` - - `enum Color { red, green, blue };` - - `which_one` -- Can tracing be reconfigured at runtime? -- Can multiple tracers share a collector? -- Are rate limits per-tracer, per-process, or other? -- Which clang-format version and configuration do we use? -- Do we separate "public" and "private" APIs, or do we export all headers? diff --git a/docs/design.md b/docs/design.md index 8dfd8b80..6a15556a 100644 --- a/docs/design.md +++ b/docs/design.md @@ -185,11 +185,13 @@ in a subsequent section. `class Collector` is an interface for sending a `TraceSegment`'s spans somewhere once they're all done. It's defined in [collector.h](../include/datadog/collector.h). -It's just one function: `send`. More of a callback than an interface. +It's just one function: `send()`. More of a callback than an interface. A `Collector` is either created by `Tracer` or injected into its configuration. The `Collector` instance is then shared with all `TraceSegment`s created by the `Tracer`. The only thing that a -`TraceSegment` does with the `Collector` is call `send` once the segment is finished. +`TraceSegment` does with the `Collector` is call `send()` once the segment is finished. + +A `Collector` can also be shared by several `Tracer`s. The default implementation is `DatadogAgent`, which is described in the next section. @@ -306,8 +308,10 @@ Objects: - `Tracer` is responsible for creating trace segments. It contains the instances of, and configuration for, the `Collector`, `TraceSampler`, and `SpanSampler`. A tracer is created from a `TracerConfig`. -- `TraceSampler` is used by trace segments to decide when to keep or drop themselves. +- `TraceSampler` is used by trace segments to decide when to keep or drop themselves. It is owned + exclusively by one `Tracer`. - `SpanSampler` is used by trace segments to decide which spans to keep when the segment is dropped. + It is owned exclusively by one `Tracer`. - `TracerConfig` contains all of the information needed to configure the collector, trace sampler, and span sampler, as well as defaults for span properties. @@ -321,8 +325,11 @@ Intended usage is: 6. When all `Span`s in `TraceSegment` are finished, the segment is sent to the `Collector`. -Different instances of `Tracer` are independent of each other. If an application wishes to -reconfigure tracing at runtime, it can create another `Tracer` using the new configuration. +Different instances of `Tracer` are independent of each other. + +If an application wishes to reconfigure tracing at runtime, it can create another `Tracer` using the +new configuration. Some behavior (sampling rate / rules, trace reporting, tags) is reconfigurable at +runtime via Remote Config, through `ConfigManager`. ## EventScheduler diff --git a/include/datadog/collector.h b/include/datadog/collector.h index 5198834f..72ba2723 100644 --- a/include/datadog/collector.h +++ b/include/datadog/collector.h @@ -15,18 +15,18 @@ #include "expected.h" -namespace datadog { -namespace tracing { +namespace datadog::tracing { struct SpanData; class TraceSampler; class Collector { public: - // Submit ownership of the specified `spans` to the collector. If the - // collector delivers a response relevant to trace sampling, reconfigure the - // sampler using the specified `response_handler`. Return an error if one - // occurs. + // Submit ownership of the specified `spans` to the collector. + // If the collector delivers a response relevant to trace sampling, + // reconfigure the sampler using the specified `response_handler`. Return an + // error if one occurs. This must be safe to call from multiple threads + // concurrently. virtual Expected send( std::vector>&& spans, const std::shared_ptr& response_handler) = 0; @@ -43,5 +43,4 @@ class Collector { virtual ~Collector() {} }; -} // namespace tracing -} // namespace datadog +} // namespace datadog::tracing