Skip to content

Commit

Permalink
datadog: Config (final) portion of new tracing library (envoyproxy#26284
Browse files Browse the repository at this point in the history
)

This is the final part of the work proposed in envoyproxy#23958.

This PR additionally contains all of the changes from envoyproxy#26148. This diff will shrink when that PR is merged.

This revision alters the DatadogTracerFactory in source/extensions/tracers/datadog/config.h to produce instances of the new dd-trace-cpp based implementation of the Datadog tracer, instead of the old dd-opentracing-cpp based one.

This revision actually alters the implementation of the Datadog tracer. Previous pull requests have only added code for use here.

This revision also moves some unit tests around:

Two tests that were part of datadog_tracer_impl_test.cc have been moved into agent_http_client_test.cc, because they're about HTTP requests.
One test that was part of datadog_tracer_impl_test.cc has been removed because its behavior is already covered by tests added in other PRs in this series.
The remaining tests in datadog_tracer_impl_test_.cc were moved into config_test.cc, since they all now have to do with the configuration of the tracer and the resulting behavior.
Finally, all references to dd-opentracing-cpp and msgpack have been removed from the repo, and the documentation (READMEs) and demo/ directory from envoyproxy#23958 have been added.

Signed-off-by: David Goffredo <david.goffredo@datadoghq.com>
  • Loading branch information
dgoffredo authored Apr 27, 2023
1 parent 7f26053 commit 9bae445
Show file tree
Hide file tree
Showing 26 changed files with 1,034 additions and 860 deletions.
4 changes: 0 additions & 4 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ build:linux --features=per_object_debug_info
build:linux --action_env=BAZEL_LINKLIBS=-l%:libstdc++.a
build:linux --action_env=BAZEL_LINKOPTS=-lm

# TODO(keith): remove once https://github.com/DataDog/dd-opentracing-cpp/pull/252 is integrated
# this avoids warnings/errors on arm64 Linux builds
build:linux --per_file_copt=external/com_github_datadog_dd_opentracing_cpp/.*.cpp@-Wno-type-limits

# We already have absl in the build, define absl=1 to tell googletest to use absl for backtrace.
build --define absl=1

