Skip to content
Merged
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
1 change: 1 addition & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ cc_library(
"src/datadog/datadog_agent.cpp",
"src/datadog/datadog_agent.h",
"src/datadog/datadog_agent_config.cpp",
"src/datadog/datadog_agent_config_internal.h",
"src/datadog/default_http_client.h",
"src/datadog/default_http_client_null.cpp",
"src/datadog/endpoint_inferral.cpp",
Expand Down
9 changes: 4 additions & 5 deletions benchmark/hasher.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#include <filesystem>

namespace datadog {
namespace tracing {
namespace datadog::tracing {
class Tracer;
} // namespace tracing
} // namespace datadog
} // namespace datadog::tracing

// Use the specified `tracer` to create a trace whose structure resembles the
// file system tree rooted at the specified `path`.
void sha256_traced(const std::filesystem::path &path, datadog::tracing::Tracer &tracer);
void sha256_traced(const std::filesystem::path &path,
datadog::tracing::Tracer &tracer);
26 changes: 18 additions & 8 deletions benchmark/trace_id_bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
namespace {
namespace dd = datadog::tracing;

constexpr int batch_size = 1000;

void BM_TraceID_HexPadded(benchmark::State& state, dd::TraceID id) {
for (auto _ : state) {
auto result = id.hex_padded();
benchmark::DoNotOptimize(result);
for (int i = 0; i < batch_size; ++i) {
auto result = id.hex_padded();
benchmark::DoNotOptimize(result);
}
}
}
BENCHMARK_CAPTURE(BM_TraceID_HexPadded, NoPadding,
Expand All @@ -18,8 +22,10 @@ BENCHMARK_CAPTURE(BM_TraceID_HexPadded, WithPadding, dd::TraceID{1, 0});

void BM_TraceID_ParseHex(benchmark::State& state, std::string input) {
for (auto _ : state) {
auto result = dd::TraceID::parse_hex(input);
benchmark::DoNotOptimize(result);
for (int i = 0; i < batch_size; ++i) {
auto result = dd::TraceID::parse_hex(input);
benchmark::DoNotOptimize(result);
}
}
}
BENCHMARK_CAPTURE(BM_TraceID_ParseHex, 64bit, std::string{"deadbeefcafebabe"});
Expand All @@ -28,8 +34,10 @@ BENCHMARK_CAPTURE(BM_TraceID_ParseHex, 128bit,

void BM_HexPadded_uint64(benchmark::State& state, std::uint64_t value) {
for (auto _ : state) {
auto result = dd::hex_padded(value);
benchmark::DoNotOptimize(result);
for (int i = 0; i < batch_size; ++i) {
auto result = dd::hex_padded(value);
benchmark::DoNotOptimize(result);
}
}
}
BENCHMARK_CAPTURE(BM_HexPadded_uint64, NoPadding, 0xDEADBEEFCAFEBABEULL);
Expand All @@ -38,8 +46,10 @@ BENCHMARK_CAPTURE(BM_HexPadded_uint64, WorstCasePadding, 0x1ULL);
void BM_Hex_uint64(benchmark::State& state) {
const std::uint64_t value = 0xDEADBEEFCAFEBABEULL;
for (auto _ : state) {
auto result = dd::hex(value);
benchmark::DoNotOptimize(result);
for (int i = 0; i < batch_size; ++i) {
auto result = dd::hex(value);
benchmark::DoNotOptimize(result);
}
}
}
BENCHMARK(BM_Hex_uint64);
Expand Down
3 changes: 2 additions & 1 deletion include/datadog/environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ namespace environment {
MACRO(DD_TRACE_AGENT_URL, STRING, \
ENV_DEFAULT_RESOLVED_IN_CODE( \
"If unset, built from DD_AGENT_HOST and DD_TRACE_AGENT_PORT, " \
"then defaults to http://localhost:8126.")) \
"then uses /var/run/datadog/apm.socket when present, otherwise " \
"defaults to http://localhost:8126.")) \
MACRO(DD_TRACE_DEBUG, BOOLEAN, false) \
MACRO(DD_TRACE_ENABLED, BOOLEAN, true) \
MACRO(DD_TRACE_RATE_LIMIT, INT, 100) \
Expand Down
32 changes: 29 additions & 3 deletions src/datadog/datadog_agent_config.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include <datadog/datadog_agent_config.h>
#include <datadog/environment.h>

#include <filesystem>

#include "datadog_agent_config_internal.h"
#include "default_http_client.h"
#include "parse_util.h"
#include "threaded_event_scheduler.h"
Expand All @@ -9,6 +12,30 @@ namespace datadog::tracing {

namespace {

constexpr char default_agent_url[] = "http://localhost:8126";

std::string detect_default_agent_url(
[[maybe_unused]] const std::filesystem::path& socket_path) {
#ifndef _WIN32
std::error_code error;
if (std::filesystem::exists(socket_path, error)) {
return "unix://" + socket_path.string();
}
#endif

return std::string{default_agent_url};
}

} // namespace

std::pair<ConfigMetadata::Origin, std::string> select_agent_url(
const Optional<std::string>& environment_url,
const Optional<std::string>& programmatic_url,
const std::filesystem::path& default_socket_path) {
return pick(environment_url, programmatic_url,
detect_default_agent_url(default_socket_path));
}

Optional<std::string> build_agent_url_from_environment_variables() {
Optional<StringView> url_env = lookup(environment::DD_TRACE_AGENT_URL);
if (url_env && !url_env->empty()) {
Expand Down Expand Up @@ -39,8 +66,6 @@ Optional<std::string> build_agent_url_from_environment_variables() {
return nullopt;
}

} // namespace

Expected<DatadogAgentConfig> load_datadog_agent_env_config() {
DatadogAgentConfig env_config;

Expand Down Expand Up @@ -155,7 +180,8 @@ Expected<FinalizedDatadogAgentConfig> finalize_config(
user_config.remote_configuration_enabled, true);

const auto [origin, url] =
pick(env_config->url, user_config.url, "http://localhost:8126");
select_agent_url(env_config->url, user_config.url,
std::filesystem::path{default_agent_socket_path});
auto parsed_url = HTTPClient::URL::parse(url);
if (auto* error = parsed_url.if_error()) {
return std::move(*error);
Expand Down
28 changes: 28 additions & 0 deletions src/datadog/datadog_agent_config_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <datadog/datadog_agent_config.h>

#include <filesystem>
#include <utility>

namespace datadog::tracing {

// The well-known path where the Datadog Agent listens on a Unix domain socket.
// Single-step instrumentation mounts the socket here.
inline constexpr char default_agent_socket_path[] =
"/var/run/datadog/apm.socket";

// Return the Agent URL configured by the environment, or null if the
// environment does not configure one. `DD_TRACE_AGENT_URL` wins over
// `DD_AGENT_HOST` and `DD_TRACE_AGENT_PORT`. Empty values count as unset.
Optional<std::string> build_agent_url_from_environment_variables();

// Return the origin and value of the Agent URL, given the URL from the
// environment, the URL from programmatic configuration, and the path where the
// Agent might listen on a Unix domain socket.
std::pair<ConfigMetadata::Origin, std::string> select_agent_url(
const Optional<std::string>& environment_url,
const Optional<std::string>& programmatic_url,
const std::filesystem::path& default_socket_path);

} // namespace datadog::tracing
9 changes: 7 additions & 2 deletions test/common/environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ class EnvGuard {
tracing::Optional<std::string> former_value_;

public:
EnvGuard(std::string name, std::string value) : name_(std::move(name)) {
EnvGuard(std::string name, std::string value) : EnvGuard(std::move(name)) {
set_value(value);
}

// Unset the variable until a value is set or this object is destroyed.
Comment thread
Seanbon0611 marked this conversation as resolved.
explicit EnvGuard(std::string name) : name_(std::move(name)) {
const char* current = std::getenv(name_.c_str());
if (current) {
former_value_ = current;
}
set_value(value);
unset();
}

~EnvGuard() {
Expand Down
106 changes: 103 additions & 3 deletions test/test_tracer_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <iostream>

#include "common/environment.h"
#include "datadog_agent_config_internal.h"
#include "mocks/collectors.h"
#include "mocks/event_schedulers.h"
#include "mocks/loggers.h"
Expand Down Expand Up @@ -450,6 +451,75 @@ TRACER_CONFIG_TEST("TracerConfig::agent") {
}

SECTION("url") {
SECTION("the default socket path is the well-known Agent socket") {
REQUIRE(std::string{default_agent_socket_path} ==
"/var/run/datadog/apm.socket");
}

SECTION("all defaults use the detected default URL") {
// Whether the well-known socket exists depends on the machine running
// this test, so compare against what detection decides, not against a
// hard-coded URL. This checks that `finalize_config` probes the
// well-known socket path.
EnvGuard host_guard{"DD_AGENT_HOST"};
EnvGuard port_guard{"DD_TRACE_AGENT_PORT"};
EnvGuard url_guard{"DD_TRACE_AGENT_URL"};

const auto [origin, expected_url] =
select_agent_url(nullopt, nullopt, default_agent_socket_path);
REQUIRE(origin == ConfigMetadata::Origin::DEFAULT);
const auto expected = HTTPClient::URL::parse(expected_url);
REQUIRE(expected);

auto finalized = finalize_config(config);
REQUIRE(finalized);
const auto* const agent =
std::get_if<FinalizedDatadogAgentConfig>(&finalized->collector);
REQUIRE(agent);
REQUIRE(agent->url.scheme == expected->scheme);
REQUIRE(agent->url.authority == expected->authority);
}

SECTION("default socket detection") {
SomewhatSecureTemporaryFile socket;
REQUIRE(socket.is_open());

SECTION("uses an existing socket") {
const auto [origin, url] =
select_agent_url(nullopt, nullopt, socket.path());
REQUIRE(origin == ConfigMetadata::Origin::DEFAULT);
#ifdef _WIN32
REQUIRE(url == "http://localhost:8126");
#else
REQUIRE(url == "unix://" + socket.path().string());
#endif
}

SECTION("falls back when the socket does not exist") {
const std::filesystem::path missing_socket =
socket.path().string() + ".missing";
const auto [origin, url] =
select_agent_url(nullopt, nullopt, missing_socket);
REQUIRE(origin == ConfigMetadata::Origin::DEFAULT);
REQUIRE(url == "http://localhost:8126");
}

SECTION("programmatic URL takes precedence") {
const auto [origin, url] = select_agent_url(
nullopt, "http://configured-agent:8126", socket.path());
REQUIRE(origin == ConfigMetadata::Origin::CODE);
REQUIRE(url == "http://configured-agent:8126");
}

SECTION("environment configuration takes precedence") {
const auto [origin, url] =
select_agent_url("http://environment-agent:8126",
"http://configured-agent:8126", socket.path());
REQUIRE(origin == ConfigMetadata::Origin::ENVIRONMENT_VARIABLE);
REQUIRE(url == "http://environment-agent:8126");
}
}

SECTION("parsing") {
struct TestCase {
std::string url;
Expand Down Expand Up @@ -493,6 +563,39 @@ TRACER_CONFIG_TEST("TracerConfig::agent") {
}
}

SECTION("no environment configuration") {
struct TestCase {
std::string name;
Optional<std::string> env_host;
Optional<std::string> env_port;
Optional<std::string> env_url;
};

auto test_case = GENERATE(values<TestCase>({
{"all unset", nullopt, nullopt, nullopt},
{"empty host", "", nullopt, nullopt},
{"empty port", nullopt, "", nullopt},
{"empty URL", nullopt, nullopt, ""},
{"all empty", "", "", ""},
}));

CAPTURE(test_case.name);
EnvGuard host_guard{"DD_AGENT_HOST"};
EnvGuard port_guard{"DD_TRACE_AGENT_PORT"};
EnvGuard url_guard{"DD_TRACE_AGENT_URL"};
if (test_case.env_host) {
host_guard.set_value(*test_case.env_host);
}
if (test_case.env_port) {
port_guard.set_value(*test_case.env_port);
}
if (test_case.env_url) {
url_guard.set_value(*test_case.env_url);
}

REQUIRE(build_agent_url_from_environment_variables() == nullopt);
}

SECTION("environment variables override") {
struct TestCase {
std::string name;
Expand All @@ -504,15 +607,12 @@ TRACER_CONFIG_TEST("TracerConfig::agent") {
};

auto test_case = GENERATE(values<TestCase>({
{"all defaults", nullopt, nullopt, nullopt, "http", "localhost:8126"},
{"override host", "dd-agent", nullopt, nullopt, "http",
"dd-agent:8126"},
{"override port", nullopt, "8080", nullopt, "http", "localhost:8080"},
{"override host and port", "dd-agent", "8080", nullopt, "http",
"dd-agent:8080"},
{"empty URL", "dd-agent", "8080", "", "http", "dd-agent:8080"},
{"empty host", "", nullopt, nullopt, "http", "localhost:8126"},
{"empty port", nullopt, "", nullopt, "http", "localhost:8126"},
{"IPv6 host", "::1", nullopt, nullopt, "http", "[::1]:8126"},
{"IPv6 host with brackets", "[::1]", nullopt, nullopt, "http",
"[::1]:8126"},
Expand Down
Loading