Skip to content

Commit f2e7b9b

Browse files
authored
feat: otel drop in support (#182)
This PR introduces the ability to replace the OpenTelemetry (oTel) module`otel_ngx_module` with `nginx-datadog` without requiring any changes to the existing oTel directives.
1 parent 7eaa1eb commit f2e7b9b

10 files changed

+393
-338
lines changed

src/datadog_directive.cpp

+59-7
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,74 @@
22

33
#include <cassert>
44

5+
#include "datadog_conf_handler.h"
6+
57
namespace datadog {
68
namespace nginx {
79

8-
char *warn_deprecated_command_datadog_tracing(ngx_conf_t *cf,
9-
ngx_command_t * /*command*/,
10-
void * /*conf*/) noexcept {
10+
char *silently_ignore_command(ngx_conf_t *cf, ngx_command_t *command, void *) {
11+
ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "Directive \"%V\" ignored",
12+
&command->name);
13+
return NGX_OK;
14+
}
15+
16+
char *alias_directive(ngx_conf_t *cf, ngx_command_t *command, void *) noexcept {
17+
if (command->post == nullptr) {
18+
return static_cast<char *>(NGX_CONF_ERROR);
19+
}
20+
21+
auto src_directive = static_cast<char *>(command->post);
22+
1123
const auto elements = static_cast<ngx_str_t *>(cf->args->elts);
1224
assert(cf->args->nelts >= 1);
1325

14-
ngx_log_error(
15-
NGX_LOG_WARN, cf->log, 0,
16-
"Directive \"%V\" is deprecated. Use datadog_tracing on/off instead",
17-
&elements[0]);
26+
const ngx_str_t new_name_ngx{.len = strlen(src_directive),
27+
.data = (u_char *)src_directive};
28+
ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "Alias \"%V\" to \"%V\"",
29+
&command->name, &new_name_ngx);
1830

31+
// Rename the command and let `datadog_conf_handler` dispatch to the
32+
// appropriate handler.
33+
elements[0] = new_name_ngx;
34+
auto rcode = datadog_conf_handler({.conf = cf, .skip_this_module = false});
35+
if (rcode != NGX_OK) {
36+
return static_cast<char *>(NGX_CONF_ERROR);
37+
}
38+
39+
return static_cast<char *>(NGX_CONF_OK);
40+
}
41+
42+
char *warn_deprecated_command(ngx_conf_t *cf, ngx_command_t *command,
43+
void *) noexcept {
44+
u_char buf[NGX_MAX_ERROR_STR] = {0};
45+
u_char *last = buf + NGX_MAX_ERROR_STR;
46+
u_char *p =
47+
ngx_slprintf(buf, last, "Directive \"%V\" is deprecated", &command->name);
48+
49+
if (command->post != nullptr) {
50+
auto reason = static_cast<char *>(command->post);
51+
ngx_slprintf(p, last, ". %s", reason);
52+
}
53+
54+
ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "%s", buf);
1955
return NGX_OK;
2056
}
2157

58+
char *err_deprecated_command(ngx_conf_t *cf, ngx_command_t *command,
59+
void *) noexcept {
60+
u_char buf[NGX_MAX_ERROR_STR] = {0};
61+
u_char *last = buf + NGX_MAX_ERROR_STR;
62+
u_char *p =
63+
ngx_slprintf(buf, last, "Directive \"%V\" is deprecated", &command->name);
64+
65+
if (command->post != nullptr) {
66+
auto reason = static_cast<char *>(command->post);
67+
ngx_slprintf(p, last, ". %s", reason);
68+
}
69+
70+
ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "%s", buf);
71+
return static_cast<char *>(NGX_CONF_ERROR);
72+
}
73+
2274
} // namespace nginx
2375
} // namespace datadog

src/datadog_directive.h

+31-3
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,39 @@ constexpr auto generate_directives(const T &...directives) {
7272
return merge_directives(directives...);
7373
}
7474