Expand Down
1 change: 0 additions & 1 deletion bazel/external/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ cc_library(
# @io_opentracing_cpp//:generate_version_h failed - needs porting
tags = ["skip_on_windows"],
deps = [
"@com_github_datadog_dd_opentracing_cpp//:dd_opentracing_cpp",
"@com_github_datadog_dd_trace_cpp//:dd_trace_cpp",
"@com_google_googletest//:gtest",
"@io_opentracing_cpp//:opentracing",
Expand Down
12 changes: 0 additions & 12 deletions bazel/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,6 @@ def envoy_dependencies(skip_targets = []):
_com_github_c_ares_c_ares()
_com_github_circonus_labs_libcircllhist()
_com_github_cyan4973_xxhash()
_com_github_datadog_dd_opentracing_cpp()
_com_github_datadog_dd_trace_cpp()
_com_github_mirror_tclap()
_com_github_envoyproxy_sqlparser()
Expand Down Expand Up @@ -650,17 +649,6 @@ def _io_opentracing_cpp():
actual = "@io_opentracing_cpp//:opentracing",
)

def _com_github_datadog_dd_opentracing_cpp():
external_http_archive("com_github_datadog_dd_opentracing_cpp")
external_http_archive(
name = "com_github_msgpack_msgpack_c",
build_file = "@com_github_datadog_dd_opentracing_cpp//:bazel/external/msgpack.BUILD",
)
native.bind(
name = "dd_opentracing_cpp",
actual = "@com_github_datadog_dd_opentracing_cpp//:dd_opentracing_cpp",
)

def _com_github_datadog_dd_trace_cpp():
external_http_archive("com_github_datadog_dd_trace_cpp")
native.bind(
Expand Down
36 changes: 3 additions & 33 deletions bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -520,32 +520,17 @@ REPOSITORY_LOCATIONS_SPEC = dict(
license = "Apache-2.0",
license_url = "https://github.com/SkyAPM/cpp2sky/blob/v{version}/LICENSE",
),
com_github_datadog_dd_opentracing_cpp = dict(
project_name = "Datadog OpenTracing C++ Client",
project_desc = "Datadog OpenTracing C++ Client",
project_url = "https://github.com/DataDog/dd-opentracing-cpp",
version = "1.2.1",
sha256 = "ae44699e4aa2d21b70ed897a6c0cf3ed7dfb411e1aae4e686e39af75cec7c9bf",
strip_prefix = "dd-opentracing-cpp-{version}",
urls = ["https://github.com/DataDog/dd-opentracing-cpp/archive/v{version}.tar.gz"],
use_category = ["observability_ext"],
extensions = ["envoy.tracers.datadog"],
release_date = "2021-01-27",
cpe = "N/A",
license = "Apache-2.0",
license_url = "https://github.com/DataDog/dd-opentracing-cpp/blob/v{version}/LICENSE",
),
com_github_datadog_dd_trace_cpp = dict(
project_name = "Datadog C++ Tracing Library",
project_desc = "Datadog distributed tracing for C++",
project_url = "https://github.com/DataDog/dd-trace-cpp",
version = "0.1.7",
sha256 = "1dd304885e1d66d78dbeb43a6dc6d08b077802a7a604bb41ed6a02303abac276",
version = "0.1.8",
sha256 = "77162c26ba976b8b18e6daf50beaec39389286840733b08e1627d4e5572d4b51",
strip_prefix = "dd-trace-cpp-{version}",
urls = ["https://github.com/DataDog/dd-trace-cpp/archive/v{version}.tar.gz"],
use_category = ["observability_ext"],
extensions = ["envoy.tracers.datadog"],
release_date = "2023-03-17",
release_date = "2023-03-31",
cpe = "N/A",
license = "Apache-2.0",
license_url = "https://github.com/DataDog/dd-trace-cpp/blob/v{version}/LICENSE",
Expand Down Expand Up @@ -733,21 +718,6 @@ REPOSITORY_LOCATIONS_SPEC = dict(
license = "MIT",
license_url = "https://github.com/jbeder/yaml-cpp/blob/{version}/LICENSE",
),
com_github_msgpack_msgpack_c = dict(
project_name = "msgpack for C/C++",
project_desc = "MessagePack is an efficient binary serialization format",
project_url = "https://github.com/msgpack/msgpack-c",
version = "3.3.0",
sha256 = "6e114d12a5ddb8cb11f669f83f32246e484a8addd0ce93f274996f1941c1f07b",
strip_prefix = "msgpack-{version}",
urls = ["https://github.com/msgpack/msgpack-c/releases/download/cpp-{version}/msgpack-{version}.tar.gz"],
use_category = ["observability_ext"],
extensions = ["envoy.tracers.datadog"],
release_date = "2020-06-05",
cpe = "N/A",
license = "Boost",
license_url = "https://github.com/msgpack/msgpack-c/blob/cpp-{version}/LICENSE_1_0.txt",
),
com_github_google_jwt_verify = dict(
project_name = "jwt_verify_lib",
project_desc = "JWT verification library for C++",
Expand Down
2 changes: 2 additions & 0 deletions source/extensions/tracers/datadog/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Prevent the exclusion of the diagram used in the readme.
!diagram.svg
7 changes: 2 additions & 5 deletions source/extensions/tracers/datadog/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ envoy_cc_library(
name = "datadog_tracer_lib",
srcs = [
"agent_http_client.cc",
"datadog_tracer_impl.cc",
"dict_util.cc",
"event_scheduler.cc",
"logger.cc",
Expand All @@ -25,7 +24,6 @@ envoy_cc_library(
],
hdrs = [
"agent_http_client.h",
"datadog_tracer_impl.h",
"dict_util.h",
"event_scheduler.h",
"logger.h",
Expand All @@ -41,15 +39,14 @@ envoy_cc_library(
],
external_deps = [
"dd_trace_cpp",
"dd_opentracing_cpp",
],
deps = [
"//source/common/config:utility_lib",
"//source/common/http:async_client_utility_lib",
"//source/common/tracing:null_span_lib",
"//source/common/upstream:cluster_update_tracker_lib",
"//source/common/version:version_lib",
"//source/extensions/tracers/common/ot:opentracing_driver_lib",
"@envoy_api//envoy/config/trace/v3:pkg_cc_proto",
"//source/extensions/tracers/common:factory_base_lib",
],
)

Expand Down
181 changes: 181 additions & 0 deletions source/extensions/tracers/datadog/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
Datadog Tracer
==============
This directory contains the source code for distributed tracing using Datadog.
It is a wrapper around [dd-trace-cpp][2], Datadog's core tracing C++ library.

The unit tests are under [../../../../test/extensions/tracers/datadog/][1].

Design
------
The following diagram illustrates the relationships among classes relevant to
this library.

Each node denotes one of the following:

- Hexagonal nodes are interfaces defined by Envoy.
- Nodes that mention the 🐶 namespace (`::datadog::tracing`) are
defined within the Datadog core C++ tracing library, [dd-trace-cpp][2].
- Rectangular nodes are classes defined in this library.

Each edge denotes one of the following relationships:

- Edges labeled "has" indicate that the predecessor node contains an instance of (or
a pointer to) the successor node.
- Edges labeled "implemented by" indicate that the successor node is an
implementation of the predecessor node.

![diagram of components of this library](diagram.svg)

The design of [dd-trace-cpp][2] was informed by the anticipated integration with
Envoy, Nginx, and arbitrary C++ code. The integration-specific operations are:

- Scheduling an event to happen periodically: sending batched traces to the
Datadog Agent.
- Sending an HTTP POST request to the Datadog Agent and handling the resulting
response.

For event scheduling there is the [🐶::EventScheduler][4] interface, whose
Envoy-specific implementation is [EventScheduler](./event_scheduler.h).

For HTTP requests there is the [🐶::HTTPClient][3] interface, whose
Envoy-specific implementation is [AgentHTTPClient](./agent_http_client.h).

Directory Contents
------------------
#### `agent_http_client.{h,cc}`
Contains `class AgentHTTPClient`, which is an implementation of
[🐶::HTTPClient][3] in terms of `Http::AsyncClient::Callbacks`.

The HTTP client is passed to the configuration of
[🐶::DatadogAgent][10], a [🐶::Collector][11]
implementation that uses the HTTP client to send traces to the Datadog Agent.

#### `BUILD`
The Bazel build configuration for this library ("datadog_tracer_lib").

#### `config.{h,cc}`
Contains `class DatadogTracerFactory`, a type that is registered to produce
`Tracer` instances (see `tracer.{h,cc}` below).

#### `dict_util.{h,cc}`
The Datadog core tracing library uses two interfaces, `DictReader` and
`DictWriter`, for reading and writing, respectively, string mappings for trace
context (e.g. HTTP headers).

These files contain implementations of those interfaces used by this library.

#### `event_scheduler.{h,cc}`
Contains `class EventScheduler`, which is an implementation of
[🐶::EventScheduler][4] in terms of `Event::Dispatcher`.

The event scheduler is passed to the configuration of
[🐶::DatadogAgent][10], a [🐶::Collector][11]
implementation that uses the event scheduler to periodically send batched traces
to the Datadog Agent.

#### `logger.{h,cc}`
Contains `class Logger`, which is an implementation of
[🐶::Logger][5] in terms of `spdlog::logger`.

The logger is used by the Datadog core C++ tracing library to print error
diagnostics in cases where an error cannot otherwise be reported, and to print
a banner of the library's configuration on startup.

#### `span.{h,cc}`
Contains `class Span`, which is an implementation of `Tracing::Span` in terms
of [🐶::Span][6].

#### `time_util.{h,cc}`
Contains a conversion function that estimates the value of a [datadog::tracing::TimePoint][7] given a `SystemTime`.

`🐶::TimePoint` contains both a system time point and a steady
(monotonic) time point. The system time is used to determine when a span
begins, while the steady time is used to determine a span's duration once it
has finished.

Envoy's tracing interface exposes only the system time. However, the Datadog
core tracing library uses the steady (monotonic) component of the start time
to later calculate a span's duration. The conversion function estimates the
steady time when a span starts by examining the difference between the current
system time and the provided system time, and uses that difference as the offset
to the current steady time.

#### `tracer_stats.h`
Contains `struct TracerStats`, which is used by this library to keep track of
certain events, such as when sending traces to the Datadog Agent fails.

#### `tracer.{h,cc}`
Contains `class Tracer`, which is an implementation of `Tracing::Driver` in
terms of [🐶::Tracer][8].

Each instance of `Tracer` is local to a worker thread.

`Tracer` is what is returned by `DatadogTracerFactory::createTracerDriverTyped`.

Demo
----
[demo/](demo/) contains a [docker compose][9] setup and supporting
configuration that can be used to manually test Datadog tracing in a local
build of Envoy.

The local build of Envoy runs on the host, while the Datadog Agent and an
upstream HTTP server are services within the [docker compose setup](demo/docker-compose.yaml).

See [demo/envoy](demo/envoy) and
[demo/docker-compose.yaml](demo/docker-compose.yaml).

### Example Usage
In a command shell:
```console
$ cd demo
$ DD_API_KEY=your_datadog_api_key_here docker compose up --build
[...]
demo-http-1 | http node.js web server is running
demo-dd-agent-1 | system-probe exited with code 0, disabling
```

In another command shell:
```console
$ cd demo
$ ./envoy
[...]
[2022-11-10 20:06:10.217][264507][info][main] [source/server/server.cc:907] starting main dispatch loop
```

In a third command shell:
```console
$ curl 'http://localhost:1337'
{
"service": "http",
"headers": {
"host": "localhost:1337",
"user-agent": "curl/7.81.0",
"accept": "*/*",
"x-forwarded-for": "172.16.14.142",
"x-forwarded-proto": "http",
"x-envoy-internal": "true",
"x-request-id": "cfa52b85-8660-9532-b347-bd484da76166",
"x-envoy-expected-rq-timeout-ms": "15000",
"x-foobar-banana": "",
"x-datadog-tags": "_dd.p.dm=-0",
"x-datadog-trace-id": "6487770461011569198",
"x-datadog-parent-id": "6487770461011569198",
"x-datadog-sampling-priority": "1"
}
}
```

If all went well, then the resulting trace will be visible in Datadog's UI. The
service name is `envoy-demo`. See the [Envoy config](demo/envoy.yaml).

[1]: ../../../../test/extensions/tracers/datadog/
[2]: https://github.com/DataDog/dd-trace-cpp
[3]: https://github.com/DataDog/dd-trace-cpp/blob/main/src/datadog/http_client.h
[4]: https://github.com/DataDog/dd-trace-cpp/blob/main/src/datadog/event_scheduler.h
[5]: https://github.com/DataDog/dd-trace-cpp/blob/main/src/datadog/logger.h
[6]: https://github.com/DataDog/dd-trace-cpp/blob/main/src/datadog/span.h
[7]: https://github.com/DataDog/dd-trace-cpp/blob/main/src/datadog/clock.h
[8]: https://github.com/DataDog/dd-trace-cpp/blob/main/src/datadog/tracer.h
[9]: https://docs.docker.com/compose/
[10]: https://github.com/DataDog/dd-trace-cpp/blob/main/src/datadog/datadog_agent.h
[11]: https://github.com/DataDog/dd-trace-cpp/blob/main/src/datadog/collector.h
40 changes: 32 additions & 8 deletions source/extensions/tracers/datadog/config.cc
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#include "source/extensions/tracers/datadog/config.h"

#include <datadog/tracer_config.h>

#include <memory>

#include "envoy/config/trace/v3/datadog.pb.h"
#include "envoy/config/trace/v3/datadog.pb.validate.h"
#include "envoy/registry/registry.h"

#include "source/common/common/utility.h"
#include "source/extensions/tracers/datadog/datadog_tracer_impl.h"

#include "datadog/opentracing.h"
#include "source/common/version/version.h"
#include "source/extensions/tracers/datadog/tracer.h"

namespace Envoy {
namespace Extensions {
Expand All @@ -16,13 +18,35 @@ namespace Datadog {

DatadogTracerFactory::DatadogTracerFactory() : FactoryBase("envoy.tracers.datadog") {}

datadog::tracing::TracerConfig
DatadogTracerFactory::makeConfig(const envoy::config::trace::v3::DatadogConfig& proto_config) {
datadog::tracing::TracerConfig config;
config.defaults.version = "envoy " + Envoy::VersionInfo::version();
config.defaults.name = "envoy.proxy";
if (proto_config.service_name().empty()) {
config.defaults.service = "envoy";
} else {
config.defaults.service = proto_config.service_name();
}
return config;
}

std::string DatadogTracerFactory::makeCollectorReferenceHost(
const envoy::config::trace::v3::DatadogConfig& proto_config) {
std::string collector_reference_host = proto_config.collector_hostname();
if (collector_reference_host.empty()) {
collector_reference_host = proto_config.collector_cluster();
}
return collector_reference_host;
}

Tracing::DriverSharedPtr DatadogTracerFactory::createTracerDriverTyped(
const envoy::config::trace::v3::DatadogConfig& proto_config,
Server::Configuration::TracerFactoryContext& context) {
return std::make_shared<Driver>(proto_config, context.serverFactoryContext().clusterManager(),
context.serverFactoryContext().scope(),
context.serverFactoryContext().threadLocal(),
context.serverFactoryContext().runtime());
return std::make_shared<Tracer>(
proto_config.collector_cluster(), makeCollectorReferenceHost(proto_config),
makeConfig(proto_config), context.serverFactoryContext().clusterManager(),
context.serverFactoryContext().scope(), context.serverFactoryContext().threadLocal());
}

/**
Expand Down
Loading

0 comments on commit 9bae445

Please sign in to comment.