Skip to content

Commit

Permalink
Merge pull request #82 from DataDog/willgittoes-dd/b3-headers-flags
Browse files Browse the repository at this point in the history
Add environment variables for B3 header propagation
  • Loading branch information
willgittoes-dd authored Jan 22, 2019
2 parents c91c495 + 29f43ea commit ea185e7
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 67 deletions.
30 changes: 16 additions & 14 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,30 @@ cc_library(
name = "dd_opentracing_cpp",
srcs = [
"src/clock.h",
"src/encoder.cpp",
"src/encoder.h",
"src/noopspan.cpp",
"src/noopspan.h",
"src/opentracing_external.cpp",
"src/propagation.cpp",
"src/propagation.h",
"src/encoder.cpp",
"src/encoder.h",
"src/sample.cpp",
"src/sample.h",
"src/span_buffer.cpp",
"src/span_buffer.h",
"src/span.cpp",
"src/span.h",
"src/span_buffer.cpp",
"src/span_buffer.h",
"src/tracer.cpp",
"src/tracer.h",
"src/tracer_options.cpp",
"src/tracer_options.h",
"src/writer.cpp",
"src/writer.h",
":version_number.h",
],
hdrs = [
"include/datadog/opentracing.h",
],
strip_include_prefix = "include",
visibility = ["//visibility:public"],
deps = [
"//:3rd_party_nlohmann",
"@io_opentracing_cpp//:opentracing",
"@com_github_msgpack_msgpack_c//:msgpack",
],
copts = [
"-Wall",
"-Wextra",
Expand All @@ -40,16 +35,23 @@ cc_library(
"-Wold-style-cast",
"-std=c++14",
],
strip_include_prefix = "include",
visibility = ["//visibility:public"],
deps = [
"//:3rd_party_nlohmann",
"@com_github_msgpack_msgpack_c//:msgpack",
"@io_opentracing_cpp//:opentracing",
],
)

genrule(
name = "generate_version_number_h",
srcs = glob([
"CMakeLists.txt",
"src/*",
"CMakeLists.txt",
"src/*",
]),
outs = [
"version_number.h"
"version_number.h",
],
cmd = """
TEMP_DIR=$$(mktemp -d)
Expand Down
14 changes: 9 additions & 5 deletions include/datadog/opentracing.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ enum class PropagationStyle {
};

struct TracerOptions {
// Hostname or IP address of the Datadog agent.
// Hostname or IP address of the Datadog agent. Can also be set by the environment variable
// DD_AGENT_HOST.
std::string agent_host = "localhost";
// Port on which the Datadog agent is running.
// Port on which the Datadog agent is running. Can also be set by the environment variable
// DD_TRACE_AGENT_PORT
uint32_t agent_port = 8126;
// The name of the service being traced.
// See:
Expand All @@ -49,9 +51,11 @@ struct TracerOptions {
// If not empty, the given string overrides the operation name (and the overridden operation name
// is recorded in the tag "operation").
std::string operation_name_override = "";
// The style of propagation headers to accept/extract.
std::set<PropagationStyle> extract{PropagationStyle::Datadog, PropagationStyle::B3};
// The style of propagation headers to emit/inject.
// The style of propagation headers to accept/extract. Can also be set by the environment
// variable DD_PROPAGATION_STYLE_EXTRACT.
std::set<PropagationStyle> extract{PropagationStyle::Datadog};
// The style of propagation headers to emit/inject. Can also be set by the environment variable
// DD_PROPAGATION_STYLE_INJECT.
std::set<PropagationStyle> inject{PropagationStyle::Datadog};
};

Expand Down
18 changes: 14 additions & 4 deletions src/opentracing_agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,28 @@
#include "agent_writer.h"
#include "sample.h"
#include "tracer.h"
#include "tracer_options.h"

namespace ot = opentracing;

namespace datadog {
namespace opentracing {

std::shared_ptr<ot::Tracer> makeTracer(const TracerOptions &options) {
std::shared_ptr<SampleProvider> sampler = sampleProviderFromOptions(options);
auto maybe_options = applyTracerOptionsFromEnvironment(options);
if (!maybe_options) {
std::cerr << "Error applying TracerOptions from environment variables: "
<< maybe_options.error() << std::endl
<< "Tracer will be started without options from the environment" << std::endl;
maybe_options = options;
}
TracerOptions opts = maybe_options.value();

std::shared_ptr<SampleProvider> sampler = sampleProviderFromOptions(opts);
auto writer = std::shared_ptr<Writer>{
new AgentWriter(options.agent_host, options.agent_port,
std::chrono::milliseconds(llabs(options.write_period_ms)), sampler)};
return std::shared_ptr<ot::Tracer>{new Tracer{options, writer, sampler}};
new AgentWriter(opts.agent_host, opts.agent_port,
std::chrono::milliseconds(llabs(opts.write_period_ms)), sampler)};
return std::shared_ptr<ot::Tracer>{new Tracer{opts, writer, sampler}};
}

} // namespace opentracing
Expand Down
14 changes: 12 additions & 2 deletions src/opentracing_external.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <datadog/opentracing.h>
#include "sample.h"
#include "tracer.h"
#include "tracer_options.h"
#include "writer.h"

namespace ot = opentracing;
Expand All @@ -17,12 +18,21 @@ namespace opentracing {

std::tuple<std::shared_ptr<ot::Tracer>, std::shared_ptr<TraceEncoder>> makeTracerAndEncoder(
const TracerOptions &options) {
std::shared_ptr<SampleProvider> sampler = sampleProviderFromOptions(options);
auto maybe_options = applyTracerOptionsFromEnvironment(options);
if (!maybe_options) {
std::cerr << "Error applying TracerOptions from environment variables: "
<< maybe_options.error() << std::endl
<< "Tracer will be started without options from the environment" << std::endl;
maybe_options = options;
}
TracerOptions opts = maybe_options.value();

std::shared_ptr<SampleProvider> sampler = sampleProviderFromOptions(opts);
auto xwriter = std::make_shared<ExternalWriter>(sampler);
auto encoder = xwriter->encoder();
std::shared_ptr<Writer> writer = xwriter;
return std::tuple<std::shared_ptr<ot::Tracer>, std::shared_ptr<TraceEncoder>>{
std::shared_ptr<ot::Tracer>{new Tracer{options, writer, sampler}}, encoder};
std::shared_ptr<ot::Tracer>{new Tracer{opts, writer, sampler}}, encoder};
}

} // namespace opentracing
Expand Down
54 changes: 14 additions & 40 deletions src/tracer_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,13 @@
#include <nlohmann/json.hpp>
#include "agent_writer.h"
#include "tracer.h"
#include "tracer_options.h"

using json = nlohmann::json;

namespace datadog {
namespace opentracing {

namespace {
ot::expected<std::set<PropagationStyle>> asPropagationStyle(json styles) {
std::set<PropagationStyle> propagation_styles;
for (auto &style : styles) {
if (style == "Datadog") {
propagation_styles.insert(PropagationStyle::Datadog);
} else if (style == "B3") {
propagation_styles.insert(PropagationStyle::B3);
} else {
return ot::make_unexpected(std::make_error_code(std::errc::invalid_argument));
}
}
if (propagation_styles.size() == 0) {
return ot::make_unexpected(std::make_error_code(std::errc::invalid_argument));
}
return propagation_styles;
}
} // namespace

ot::expected<TracerOptions> optionsFromConfig(const char *configuration,
std::string &error_message) {
TracerOptions options{"localhost", 8126, "", "web", "", 1.0};
Expand Down Expand Up @@ -93,30 +75,20 @@ ot::expected<TracerOptions> optionsFromConfig(const char *configuration,
return ot::make_unexpected(std::make_error_code(std::errc::invalid_argument));
}

// Agent host and port environment variables override defaults and config.
auto agent_host = std::getenv("DD_AGENT_HOST");
if (agent_host != nullptr && std::strlen(agent_host) > 0) {
options.agent_host = agent_host;
}
auto trace_agent_port = std::getenv("DD_TRACE_AGENT_PORT");
if (trace_agent_port != nullptr && std::strlen(trace_agent_port) > 0) {
try {
options.agent_port = std::stoi(trace_agent_port);
} catch (const std::invalid_argument &ia) {
error_message = "Value for DD_TRACE_AGENT_PORT is invalid";
return ot::make_unexpected(std::make_error_code(std::errc::invalid_argument));
} catch (const std::out_of_range &oor) {
error_message = "Value for DD_TRACE_AGENT_PORT is out of range";
return ot::make_unexpected(std::make_error_code(std::errc::invalid_argument));
}
auto maybe_options = applyTracerOptionsFromEnvironment(options);
if (!maybe_options) {
error_message = maybe_options.error();
return ot::make_unexpected(std::make_error_code(std::errc::invalid_argument));
}
return options;
return maybe_options.value();
}

// Accepts configuration in JSON format, with the following keys:
// "service": Required. A string, the name of the service.
// "agent_host": A string, defaults to localhost.
// "agent_port": A number, defaults to 8126.
// "agent_host": A string, defaults to localhost. Can also be set by the environment variable
// DD_AGENT_HOST
// "agent_port": A number, defaults to 8126. "type": A string, defaults to web. Can also be set by
// the environment variable DD_TRACE_AGENT_PORT
// "type": A string, defaults to web.
// "environment": A string, defaults to "". The environment this trace belongs to.
// eg. "" (env:none), "staging", "prod"
Expand All @@ -127,9 +99,11 @@ ot::expected<TracerOptions> optionsFromConfig(const char *configuration,
// "operation_name_override": A string, if not empty it overrides the operation name (and the
// overridden operation name is recorded in the tag "operation").
// "propagation_style_extract": A list of strings, each string is one of "Datadog", "B3". Defaults
// to ["Datadog", "B3"]. The type of headers to use to propagate distributed traces.
// to ["Datadog"]. The type of headers to use to propagate distributed traces. Can also be set
// by the environment variable DD_PROPAGATION_STYLE_EXTRACT.
// "propagation_style_inject": A list of strings, each string is one of "Datadog", "B3". Defaults
// to ["Datadog"]. The type of headers to use to receive distributed traces.
// to ["Datadog"]. The type of headers to use to receive distributed traces. Can also be set by
// the environment variable DD_PROPAGATION_STYLE_INJECT.
//
// Extra keys will be ignored.
template <class TracerImpl>
Expand Down
57 changes: 57 additions & 0 deletions src/tracer_options.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include "tracer_options.h"

#include <iterator>
#include <sstream>

namespace ot = opentracing;

namespace datadog {
namespace opentracing {

ot::expected<TracerOptions, const char *> applyTracerOptionsFromEnvironment(
const TracerOptions &input) {
TracerOptions opts = input;

auto agent_host = std::getenv("DD_AGENT_HOST");
if (agent_host != nullptr && std::strlen(agent_host) > 0) {
opts.agent_host = agent_host;
}

auto trace_agent_port = std::getenv("DD_TRACE_AGENT_PORT");
if (trace_agent_port != nullptr && std::strlen(trace_agent_port) > 0) {
try {
opts.agent_port = std::stoi(trace_agent_port);
} catch (const std::invalid_argument &ia) {
return ot::make_unexpected("Value for DD_TRACE_AGENT_PORT is invalid");
} catch (const std::out_of_range &oor) {
return ot::make_unexpected("Value for DD_TRACE_AGENT_PORT is out of range");
}
}

auto extract = std::getenv("DD_PROPAGATION_STYLE_EXTRACT");
if (extract != nullptr && std::strlen(extract) > 0) {
std::stringstream words{extract};
auto style_maybe = asPropagationStyle(std::vector<std::string>{
std::istream_iterator<std::string>{words}, std::istream_iterator<std::string>{}});
if (!style_maybe) {
return ot::make_unexpected("Value for DD_PROPAGATION_STYLE_EXTRACT is invalid");
}
opts.extract = style_maybe.value();
}

auto inject = std::getenv("DD_PROPAGATION_STYLE_INJECT");
if (inject != nullptr && std::strlen(inject) > 0) {
std::stringstream words{inject};
auto style_maybe = asPropagationStyle(std::vector<std::string>{
std::istream_iterator<std::string>{words}, std::istream_iterator<std::string>{}});
if (!style_maybe) {
return ot::make_unexpected("Value for DD_PROPAGATION_STYLE_INJECT is invalid");
}
opts.inject = style_maybe.value();
}

return opts;
}

} // namespace opentracing
} // namespace datadog
36 changes: 36 additions & 0 deletions src/tracer_options.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef DD_TRACER_OPTIONS_H
#define DD_TRACER_OPTIONS_H

#include <datadog/opentracing.h>
#include <opentracing/expected/expected.hpp>

namespace ot = opentracing;

namespace datadog {
namespace opentracing {

template <class Iterable>
ot::expected<std::set<PropagationStyle>> asPropagationStyle(Iterable styles) {
std::set<PropagationStyle> propagation_styles;
for (const std::string& style : styles) {
if (style == "Datadog") {
propagation_styles.insert(PropagationStyle::Datadog);
} else if (style == "B3") {
propagation_styles.insert(PropagationStyle::B3);
} else {
return ot::make_unexpected(std::make_error_code(std::errc::invalid_argument));
}
}
if (propagation_styles.size() == 0) {
return ot::make_unexpected(std::make_error_code(std::errc::invalid_argument));
}
return propagation_styles;
};

ot::expected<TracerOptions, const char*> applyTracerOptionsFromEnvironment(
const TracerOptions& input);

} // namespace opentracing
} // namespace datadog

#endif // DD_TRACER_OPTIONS_H
5 changes: 3 additions & 2 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ macro(_datadog_test TEST_NAME)
add_test(${TEST_NAME} ${TEST_NAME})
endmacro()

_datadog_test(agent_writer_test agent_writer_test.cpp)
_datadog_test(opentracing_test opentracing_test.cpp)
_datadog_test(propagation_test propagation_test.cpp)
_datadog_test(sample_test sample_test.cpp)
_datadog_test(span_buffer_test span_buffer_test.cpp)
_datadog_test(span_test span_test.cpp)
_datadog_test(tracer_factory_test tracer_factory_test.cpp)
_datadog_test(tracer_options_test tracer_options_test.cpp)
_datadog_test(tracer_test tracer_test.cpp)
_datadog_test(sample_test sample_test.cpp)
_datadog_test(agent_writer_test agent_writer_test.cpp)
Loading

0 comments on commit ea185e7

Please sign in to comment.