75+
#define IGNORE_COMMAND(NAME, TYPE) \
76+
{ NAME, TYPE, silently_ignore_command, NGX_HTTP_LOC_CONF_OFFSET, 0, nullptr }
77+
78+
#define ALIAS_COMMAND(SRC_DIRECTIVE, TARGET_DIRECTIVE, TYPE) \
79+
{ \
80+
TARGET_DIRECTIVE, TYPE, alias_directive, NGX_HTTP_LOC_CONF_OFFSET, 0, \
81+
(void *)SRC_DIRECTIVE \
82+
}
83+
84+
#define WARN_DEPRECATED_COMMAND(NAME, TYPE, MSG) \
85+
{ \
86+
NAME, TYPE, warn_deprecated_command, NGX_HTTP_LOC_CONF_OFFSET, 0, \
87+
(void *)MSG \
88+
}
89+
90+
#define ERROR_DEPRECATED_COMMAND(NAME, TYPE, MSG) \
91+
{ \
92+
NAME, TYPE, err_deprecated_command, NGX_HTTP_LOC_CONF_OFFSET, 0, \
93+
(void *)MSG \
94+
}
95+
96+
char *silently_ignore_command(ngx_conf_t *, ngx_command_t *, void *);
97+
98+
char *alias_directive(ngx_conf_t *cf, ngx_command_t *command,
99+
void *conf) noexcept;
100+
75101
char *set_datadog_agent_url(ngx_conf_t *, ngx_command_t *, void *conf) noexcept;
76102

77-
char *warn_deprecated_command_datadog_tracing(ngx_conf_t *cf,
78-
ngx_command_t * /*command*/,
79-
void * /*conf*/) noexcept;
103+
char *warn_deprecated_command(ngx_conf_t *cf, ngx_command_t *command,
104+
void *conf) noexcept;
105+
106+
char *err_deprecated_command(ngx_conf_t *cf, ngx_command_t *command,
107+
void *) noexcept;
80108

81109
} // namespace nginx
82110
} // namespace datadog

src/datadog_variable.cpp

