diff --git a/CMakeLists.txt b/CMakeLists.txt
index aa8bc32a..8f690230 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,19 +1,28 @@
-cmake_minimum_required(VERSION 3.13)
+# Note: Make sure that this version is the same as that in
+# "./CheckRequiredCMakeVersion.cmake".
+cmake_minimum_required(VERSION 3.24)
project(dd-trace-cpp)
option(BUILD_COVERAGE "Build code with code coverage profiling instrumentation" OFF)
+option(BUILD_EXAMPLE "Build the example program (example/)" OFF)
set(CMAKE_BUILD_TYPE "RelWithDebInfo")
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+include(ProcessorCount)
+ProcessorCount(NUM_PROCESSORS)
+set(MAKE_JOB_COUNT ${NUM_PROCESSORS} CACHE STRING "Number of jobs to use when building libcurl")
include (ExternalProject)
ExternalProject_Add(curl
URL "https://github.com/curl/curl/releases/download/curl-7_85_0/curl-7.85.0.tar.gz"
URL_MD5 "4e9eb4f434e9be889e510f038754d3de"
BUILD_IN_SOURCE 1
+ DOWNLOAD_EXTRACT_TIMESTAMP 0
SOURCE_DIR ${CMAKE_BINARY_DIR}/curl
CONFIGURE_COMMAND ${CMAKE_BINARY_DIR}/curl/configure --prefix=${CMAKE_BINARY_DIR} --disable-ftp --disable-ldap --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-smtp --disable-gopher --without-ssl --disable-crypto-auth --without-axtls --without-zlib --disable-rtsp --enable-shared=no --enable-static=yes --with-pic --without-brotli
- BUILD_COMMAND make -j16
+ BUILD_COMMAND make -j${MAKE_JOB_COUNT}
INSTALL_COMMAND make install
)
@@ -40,7 +49,8 @@ if(BUILD_COVERAGE)
set(COVERAGE_LIBRARIES gcov)
endif()
-add_library(dd_trace_cpp
+add_library(dd_trace_cpp SHARED)
+target_sources(dd_trace_cpp PRIVATE
src/datadog/cerr_logger.cpp
src/datadog/clock.cpp
src/datadog/collector.cpp
@@ -89,17 +99,74 @@ add_library(dd_trace_cpp
src/datadog/version.cpp
)
-add_dependencies(dd_trace_cpp curl)
+# This library's public headers are just its source headers.
+target_sources(dd_trace_cpp PUBLIC
+ FILE_SET public_headers
+ TYPE HEADERS
+ BASE_DIRS src/
+ FILES
+ src/datadog/cerr_logger.h
+ src/datadog/clock.h
+ src/datadog/collector.h
+ src/datadog/collector_response.h
+ # src/datadog/curl.h except for curl.h
+ src/datadog/datadog_agent_config.h
+ src/datadog/datadog_agent.h
+ src/datadog/default_http_client.h
+ src/datadog/dict_reader.h
+ src/datadog/dict_writer.h
+ src/datadog/environment.h
+ src/datadog/error.h
+ src/datadog/event_scheduler.h
+ src/datadog/expected.h
+ src/datadog/glob.h
+ src/datadog/http_client.h
+ src/datadog/id_generator.h
+ src/datadog/json_fwd.hpp
+ src/datadog/json.hpp
+ src/datadog/limiter.h
+ src/datadog/logger.h
+ src/datadog/msgpack.h
+ src/datadog/net_util.h
+ src/datadog/null_collector.h
+ src/datadog/parse_util.h
+ src/datadog/propagation_styles.h
+ src/datadog/rate.h
+ src/datadog/sampling_decision.h
+ src/datadog/sampling_mechanism.h
+ src/datadog/sampling_priority.h
+ src/datadog/sampling_util.h
+ src/datadog/span_config.h
+ src/datadog/span_data.h
+ src/datadog/span_defaults.h
+ src/datadog/span.h
+ src/datadog/span_matcher.h
+ src/datadog/span_sampler_config.h
+ src/datadog/span_sampler.h
+ src/datadog/tag_propagation.h
+ src/datadog/tags.h
+ src/datadog/threaded_event_scheduler.h
+ src/datadog/tracer_config.h
+ src/datadog/tracer.h
+ src/datadog/trace_sampler_config.h
+ src/datadog/trace_sampler.h
+ src/datadog/trace_segment.h
+ src/datadog/version.h
+)
-# Make the build libcurl visible to dd_trace_cpp and its dependents.
-target_include_directories(dd_trace_cpp PUBLIC ${CMAKE_BINARY_DIR}/include)
+add_dependencies(dd_trace_cpp curl)
-# This library's public headers are just its source headers.
-target_include_directories(dd_trace_cpp INTERFACE src/)
+# Make the build libcurl visible to dd_trace_cpp, but not to its dependents.
+target_include_directories(dd_trace_cpp PRIVATE ${CMAKE_BINARY_DIR}/include)
-# Any dependent target that's linking this library will also need curl and threads.
+# Linking this library requires libcurl and threads.
find_package(Threads REQUIRED)
-target_link_libraries(dd_trace_cpp INTERFACE ${CMAKE_BINARY_DIR}/lib/libcurl.a Threads::Threads)
+target_link_libraries(dd_trace_cpp PRIVATE ${CMAKE_BINARY_DIR}/lib/libcurl.a PUBLIC Threads::Threads)
+
+# When installing, install the library and its public headers.
+
+install(TARGETS dd_trace_cpp
+ FILE_SET public_headers)
if(BUILD_TESTING)
add_subdirectory(test)
diff --git a/CheckRequiredCMakeVersion.cmake b/CheckRequiredCMakeVersion.cmake
new file mode 100644
index 00000000..bb412638
--- /dev/null
+++ b/CheckRequiredCMakeVersion.cmake
@@ -0,0 +1,11 @@
+# "bin/install-cmake" loads this file with "cmake -P [...]" to check whether the
+# installed version of cmake is recent enough.
+#
+# If "cmake -P [...]" exits with status code zero, then the versions are
+# compatible.
+#
+# If it exits with another status code, then either the versions are
+# incompatible or something else went wrong.
+#
+# Note: Make sure that this version is the same as that in "./CMakeLists.txt".
+cmake_minimum_required(VERSION 3.24)
diff --git a/README.md b/README.md
index 6fff21e5..a520f373 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,47 @@
-Check out the latest [testing code coverage report][1].
-
-Logical Component Relationships
--------------------------------
-- Vertices are components.
-- Edges are ownership relationships between components. Each edge is labeled
- by the kind of "smart pointer" that could implement that kind of
- relationship.
-- Components containing a padlock are protected by a mutex.
-
-
-
-Code Component Relationships
-----------------------------
-
-
-Example Usage
--------------
-TODO
-
-Objects
--------
-- _Span_ has a beginning, end, and tags. It is associated with a _TraceSegment_.
-- _TraceSegment_ is part of a trace. It makes sampling decisions, detects when
- it is finished, and sends itself to the _Collector_.
-- _Collector_ receives trace segments. It provides a callback to deliver
- sampler modifications, if applicable.
-- _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.
-- _SpanSampler_ is used by trace segments to decide which spans to keep when
- the segment is dropped.
-- _TracerConfig_ contains all of the information needed to configure the collector,
- trace sampler, and span sampler, as well as defaults for span properties.
-
-Intended usage is:
-
-1. Create a `TracerConfig`.
-2. Use the `TracerConfig` to create a `Tracer`.
-3. Use the `Tracer` to create and/or extract local root `Span`s.
-4. Use `Span` to create children and/or inject context.
-5. Use a `Span`'s `TraceSegment` to perform trace-wide operations.
-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.
-
-[1]: https://datadog.github.io/dd-trace-cpp/datadog
+Build
+-----
+### `cmake && make && make install` Style Build
+Build this library from source using [CMake][1]. Installation places a shared
+library and public headers into the appropriate system directories
+(`/usr/local/[...]`), or to a specified installation prefix.
+
+A recent version of CMake is required (3.24), which might not be in your
+system's package manager. [bin/install-cmake](bin/install-cmake) is an installer
+for a recent CMake.
+
+Here is how to install dd-trace-cpp into `.install/` within the source
+repository.
+```shell
+$ git clone 'https://github.com/datadog/dd-trace-cpp'
+$ cd dd-trace-cpp
+$ bin/install-cmake
+$ mkdir .install
+$ mkdir .build
+$ cd .build
+$ cmake -DCMAKE_INSTALL_PREFIX=../.install ..
+$ make -j $(nproc)
+$ make install
+$ find ../.install -type d
+```
+
+To instead install into `/usr/local/`, omit the `.install` directory and the
+`-DCMAKE_INSTALL_PREFIX=../.install` option.
+
+Then, when building an executable that uses `dd-trace-cpp`, specify the path to
+the installed headers using an appropriate `-I` option. If the library was
+installed into the default system directories, then the `-I` option is not
+needed.
+```shell
+$ c++ -I/path/to/dd-trace-cpp/.install/include -c -o my_app.o my_app.cpp
+```
+
+When linking an executable that uses `dd-trace-cpp`, specify linkage to the
+built library using the `-ldd_trace_cpp` option and an appropriate `-L` option.
+If the library was installed into the default system directories, then the `-L`
+options is not needed. The `-ldd_trace_cpp` option is always needed.
+```shell
+$ c++ -o my_app my_app.o -L/path/to/dd-trace-cpp/.install/lib -ldd_trace_cpp
+```
+
+
+[1]: https://cmake.org/
diff --git a/bin/example b/bin/example
index 329cdfa3..5139ca41 100755
--- a/bin/example
+++ b/bin/example
@@ -26,12 +26,15 @@ if [ "$build_only" -eq 1 ]; then
exit
fi
+trap 'docker compose --project-directory ../example down' INT
+
echo 'Running example...'
if [ "$DD_API_KEY" = '' ]; then
>&2 echo "The DD_API_KEY environment variable must be set to a Datadog API key."
exit 1
fi
docker compose --project-directory ../example up --detach --remove-orphans
-sleep 3
+# docker compose --project-directory ../example logs --follow &
./example/example"$@"
docker compose --project-directory ../example down
+# wait
diff --git a/bin/install-cmake b/bin/install-cmake
new file mode 100755
index 00000000..66761dcd
--- /dev/null
+++ b/bin/install-cmake
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# Install a recent binary release of cmake.
+# Kitware produces a self-installing tarball.
+
+if [ "$(uname)" != Linux ]; then
+ >&2 echo "This installer requires Linux, but instead you're running $(uname)."
+ exit 1
+fi
+
+VERSION=3.24.2
+REPO=$(dirname "$0")/..
+
+# If a suitably recent version of cmake is already installed, then don't bother.
+if >/dev/null command -v cmake && >/dev/null 2>&1 cmake -P "$REPO/CheckRequiredCMakeVersion.cmake"; then
+ echo 'A suitable version of cmake is already installed.'
+ exit
+fi
+
+for required in wget sed; do
+ if ! >/dev/null command -v "$required"; then
+ >&2 echo "This installer requires $required."
+ exit 2
+ fi
+done
+
+ARCHITECTURE=$(uname -m)
+INSTALLER=cmake-${VERSION}-linux-${ARCHITECTURE}.sh
+URL=https://github.com/Kitware/CMake/releases/download/v${VERSION}/${INSTALLER}
+
+maybe_sudo() {
+ if [ "$(id -u)" -eq 0 ]; then
+ "$@"
+ else
+ sudo "$@"
+ fi
+}
+
+cd /tmp
+if ! wget "${URL}"; then
+ >&2 echo "wget failed to download \"${URL}\"."
+ exit 3
+fi
+chmod +x "${INSTALLER}"
+maybe_sudo ./"${INSTALLER}" --skip-license --prefix=/usr/local --exclude-subdir
+rm "${INSTALLER}"
diff --git a/Makefile b/doc/Makefile
similarity index 65%
rename from Makefile
rename to doc/Makefile
index 3d3c3507..7631f39a 100644
--- a/Makefile
+++ b/doc/Makefile
@@ -4,5 +4,5 @@ all: ownership.svg includes.svg
%.svg: %.dot
dot -Grankdir=LR -Tsvg -o $@ $<
-includes.dot: $(wildcard src/*)
- raco graph-includes --exclude-std-c --exclude-std-cpp --exclude-posix --extension h --extension cpp src/ >$@
+includes.dot: $(wildcard ../src/*)
+ raco graph-includes --exclude-std-c --exclude-std-cpp --exclude-posix --extension h --extension cpp ../src/ >$@
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 00000000..6fff21e5
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,52 @@
+Check out the latest [testing code coverage report][1].
+
+Logical Component Relationships
+-------------------------------
+- Vertices are components.
+- Edges are ownership relationships between components. Each edge is labeled
+ by the kind of "smart pointer" that could implement that kind of
+ relationship.
+- Components containing a padlock are protected by a mutex.
+
+
+
+Code Component Relationships
+----------------------------
+
+
+Example Usage
+-------------
+TODO
+
+Objects
+-------
+- _Span_ has a beginning, end, and tags. It is associated with a _TraceSegment_.
+- _TraceSegment_ is part of a trace. It makes sampling decisions, detects when
+ it is finished, and sends itself to the _Collector_.
+- _Collector_ receives trace segments. It provides a callback to deliver
+ sampler modifications, if applicable.
+- _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.
+- _SpanSampler_ is used by trace segments to decide which spans to keep when
+ the segment is dropped.
+- _TracerConfig_ contains all of the information needed to configure the collector,
+ trace sampler, and span sampler, as well as defaults for span properties.
+
+Intended usage is:
+
+1. Create a `TracerConfig`.
+2. Use the `TracerConfig` to create a `Tracer`.
+3. Use the `Tracer` to create and/or extract local root `Span`s.
+4. Use `Span` to create children and/or inject context.
+5. Use a `Span`'s `TraceSegment` to perform trace-wide operations.
+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.
+
+[1]: https://datadog.github.io/dd-trace-cpp/datadog
diff --git a/decisions.md b/doc/decisions.md
similarity index 100%
rename from decisions.md
rename to doc/decisions.md
diff --git a/doc/includes.dot b/doc/includes.dot
new file mode 100644
index 00000000..5e6e4799
--- /dev/null
+++ b/doc/includes.dot
@@ -0,0 +1,296 @@
+digraph G {
+ node0 [label="span_data.cpp"];
+ node1 [label="threaded_event_scheduler.cpp"];
+ node2 [label="rate.cpp"];
+ node3 [label="default_http_client_null.cpp"];
+ node4 [label="trace_segment.h"];
+ node5 [label="dict_writer.h"];
+ node6 [label="tag_propagation.cpp"];
+ node7 [label="json.hpp"];
+ node8 [label="span_sampler.h"];
+ node9 [label="dict_reader.cpp"];
+ node10 [label="tags.h"];
+ node11 [label="tracer_config.h"];
+ node12 [label="curl/curl.h"];
+ node13 [label="expected.h"];
+ node14 [label="limiter.h"];
+ node15 [label="span.h"];
+ node16 [label="sampling_mechanism.cpp"];
+ node17 [label="logger.cpp"];
+ node18 [label="rate.h"];
+ node19 [label="sampling_util.h"];
+ node20 [label="sampling_decision.h"];
+ node21 [label="span_data.h"];
+ node22 [label="datadog_agent_config.h"];
+ node23 [label="sampling_mechanism.h"];
+ node24 [label="msgpack.cpp"];
+ node25 [label="default_http_client.h"];
+ node26 [label="sampling_util.cpp"];
+ node27 [label="datadog_agent_config.cpp"];
+ node28 [label="span.cpp"];
+ node29 [label="json_fwd.hpp"];
+ node30 [label="event_scheduler.cpp"];
+ node31 [label="datadog_agent.h"];
+ node32 [label="error.h"];
+ node33 [label="event_scheduler.h"];
+ node34 [label="tag_propagation.h"];
+ node35 [label="clock.h"];
+ node36 [label="logger.h"];
+ node37 [label="curl.h"];
+ node38 [label="span_defaults.h"];
+ node39 [label="span_defaults.cpp"];
+ node40 [label="tracer.h"];
+ node41 [label="threaded_event_scheduler.h"];
+ node42 [label="parse_util.h"];
+ node43 [label="expected.cpp"];
+ node44 [label="collector.cpp"];
+ node45 [label="id_generator.cpp"];
+ node46 [label="sampling_decision.cpp"];
+ node47 [label="trace_sampler.cpp"];
+ node48 [label="sampling_priority.cpp"];
+ node49 [label="span_sampler.cpp"];
+ node50 [label="collector.h"];
+ node51 [label="curl.cpp"];
+ node52 [label="null_collector.cpp"];
+ node53 [label="cerr_logger.cpp"];
+ node54 [label="collector_response.h"];
+ node55 [label="msgpack.h"];
+ node56 [label="trace_sampler.h"];
+ node57 [label="span_config.cpp"];
+ node58 [label="dict_writer.cpp"];
+ node59 [label="trace_sampler_config.cpp"];
+ node60 [label="span_config.h"];
+ node61 [label="environment.h"];
+ node62 [label="datadog_agent.cpp"];
+ node63 [label="winsock.h"];
+ node64 [label="environment.cpp"];
+ node65 [label="id_generator.h"];
+ node66 [label="tracer_config.cpp"];
+ node67 [label="net_util.cpp"];
+ node68 [label="parse_util.cpp"];
+ node69 [label="http_client.cpp"];
+ node70 [label="null_collector.h"];
+ node71 [label="charconv"];
+ node72 [label="version.h"];
+ node73 [label="span_sampler_config.h"];
+ node74 [label="span_matcher.h"];
+ node75 [label="version.cpp"];
+ node76 [label="propagation_styles.cpp"];
+ node77 [label="dict_reader.h"];
+ node78 [label="span_matcher.cpp"];
+ node79 [label="tracer.cpp"];
+ node80 [label="default_http_client_curl.cpp"];
+ node81 [label="http_client.h"];
+ node82 [label="clock.cpp"];
+ node83 [label="sampling_priority.h"];
+ node84 [label="collector_response.cpp"];
+ node85 [label="propagation_styles.h"];
+ node86 [label="limiter.cpp"];
+ node87 [label="net_util.h"];
+ node88 [label="error.cpp"];
+ node89 [label="trace_sampler_config.h"];
+ node90 [label="cerr_logger.h"];
+ node91 [label="tags.cpp"];
+ node92 [label="trace_segment.cpp"];
+ node93 [label="span_sampler_config.cpp"];
+ subgraph U {
+ edge [dir=none];
+ }
+ subgraph D {
+ node0 -> node38 [];
+ node0 -> node60 [];
+ node0 -> node21 [];
+ node0 -> node55 [];
+ node0 -> node10 [];
+ node0 -> node32 [];
+ node1 -> node41 [];
+ node2 -> node18 [];
+ node3 -> node25 [];
+ node4 -> node85 [];
+ node4 -> node20 [];
+ node4 -> node13 [];
+ node6 -> node34 [];
+ node6 -> node42 [];
+ node6 -> node32 [];
+ node8 -> node35 [];
+ node8 -> node73 [];
+ node8 -> node20 [];
+ node8 -> node14 [];
+ node9 -> node77 [];
+ node11 -> node73 [];
+ node11 -> node22 [];
+ node11 -> node89 [];
+ node11 -> node13 [];
+ node11 -> node32 [];
+ node11 -> node85 [];
+ node11 -> node38 [];
+ node13 -> node32 [];
+ node14 -> node35 [];
+ node14 -> node18 [];
+ node15 -> node35 [];
+ node15 -> node65 [];
+ node15 -> node32 [];
+ node16 -> node23 [];
+ node17 -> node36 [];
+ node17 -> node32 [];
+ node18 -> node13 [];
+ node19 -> node18 [];
+ node20 -> node23 [];
+ node20 -> node18 [];
+ node21 -> node35 [];
+ node21 -> node13 [];
+ node22 -> node13 [];
+ node22 -> node81 [];
+ node24 -> node55 [];
+ node24 -> node32 [];
+ node26 -> node19 [];
+ node27 -> node42 [];
+ node27 -> node22 [];
+ node27 -> node25 [];
+ node27 -> node61 [];
+ node27 -> node41 [];
+ node28 -> node4 [];
+ node28 -> node60 [];
+ node28 -> node5 [];
+ node28 -> node21 [];
+ node28 -> node15 [];
+ node28 -> node10 [];
+ node30 -> node33 [];
+ node31 -> node35 [];
+ node31 -> node50 [];
+ node31 -> node81 [];
+ node31 -> node33 [];
+ node33 -> node32 [];
+ node34 -> node13 [];
+ node37 -> node81 [];
+ node39 -> node38 [];
+ node40 -> node35 [];
+ node40 -> node65 [];
+ node40 -> node15 [];
+ node40 -> node32 [];
+ node40 -> node13 [];
+ node40 -> node11 [];
+ node41 -> node33 [];
+ node42 -> node13 [];
+ node43 -> node13 [];
+ node44 -> node50 [];
+ node45 -> node65 [];
+ node46 -> node20 [];
+ node47 -> node19 [];
+ node47 -> node56 [];
+ node47 -> node83 [];
+ node47 -> node54 [];
+ node47 -> node20 [];
+ node47 -> node21 [];
+ node48 -> node83 [];
+ node49 -> node23 [];
+ node49 -> node19 [];
+ node49 -> node83 [];
+ node49 -> node8 [];
+ node49 -> node21 [];
+ node50 -> node13 [];
+ node51 -> node36 [];
+ node51 -> node37 [];
+ node51 -> node5 [];
+ node51 -> node42 [];
+ node51 -> node12 [];
+ node51 -> node81 [];
+ node51 -> node77 [];
+ node52 -> node70 [];
+ node53 -> node90 [];
+ node54 -> node18 [];
+ node55 -> node13 [];
+ node56 -> node35 [];
+ node56 -> node89 [];
+ node56 -> node18 [];
+ node56 -> node14 [];
+ node57 -> node60 [];
+ node58 -> node5 [];
+ node59 -> node42 [];
+ node59 -> node89 [];
+ node59 -> node7 [];
+ node59 -> node61 [];
+ node60 -> node35 [];
+ node62 -> node36 [];
+ node62 -> node22 [];
+ node62 -> node54 [];
+ node62 -> node7 [];
+ node62 -> node72 [];
+ node62 -> node31 [];
+ node62 -> node56 [];
+ node62 -> node5 [];
+ node62 -> node21 [];
+ node62 -> node55 [];
+ node64 -> node61 [];
+ node66 -> node42 [];
+ node66 -> node90 [];
+ node66 -> node11 [];
+ node66 -> node61 [];
+ node66 -> node70 [];
+ node66 -> node31 [];
+ node67 -> node87 [];
+ node67 -> node63 [];
+ node68 -> node71 [];
+ node68 -> node42 [];
+ node68 -> node32 [];
+ node69 -> node81 [];
+ node70 -> node50 [];
+ node73 -> node74 [];
+ node73 -> node13 [];
+ node73 -> node18 [];
+ node74 -> node13 [];
+ node74 -> node29 [];
+ node75 -> node72 [];
+ node76 -> node85 [];
+ node78 -> node7 [];
+ node78 -> node21 [];
+ node78 -> node74 [];
+ node78 -> node32 [];
+ node79 -> node4 [];
+ node79 -> node60 [];
+ node79 -> node40 [];
+ node79 -> node87 [];
+ node79 -> node8 [];
+ node79 -> node15 [];
+ node79 -> node31 [];
+ node79 -> node10 [];
+ node79 -> node34 [];
+ node79 -> node36 [];
+ node79 -> node56 [];
+ node79 -> node42 [];
+ node79 -> node21 [];
+ node79 -> node77 [];
+ node80 -> node25 [];
+ node80 -> node37 [];
+ node81 -> node13 [];
+ node81 -> node32 [];
+ node82 -> node35 [];
+ node83 -> node23 [];
+ node84 -> node54 [];
+ node86 -> node14 [];
+ node88 -> node32 [];
+ node89 -> node74 [];
+ node89 -> node13 [];
+ node89 -> node18 [];
+ node90 -> node36 [];
+ node91 -> node42 [];
+ node91 -> node10 [];
+ node92 -> node50 [];
+ node92 -> node54 [];
+ node92 -> node8 [];
+ node92 -> node21 [];
+ node92 -> node34 [];
+ node92 -> node36 [];
+ node92 -> node4 [];
+ node92 -> node71 [];
+ node92 -> node56 [];
+ node92 -> node5 [];
+ node92 -> node10 [];
+ node92 -> node32 [];
+ node93 -> node36 [];
+ node93 -> node73 [];
+ node93 -> node7 [];
+ node93 -> node13 [];
+ node93 -> node61 [];
+ }
+}
diff --git a/doc/includes.svg b/doc/includes.svg
new file mode 100644
index 00000000..38f07ec7
--- /dev/null
+++ b/doc/includes.svg
@@ -0,0 +1,1747 @@
+
+
+
+
+
diff --git a/ownership.dot b/doc/ownership.dot
similarity index 100%
rename from ownership.dot
rename to doc/ownership.dot
diff --git a/ownership.svg b/doc/ownership.svg
similarity index 100%
rename from ownership.svg
rename to doc/ownership.svg
diff --git a/example/hasher.cpp b/example/hasher.cpp
index 9edfd8fa..b39ea1e0 100644
--- a/example/hasher.cpp
+++ b/example/hasher.cpp
@@ -10,7 +10,6 @@
// canonical format. Produce a trace whose structure reflects the directory
// structure.
-#include
#include
#include
#include
diff --git a/includes.dot b/includes.dot
deleted file mode 100644
index e69de29b..00000000
diff --git a/includes.svg b/includes.svg
deleted file mode 100644
index d43b7f1d..00000000
--- a/includes.svg
+++ /dev/null
@@ -1,1633 +0,0 @@
-
-
-
-
-
diff --git a/src/datadog/curl.cpp b/src/datadog/curl.cpp
index 01329917..1575d73f 100644
--- a/src/datadog/curl.cpp
+++ b/src/datadog/curl.cpp
@@ -1,9 +1,105 @@
#include "curl.h"
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "dict_reader.h"
+#include "dict_writer.h"
+#include "http_client.h"
+#include "logger.h"
#include "parse_util.h"
namespace datadog {
namespace tracing {
+
+using ErrorHandler = HTTPClient::ErrorHandler;
+using HeadersSetter = HTTPClient::HeadersSetter;
+using ResponseHandler = HTTPClient::ResponseHandler;
+using URL = HTTPClient::URL;
+
+class CurlImpl {
+ std::mutex mutex_;
+ std::shared_ptr logger_;
+ CURLM *multi_handle_;
+ std::unordered_set request_handles_;
+ std::list new_handles_;
+ bool shutting_down_;
+ int num_active_handles_;
+ std::condition_variable no_requests_;
+ std::thread event_loop_;
+
+ struct Request {
+ curl_slist *request_headers = nullptr;
+ std::string request_body;
+ ResponseHandler on_response;
+ ErrorHandler on_error;
+ char error_buffer[CURL_ERROR_SIZE] = "";
+ std::unordered_map response_headers_lower;
+ std::string response_body;
+
+ ~Request();
+ };
+
+ class HeaderWriter : public DictWriter {
+ curl_slist *list_ = nullptr;
+ std::string buffer_;
+
+ public:
+ ~HeaderWriter();
+ curl_slist *release();
+ void set(std::string_view key, std::string_view value) override;
+ };
+
+ class HeaderReader : public DictReader {
+ std::unordered_map *response_headers_lower_;
+ mutable std::string buffer_;
+
+ public:
+ explicit HeaderReader(
+ std::unordered_map *response_headers_lower);
+ std::optional lookup(std::string_view key) const override;
+ void visit(
+ const std::function
+ &visitor) const override;
+ };
+
+ void run();
+ void handle_message(const CURLMsg &);
+ CURLcode log_on_error(CURLcode result);
+ CURLMcode log_on_error(CURLMcode result);
+
+ static std::size_t on_read_header(char *data, std::size_t, std::size_t length,
+ void *user_data);
+ static std::size_t on_read_body(char *data, std::size_t, std::size_t length,
+ void *user_data);
+ static bool is_non_whitespace(unsigned char);
+ static char to_lower(unsigned char);
+ static std::string_view trim(std::string_view);
+
+ public:
+ explicit CurlImpl(const std::shared_ptr &logger);
+ ~CurlImpl();
+
+ Expected post(const URL &url, HeadersSetter set_headers,
+ std::string body, ResponseHandler on_response,
+ ErrorHandler on_error);
+
+ void drain(std::chrono::steady_clock::time_point deadline);
+};
+
namespace {
void throw_on_error(CURLcode result) {
@@ -15,6 +111,21 @@ void throw_on_error(CURLcode result) {
} // namespace
Curl::Curl(const std::shared_ptr &logger)
+ : impl_(new CurlImpl{logger}) {}
+
+Curl::~Curl() { delete impl_; }
+
+Expected Curl::post(const URL &url, HeadersSetter set_headers,
+ std::string body, ResponseHandler on_response,
+ ErrorHandler on_error) {
+ return impl_->post(url, set_headers, body, on_response, on_error);
+}
+
+void Curl::drain(std::chrono::steady_clock::time_point deadline) {
+ impl_->drain(deadline);
+}
+
+CurlImpl::CurlImpl(const std::shared_ptr &logger)
: logger_(logger), shutting_down_(false), num_active_handles_(0) {
curl_global_init(CURL_GLOBAL_ALL);
multi_handle_ = curl_multi_init();
@@ -41,7 +152,7 @@ Curl::Curl(const std::shared_ptr &logger)
}
}
-Curl::~Curl() {
+CurlImpl::~CurlImpl() {
if (multi_handle_ == nullptr) {
// We're not running; nothing to shut down.
return;
@@ -55,9 +166,10 @@ Curl::~Curl() {
event_loop_.join();
}
-Expected Curl::post(const HTTPClient::URL &url, HeadersSetter set_headers,
- std::string body, ResponseHandler on_response,
- ErrorHandler on_error) try {
+Expected CurlImpl::post(const HTTPClient::URL &url,
+ HeadersSetter set_headers, std::string body,
+ ResponseHandler on_response,
+ ErrorHandler on_error) try {
if (multi_handle_ == nullptr) {
return Error{Error::CURL_HTTP_CLIENT_NOT_RUNNING,
"Unable to send request via libcurl because the HTTP client "
@@ -136,15 +248,15 @@ Expected Curl::post(const HTTPClient::URL &url, HeadersSetter set_headers,
return Error{Error::CURL_REQUEST_SETUP_FAILED, curl_easy_strerror(error)};
}
-void Curl::drain(std::chrono::steady_clock::time_point deadline) {
+void CurlImpl::drain(std::chrono::steady_clock::time_point deadline) {
std::unique_lock lock(mutex_);
no_requests_.wait_until(lock, deadline, [this]() {
return num_active_handles_ == 0 && new_handles_.empty();
});
}
-std::size_t Curl::on_read_header(char *data, std::size_t, std::size_t length,
- void *user_data) {
+std::size_t CurlImpl::on_read_header(char *data, std::size_t,
+ std::size_t length, void *user_data) {
const auto request = static_cast(user_data);
// The idea is:
//
@@ -179,18 +291,18 @@ std::size_t Curl::on_read_header(char *data, std::size_t, std::size_t length,
return length;
}
-bool Curl::is_non_whitespace(unsigned char ch) { return !std::isspace(ch); }
+bool CurlImpl::is_non_whitespace(unsigned char ch) { return !std::isspace(ch); }
-char Curl::to_lower(unsigned char ch) { return std::tolower(ch); }
+char CurlImpl::to_lower(unsigned char ch) { return std::tolower(ch); }
-std::size_t Curl::on_read_body(char *data, std::size_t, std::size_t length,
- void *user_data) {
+std::size_t CurlImpl::on_read_body(char *data, std::size_t, std::size_t length,
+ void *user_data) {
const auto request = static_cast(user_data);
request->response_body.append(data, length);
return length;
}
-CURLcode Curl::log_on_error(CURLcode result) {
+CURLcode CurlImpl::log_on_error(CURLcode result) {
if (result != CURLE_OK) {
logger_->log_error(
Error{Error::CURL_HTTP_CLIENT_ERROR, curl_easy_strerror(result)});
@@ -198,7 +310,7 @@ CURLcode Curl::log_on_error(CURLcode result) {
return result;
}
-CURLMcode Curl::log_on_error(CURLMcode result) {
+CURLMcode CurlImpl::log_on_error(CURLMcode result) {
if (result != CURLM_OK) {
logger_->log_error(
Error{Error::CURL_HTTP_CLIENT_ERROR, curl_multi_strerror(result)});
@@ -206,7 +318,7 @@ CURLMcode Curl::log_on_error(CURLMcode result) {
return result;
}
-void Curl::run() {
+void CurlImpl::run() {
int num_messages_remaining;
CURLMsg *message;
std::unique_lock lock(mutex_);
@@ -258,7 +370,7 @@ void Curl::run() {
curl_global_cleanup();
}
-void Curl::handle_message(const CURLMsg &message) {
+void CurlImpl::handle_message(const CURLMsg &message) {
if (message.msg != CURLMSG_DONE) {
return;
}
@@ -299,17 +411,17 @@ void Curl::handle_message(const CURLMsg &message) {
delete &request;
}
-Curl::Request::~Request() { curl_slist_free_all(request_headers); }
+CurlImpl::Request::~Request() { curl_slist_free_all(request_headers); }
-Curl::HeaderWriter::~HeaderWriter() { curl_slist_free_all(list_); }
+CurlImpl::HeaderWriter::~HeaderWriter() { curl_slist_free_all(list_); }
-curl_slist *Curl::HeaderWriter::release() {
+curl_slist *CurlImpl::HeaderWriter::release() {
auto list = list_;
list_ = nullptr;
return list;
}
-void Curl::HeaderWriter::set(std::string_view key, std::string_view value) {
+void CurlImpl::HeaderWriter::set(std::string_view key, std::string_view value) {
buffer_.clear();
buffer_ += key;
buffer_ += ": ";
@@ -318,11 +430,11 @@ void Curl::HeaderWriter::set(std::string_view key, std::string_view value) {
list_ = curl_slist_append(list_, buffer_.c_str());
}
-Curl::HeaderReader::HeaderReader(
+CurlImpl::HeaderReader::HeaderReader(
std::unordered_map *response_headers_lower)
: response_headers_lower_(response_headers_lower) {}
-std::optional Curl::HeaderReader::lookup(
+std::optional CurlImpl::HeaderReader::lookup(
std::string_view key) const {
buffer_.clear();
std::transform(key.begin(), key.end(), std::back_inserter(buffer_),
@@ -335,7 +447,7 @@ std::optional Curl::HeaderReader::lookup(
return found->second;
}
-void Curl::HeaderReader::visit(
+void CurlImpl::HeaderReader::visit(
const std::function
&visitor) const {
for (const auto &[key, value] : *response_headers_lower_) {
diff --git a/src/datadog/curl.h b/src/datadog/curl.h
index ec8f8a74..632c55f1 100644
--- a/src/datadog/curl.h
+++ b/src/datadog/curl.h
@@ -1,98 +1,31 @@
#pragma once
-#include
-
-#include
-#include
#include
-#include
-#include
-#include
-#include
#include
-#include
-#include
-#include
-#include
-#include
+#include
-#include "dict_reader.h"
-#include "dict_writer.h"
#include "http_client.h"
-#include "logger.h"
namespace datadog {
namespace tracing {
-class Curl : public HTTPClient {
- std::mutex mutex_;
- std::shared_ptr logger_;
- CURLM *multi_handle_;
- std::unordered_set request_handles_;
- std::list new_handles_;
- bool shutting_down_;
- int num_active_handles_;
- std::condition_variable no_requests_;
- std::thread event_loop_;
-
- struct Request {
- curl_slist *request_headers = nullptr;
- std::string request_body;
- ResponseHandler on_response;
- ErrorHandler on_error;
- char error_buffer[CURL_ERROR_SIZE] = "";
- std::unordered_map response_headers_lower;
- std::string response_body;
-
- ~Request();
- };
-
- class HeaderWriter : public DictWriter {
- curl_slist *list_ = nullptr;
- std::string buffer_;
-
- public:
- ~HeaderWriter();
- curl_slist *release();
- virtual void set(std::string_view key, std::string_view value) override;
- };
+class CurlImpl;
+class Logger;
- class HeaderReader : public DictReader {
- std::unordered_map *response_headers_lower_;
- mutable std::string buffer_;
-
- public:
- explicit HeaderReader(
- std::unordered_map *response_headers_lower);
- virtual std::optional lookup(
- std::string_view key) const override;
- virtual void visit(
- const std::function
- &visitor) const override;
- };
-
- void run();
- void handle_message(const CURLMsg &);
- CURLcode log_on_error(CURLcode result);
- CURLMcode log_on_error(CURLMcode result);
-
- static std::size_t on_read_header(char *data, std::size_t, std::size_t length,
- void *user_data);
- static std::size_t on_read_body(char *data, std::size_t, std::size_t length,
- void *user_data);
- static bool is_non_whitespace(unsigned char);
- static char to_lower(unsigned char);
- static std::string_view trim(std::string_view);
+class Curl : public HTTPClient {
+ CurlImpl* impl_;
public:
- explicit Curl(const std::shared_ptr &logger);
+ explicit Curl(const std::shared_ptr& logger);
~Curl();
- virtual Expected post(const URL &url, HeadersSetter set_headers,
- std::string body, ResponseHandler on_response,
- ErrorHandler on_error) override;
+ Curl(const Curl&) = delete;
+
+ Expected post(const URL& url, HeadersSetter set_headers,
+ std::string body, ResponseHandler on_response,
+ ErrorHandler on_error) override;
- virtual void drain(std::chrono::steady_clock::time_point deadline) override;
+ void drain(std::chrono::steady_clock::time_point deadline) override;
};
} // namespace tracing
diff --git a/src/datadog/msgpack.h b/src/datadog/msgpack.h
index 212350cf..812a6c57 100644
--- a/src/datadog/msgpack.h
+++ b/src/datadog/msgpack.h
@@ -121,7 +121,10 @@ template
Expected pack_map(std::string& buffer, Key&& key, PackValue&& pack_value,
Rest&&... rest) {
Expected result;
- result = pack_map(buffer, 1 + sizeof...(rest));
+ static_assert(
+ sizeof...(rest) % 2 == 0,
+ "pack_map must receive an even number of arguments after the first.");
+ result = pack_map(buffer, 1 + sizeof...(rest) / 2);
if (!result) {
return result;
}
diff --git a/test/test_tracer_config.cpp b/test/test_tracer_config.cpp
index 1be6f7a7..31ac9c1a 100644
--- a/test/test_tracer_config.cpp
+++ b/test/test_tracer_config.cpp
@@ -964,24 +964,6 @@ TEST_CASE("TracerConfig::span_sampler") {
REQUIRE(finalized.error().code == Error::SPAN_SAMPLING_RULES_FILE_IO);
}
- SECTION("unable to read") {
- SomewhatSecureTemporaryFile file;
- REQUIRE(file.is_open());
- file << "[]";
- file.close();
- // We can't read it anymore. This doesn't actually cover the call to
- // `::read` (i.e. `std::filebuf::[...]`) failing, but getting that to
- // fail after the file has already been opened for reading is too
- // tricky.
- std::filesystem::permissions(file.path(),
- std::filesystem::perms(0200));
- const EnvGuard guard{"DD_SPAN_SAMPLING_RULES_FILE",
- file.path().string()};
- auto finalized = finalize_config(config);
- REQUIRE(!finalized);
- REQUIRE(finalized.error().code == Error::SPAN_SAMPLING_RULES_FILE_IO);
- }
-
SECTION("unable to parse") {
SomewhatSecureTemporaryFile file;
REQUIRE(file.is_open());