+47-29
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ namespace {
1919

2020
// Return whether the specified `request` is a subrequest for which tracing
2121
// ("logging") is disabled.
22-
bool is_untraced_subrequest(ngx_http_request_t* request) {
23-
auto core_loc_conf = static_cast<ngx_http_core_loc_conf_t*>(
22+
bool is_untraced_subrequest(ngx_http_request_t *request) {
23+
auto core_loc_conf = static_cast<ngx_http_core_loc_conf_t *>(
2424
ngx_http_get_module_loc_conf(request, ngx_http_core_module));
2525

2626
return request->parent != nullptr && !core_loc_conf->log_subrequest;
@@ -33,13 +33,9 @@ bool is_untraced_subrequest(ngx_http_request_t* request) {
3333
// if valid, will resolve to some property on the active span, i.e.
3434
// `datadog_trace_id` resolves to a string containing the trace ID. Return
3535
// `NGX_OK` on success or another value if an error occurs.
36-
static ngx_int_t expand_span_variable(ngx_http_request_t* request,
37-
ngx_http_variable_value_t* variable_value,
36+
static ngx_int_t expand_span_variable(ngx_http_request_t *request,
37+
ngx_http_variable_value_t *variable_value,
3838
uintptr_t data) noexcept try {
39-
auto variable_name = to_string_view(*reinterpret_cast<ngx_str_t*>(data));
40-
auto prefix_length = TracingLibrary::span_variables().prefix.size();
41-
auto suffix = slice(variable_name, prefix_length);
42-
4339
auto context = get_datadog_context(request);
4440
// Context can be null if tracing is disabled.
4541
if (context == nullptr || is_untraced_subrequest(request)) {
@@ -52,16 +48,29 @@ static ngx_int_t expand_span_variable(ngx_http_request_t* request,
5248
return NGX_OK;
5349
}
5450

55-
auto span_variable_value =
56-
context->lookup_span_variable_value(request, suffix);
57-
variable_value->len = span_variable_value.len;
58-
variable_value->valid = true;
59-
variable_value->no_cacheable = true;
60-
variable_value->not_found = false;
61-
variable_value->data = span_variable_value.data;
51+
auto set_variable = [&](std::string_view suffix) {
52+
auto span_variable_value =
53+
context->lookup_span_variable_value(request, suffix);
54+
variable_value->len = span_variable_value.len;
55+
variable_value->valid = true;
56+
variable_value->no_cacheable = true;
57+
variable_value->not_found = false;
58+
variable_value->data = span_variable_value.data;
59+
};
60+
61+
auto variable_name = to_string_view(*reinterpret_cast<ngx_str_t *>(data));
62+
if (variable_name.starts_with("datadog_")) {
63+
auto suffix =
64+
slice(variable_name, TracingLibrary::span_variables().prefix.size());
65+
set_variable(suffix);
66+
} else if (std::string_view otel("opentelemetry_");
67+
variable_name.starts_with(otel)) {
68+
auto suffix = slice(variable_name, otel.size());
69+
set_variable(suffix);
70+
}
6271

6372
return NGX_OK;
64-
} catch (const std::exception& e) {
73+
} catch (const std::exception &e) {
6574
ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
6675
"failed to expand %V"
6776
" for request %p: %s",
@@ -79,9 +88,9 @@ static ngx_int_t expand_span_variable(ngx_http_request_t* request,
7988
// `TracingLibrary::environment_variable_names`. Return `NGX_OK` on success or
8089
// another value if an error occurs.
8190
static ngx_int_t expand_environment_variable(
82-
ngx_http_request_t* request, ngx_http_variable_value_t* variable_value,
91+
ngx_http_request_t *request, ngx_http_variable_value_t *variable_value,
8392
uintptr_t data) noexcept {
84-
auto variable_name = to_string_view(*reinterpret_cast<ngx_str_t*>(data));
93+
auto variable_name = to_string_view(*reinterpret_cast<ngx_str_t *>(data));
8594
auto prefix_length =
8695
TracingLibrary::environment_variable_name_prefix().size();
8796
auto suffix = slice(variable_name, prefix_length);
@@ -91,7 +100,7 @@ static ngx_int_t expand_environment_variable(
91100
to_upper);
92101

93102
const auto allow_list = TracingLibrary::environment_variable_names();
94-
const char* env_value = nullptr;
103+
const char *env_value = nullptr;
95104
if (std::find(allow_list.begin(), allow_list.end(), env_var_name) !=
96105
allow_list.end()) {
97106
env_value = std::getenv(env_var_name.c_str());
@@ -123,13 +132,13 @@ static ngx_int_t expand_environment_variable(
123132
// evaluates to a JSON representation of the tracer configuration. Return
124133
// `NGX_OK` on success or another value if an error occurs.
125134
static ngx_int_t expand_configuration_variable(
126-
ngx_http_request_t* request, ngx_http_variable_value_t* variable_value,
135+
ngx_http_request_t *request, ngx_http_variable_value_t *variable_value,
127136
uintptr_t /*data*/) noexcept {
128137
variable_value->valid = true;
129138
variable_value->no_cacheable = true;
130139
variable_value->not_found = false;
131140

132-
const dd::Tracer* tracer = global_tracer();
141+
const dd::Tracer *tracer = global_tracer();
133142
if (tracer == nullptr) {
134143
// No tracer, no config. Evaluate to "-" (hyphen).
135144
const ngx_str_t not_found_str = ngx_string("-");
@@ -150,21 +159,21 @@ static ngx_int_t expand_configuration_variable(
150159
variable_value->data = json_str.data;
151160
}
152161

153-
auto& alloc = doc.GetAllocator();
162+
auto &alloc = doc.GetAllocator();
154163

155164
// override
156-
const auto& loc_conf = *static_cast<datadog::nginx::datadog_loc_conf_t*>(
165+
const auto &loc_conf = *static_cast<datadog::nginx::datadog_loc_conf_t *>(
157166
ngx_http_get_module_loc_conf(request, ngx_http_datadog_module));
158167

159168
auto append_to_doc = [&](std::string_view key,
160-
ngx_http_complex_value_t* value) {
169+
ngx_http_complex_value_t *value) {
161170
if (value == nullptr) return;
162171

163172
ngx_str_t res;
164173
if (ngx_http_complex_value(request, value, &res) == NGX_OK &&
165174
res.len != 0) {
166175
doc.AddMember(rapidjson::Value(key.data(), key.size(), alloc),
167-
rapidjson::Value((char*)res.data, res.len, alloc), alloc);
176+
rapidjson::Value((char *)res.data, res.len, alloc), alloc);
168177
}
169178
};
170179

@@ -215,9 +224,9 @@ static ngx_int_t expand_configuration_variable(
215224
//
216225
// Return `NGX_OK` on success or another value if an error occurs.
217226
static ngx_int_t expand_location_variable(
218-
ngx_http_request_t* request, ngx_http_variable_value_t* variable_value,
227+
ngx_http_request_t *request, ngx_http_variable_value_t *variable_value,
219228
uintptr_t /*data*/) noexcept {
220-
const auto core_loc_conf = static_cast<ngx_http_core_loc_conf_t*>(
229+
const auto core_loc_conf = static_cast<ngx_http_core_loc_conf_t *>(
221230
ngx_http_get_module_loc_conf(request, ngx_http_core_module));
222231

223232
if (core_loc_conf == nullptr) {
@@ -240,9 +249,9 @@ static ngx_int_t expand_location_variable(
240249
return NGX_OK;
241250
}
242251

243-
ngx_int_t add_variables(ngx_conf_t* cf) noexcept {
252+
ngx_int_t add_variables(ngx_conf_t *cf) noexcept {
244253
ngx_str_t prefix;
245-
ngx_http_variable_t* variable;
254+
ngx_http_variable_t *variable;
246255

247256
// Register the variable name prefix for span variables.
248257
prefix = to_ngx_str(TracingLibrary::span_variables().prefix);
@@ -261,6 +270,15 @@ ngx_int_t add_variables(ngx_conf_t* cf) noexcept {
261270
variable->get_handler = expand_environment_variable;
262271
variable->data = 0;
263272

273+
// Register the variable name prefix for OpenTelemetry-relevant environment
274+
// variables.
275+
prefix = ngx_string("opentelemetry_");
276+
variable = ngx_http_add_variable(
277+
cf, &prefix,
278+
NGX_HTTP_VAR_NOCACHEABLE | NGX_HTTP_VAR_NOHASH | NGX_HTTP_VAR_PREFIX);
279+
variable->get_handler = expand_span_variable;
280+
variable->data = 0;
281+
264282
// Register the variable name for getting the tracer configuration.
265283
ngx_str_t name =
266284
to_ngx_str(TracingLibrary::configuration_json_variable_name());

src/ngx_http_datadog_module.cpp

+11-10
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,13 @@ static char *merge_datadog_loc_conf(ngx_conf_t *, void *parent, void *child) noe
5252

5353
using namespace datadog::nginx;
5454

55-
#define DEFINE_DEPRECATED_COMMAND_DATADOG_TRACING(NAME, TYPE) \
56-
{ \
57-
NAME, TYPE, warn_deprecated_command_datadog_tracing, \
58-
NGX_HTTP_LOC_CONF_OFFSET, 0, NULL \
59-
}
60-
6155
constexpr datadog::nginx::directive module_directives[] = {
62-
DEFINE_DEPRECATED_COMMAND_DATADOG_TRACING("datadog_enable",
63-
anywhere | NGX_CONF_NOARGS),
56+
WARN_DEPRECATED_COMMAND("datadog_enable", anywhere | NGX_CONF_NOARGS,
57+
"Use datadog_tracing instead"),
58+
59+
WARN_DEPRECATED_COMMAND("datadog_disable", anywhere | NGX_CONF_NOARGS,
60+
"Use datadog_tracing instead"),
6461

65-
DEFINE_DEPRECATED_COMMAND_DATADOG_TRACING("datadog_disable",
66-
anywhere | NGX_CONF_NOARGS),
6762
{"datadog_service_name",
6863
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
6964
NGX_CONF_TAKE1,
@@ -84,6 +79,12 @@ constexpr datadog::nginx::directive module_directives[] = {
8479

8580
{"datadog_agent_url", NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
8681
set_datadog_agent_url, NGX_HTTP_MAIN_CONF_OFFSET, 0, nullptr},
82+
83+
// aliases
84+
ALIAS_COMMAND("datadog_service_name", "opentelemetry_service_name",
85+
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1),
86+
ALIAS_COMMAND("datadog_agent_url", "opentelemetry_otlp_traces_endpoint",
87+
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1),
8788
};
8889

8990
static auto datadog_commands =

0 commit comments

Comments
 (0)