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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ default tracing behavior to nginx:
- Create one span per request:
- Service name is "nginx".
- Operation name is "nginx.request".
- Resource name is `"$request_method $datadog_location"`, e.g. "GET /api".
- Resource name is `"$request_method $uri"`, e.g. "GET /api/book/0-345-24223-8/title".
- Includes multiple `http.*` [tags][8].

Custom configuration can be specified via the [datadog](doc/API.md#datadog)
Expand Down
27 changes: 27 additions & 0 deletions doc/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,33 @@ those provided by this module).
The location span is a span created in addition to the request span. See
`datadog_trace_locations`.

### `datadog_resource_name`

- **syntax** `datadog_resource_name <variable_pattern>`
- **default**: `$request_method $uri`, e.g. "GET /api/book/0-345-24223-8/title"
- **context**: `http`, `server`, `location`, `if`

Set the request span's "resource name" (sometimes called "endpoint") to the
result of evaluating the specified `<variable_pattern>` in the context of the
current request. `<variable_pattern>` is a string that may contain
`$`-[variables][2] (including those provided by this module).

The request span is the span created while processing a request.

### `datadog_location_resource_name`

- **syntax** `datadog_location_resource_name <variable_pattern>`
- **default**: `$request_method $uri`, e.g. "GET /api/book/0-345-24223-8/title"
- **context**: `http`, `server`, `location`, `if`

Set the location span's "resource name" (sometimes called "endpoint") to the
result of evaluating the specified `<variable_pattern>` in the context of the
current request. `<variable_pattern>` is a string that may contain
`$`-[variables][2] (including those provided by this module).

The location span is a span created in addition to the request span. See
`datadog_trace_locations`.

### `datadog_trust_incoming_span`

- **syntax** `datadog_trust_incoming_span on|off`
Expand Down
4 changes: 4 additions & 0 deletions example/services/nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ http {
datadog_trace_locations on;
# This tag will be on the location-specific span.
datadog_tag special.tag "The URI is $uri";
# The resource name is customizable for both the request span and
# the location span.
datadog_resource_name "request URI $uri";
datadog_location_resource_name "location URI $uri";
proxy_pass http://http:8080;
}

Expand Down
2 changes: 2 additions & 0 deletions src/datadog_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ struct datadog_loc_conf_t {
ngx_flag_t enable_locations;
NgxScript operation_name_script;
NgxScript loc_operation_name_script;
NgxScript resource_name_script;
NgxScript loc_resource_name_script;
ngx_flag_t trust_incoming_span;
ngx_array_t *tags;
// `response_info_script` is a script that can contain variables that refer
Expand Down
11 changes: 11 additions & 0 deletions src/datadog_directive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,17 @@ char *set_datadog_location_operation_name(ngx_conf_t *cf, ngx_command_t *command
return set_script(cf, command, loc_conf->loc_operation_name_script);
}

char *set_datadog_resource_name(ngx_conf_t *cf, ngx_command_t *command, void *conf) noexcept {
auto loc_conf = static_cast<datadog_loc_conf_t *>(conf);
return set_script(cf, command, loc_conf->resource_name_script);
}

char *set_datadog_location_resource_name(ngx_conf_t *cf, ngx_command_t *command,
void *conf) noexcept {
auto loc_conf = static_cast<datadog_loc_conf_t *>(conf);
return set_script(cf, command, loc_conf->loc_resource_name_script);
}

char *toggle_opentracing(ngx_conf_t *cf, ngx_command_t *command, void *conf) noexcept {
const auto loc_conf = static_cast<datadog_loc_conf_t *>(conf);
const auto values = static_cast<const ngx_str_t *>(cf->args->elts);
Expand Down
5 changes: 5 additions & 0 deletions src/datadog_directive.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ char *set_datadog_operation_name(ngx_conf_t *cf, ngx_command_t *command, void *c
char *set_datadog_location_operation_name(ngx_conf_t *cf, ngx_command_t *command,
void *conf) noexcept;

char *set_datadog_resource_name(ngx_conf_t *cf, ngx_command_t *command, void *conf) noexcept;

char *set_datadog_location_resource_name(ngx_conf_t *cf, ngx_command_t *command,
void *conf) noexcept;

char *toggle_opentracing(ngx_conf_t *cf, ngx_command_t *command, void *conf) noexcept;

char *datadog_enable(ngx_conf_t *cf, ngx_command_t *command, void *conf) noexcept;
Expand Down
82 changes: 42 additions & 40 deletions src/ngx_http_datadog_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,20 @@ static ngx_command_t datadog_commands[] = {
0,
nullptr),

{ ngx_string("datadog_resource_name"),
anywhere | NGX_CONF_TAKE1,
set_datadog_resource_name,
NGX_HTTP_LOC_CONF_OFFSET,
0,
nullptr},

{ ngx_string("datadog_location_resource_name"),
anywhere | NGX_CONF_TAKE1,
set_datadog_location_resource_name,
NGX_HTTP_LOC_CONF_OFFSET,
0,
nullptr},

DEFINE_COMMAND_WITH_OLD_ALIAS(
"datadog_trust_incoming_span",
"opentracing_trust_incoming_span",
Expand Down Expand Up @@ -295,10 +309,13 @@ static ngx_int_t datadog_module_init(ngx_conf_t *cf) noexcept {
if (tags.empty()) return NGX_OK;
main_conf->tags = ngx_array_create(cf->pool, tags.size(), sizeof(datadog_tag_t));
if (!main_conf->tags) return NGX_ERROR;
for (const auto &tag : tags)
for (const auto &tag : tags) {
if (add_datadog_tag(cf, main_conf->tags, to_ngx_str(tag.first), to_ngx_str(tag.second)) !=
NGX_CONF_OK)
NGX_CONF_OK) {
return NGX_ERROR;
}
}

return NGX_OK;
}

Expand Down Expand Up @@ -398,13 +415,13 @@ static void *create_datadog_loc_conf(ngx_conf_t *conf) noexcept {

namespace {

// Merge the specified `previous` operation name script into the specified
// `current` operation name script in the context of the specified `conf`. If
// `current` does not have a value and `previous` does, then `previous` will be
// used. If neither has a value, then a hard-coded default will be used.
// Return `NGX_CONF_OK` on success, or another value otherwise.
char *merge_operation_name_script(ngx_conf_t *conf, NgxScript &previous, NgxScript &current,
ot::string_view default_pattern) {
// Merge the specified `previous` script into the specified `current` script in
// the context of the specified `conf`. If `current` does not have a value and
// `previous` does, then `previous` will be used. If neither has a value, then
// the specified `default_pattern` will be used. Return `NGX_CONF_OK` on
// success, or another value otherwise.
char *merge_script(ngx_conf_t *conf, NgxScript &previous, NgxScript &current,
ot::string_view default_pattern) {
if (current.is_valid()) {
return NGX_CONF_OK;
}
Expand All @@ -420,28 +437,6 @@ char *merge_operation_name_script(ngx_conf_t *conf, NgxScript &previous, NgxScri
return NGX_CONF_OK;
}

char *merge_response_info_script(ngx_conf_t *conf, NgxScript &previous, NgxScript &current) {
// The response info script is the same for each `datadog_loc_conf_t`. The only
// reason it's a member of `datadog_loc_conf_t` is so that it is available at
// the end of each request, when we might like to inspect e.g. response
// headers.
if (current.is_valid()) {
return NGX_CONF_OK;
}

if (!previous.is_valid()) {
// Response header inspection is not currently used by this module, but I'm
// leaving the boilerplate for future use.
const ngx_int_t rc = previous.compile(conf, ngx_string(""));
if (rc != NGX_OK) {
return (char *)NGX_CONF_ERROR;
}
}

current = previous;
return NGX_CONF_OK;
}

} // namespace

//------------------------------------------------------------------------------
Expand All @@ -455,19 +450,26 @@ static char *merge_datadog_loc_conf(ngx_conf_t *cf, void *parent, void *child) n
ngx_conf_merge_value(conf->enable_locations, prev->enable_locations,
TracingLibrary::trace_locations_by_default());

if (const auto rc = merge_script(cf, prev->operation_name_script, conf->operation_name_script,
TracingLibrary::default_request_operation_name_pattern())) {
return rc;
}
if (const auto rc =
merge_operation_name_script(cf, prev->operation_name_script, conf->operation_name_script,
TracingLibrary::default_request_operation_name_pattern())) {
merge_script(cf, prev->loc_operation_name_script, conf->loc_operation_name_script,
TracingLibrary::default_location_operation_name_pattern())) {
return rc;
}
if (const auto rc = merge_operation_name_script(
cf, prev->loc_operation_name_script, conf->loc_operation_name_script,
TracingLibrary::default_location_operation_name_pattern())) {
if (const auto rc = merge_script(cf, prev->resource_name_script, conf->resource_name_script,
TracingLibrary::default_resource_name_pattern())) {
return rc;
}
if (const auto rc =
merge_script(cf, prev->loc_resource_name_script, conf->loc_resource_name_script,
TracingLibrary::default_resource_name_pattern())) {
return rc;
}

if (const auto rc =
merge_response_info_script(cf, prev->response_info_script, conf->response_info_script)) {
merge_script(cf, prev->response_info_script, conf->response_info_script, "")) {
return rc;
}

Expand Down Expand Up @@ -510,8 +512,8 @@ static char *merge_datadog_loc_conf(ngx_conf_t *cf, void *parent, void *child) n

*tag = kv.second;
} else {
datadog_tag_t *tag = (datadog_tag_t *)conf->tags->elts;
tag[index] = kv.second;
datadog_tag_t *tags = (datadog_tag_t *)conf->tags->elts;
tags[index] = kv.second;
}

index++;
Expand Down
20 changes: 20 additions & 0 deletions src/request_tracing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,24 @@ static std::string get_request_operation_name(ngx_http_request_t *request,
return to_string(core_loc_conf->name);
}

static std::string get_loc_resource_name(ngx_http_request_t *request,
const datadog_loc_conf_t *loc_conf) {
if (loc_conf->loc_resource_name_script.is_valid()) {
return to_string(loc_conf->loc_resource_name_script.run(request));
} else {
return "[invalid_resource_name_pattern]";
}
}

static std::string get_request_resource_name(ngx_http_request_t *request,
const datadog_loc_conf_t *loc_conf) {
if (loc_conf->resource_name_script.is_valid()) {
return to_string(loc_conf->resource_name_script.run(request));
} else {
return "[invalid_resource_name_pattern]";
}
}

static void add_script_tags(ngx_array_t *tags, ngx_http_request_t *request, ot::Span &span) {
if (!tags) return;
auto add_tag = [&](const datadog_tag_t &tag) {
Expand Down Expand Up @@ -153,6 +171,7 @@ void RequestTracing::on_exit_block(std::chrono::steady_clock::time_point finish_
//
// See on_log_request below
span_->SetOperationName(get_loc_operation_name(request_, core_loc_conf_, loc_conf_));
span_->SetTag("resource.name", get_loc_resource_name(request_, loc_conf_));

span_->Finish({ot::FinishTimestamp{finish_timestamp}});
} else {
Expand All @@ -178,6 +197,7 @@ void RequestTracing::on_log_request() {
auto core_loc_conf = static_cast<ngx_http_core_loc_conf_t *>(
ngx_http_get_module_loc_conf(request_, ngx_http_core_module));
request_span_->SetOperationName(get_request_operation_name(request_, core_loc_conf, loc_conf_));
request_span_->SetTag("resource.name", get_request_resource_name(request_, loc_conf_));

// Note: At this point, we could run an `NginxScript` to interrogate the
// proxied server's response headers, e.g. to retrieve a deferred sampling
Expand Down
3 changes: 2 additions & 1 deletion src/tracing_library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,11 @@ std::unordered_map<string_view, string_view> TracingLibrary::default_tags() {
// See
// https://docs.datadoghq.com/logs/log_configuration/attributes_naming_convention/#common-attributes
{"http.useragent", "$http_user_agent"},
{"resource.name", "$request_method $datadog_location"},
{"nginx.location", "$datadog_location"}};
}

string_view TracingLibrary::default_resource_name_pattern() { return "$request_method $uri"; }

bool TracingLibrary::tracing_on_by_default() { return true; }

bool TracingLibrary::trace_locations_by_default() { return false; }
Expand Down
7 changes: 7 additions & 0 deletions src/tracing_library.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ struct TracingLibrary {
// (realistically this means that it will refer to a string literal).
static string_view default_location_operation_name_pattern();

// Return the pattern of an nginx variable script that will be used for the
// resource name of spans that do not have a resource name configured in the
// nginx configuration. Note that the storage to which the returned value
// refers must outlive any usage of the return value (realistically this
// means that it will refer to a string literal).
static string_view default_resource_name_pattern();

// Return a mapping of tag name to nginx variable script pattern. These
// tags will be defined automatically during configuration as if they
// appeared in the nginx configuration file's http section, e.g.
Expand Down
11 changes: 11 additions & 0 deletions test/cases/resource_name/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
These tests verify that the "resource name" ("resource") of spans produced by
the module are as configured.

Resource names can be set using the `datadog_resource_name` directive. If the
directive is not used, then resource name takes on a default value. See
`TracingLibrary::default_resource_name_pattern()`.

The resource name of request spans and location spans can be set separately. For
location spans, there is the `datadog_location_resource_name` directive.

These tests closely resemble those in [../operation_name](../operation_name).
16 changes: 16 additions & 0 deletions test/cases/resource_name/conf/default_in_location.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
load_module modules/ngx_http_datadog_module.so;

events {
worker_connections 1024;
}

http {
server {
listen 80;

location /foo {
datadog_trace_locations on;
proxy_pass http://http:8080;
}
}
}
15 changes: 15 additions & 0 deletions test/cases/resource_name/conf/default_in_request.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
load_module modules/ngx_http_datadog_module.so;

events {
worker_connections 1024;
}

http {
server {
listen 80;

location /foo {
proxy_pass http://http:8080;
}
}
}
18 changes: 18 additions & 0 deletions test/cases/resource_name/conf/manual_in_location_at_http.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
load_module modules/ngx_http_datadog_module.so;

events {
worker_connections 1024;
}

http {
datadog_trace_locations on;
datadog_location_resource_name "fuzzy.pumpkin";

server {
listen 80;

location /foo {
proxy_pass http://http:8080;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
load_module modules/ngx_http_datadog_module.so;

events {
worker_connections 1024;
}

http {
datadog_trace_locations on;

server {
listen 80;

location /foo {
datadog_location_resource_name "fuzzy.pumpkin";
proxy_pass http://http:8080;
}
}
}
19 changes: 19 additions & 0 deletions test/cases/resource_name/conf/manual_in_location_at_server.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
load_module modules/ngx_http_datadog_module.so;

events {
worker_connections 1024;
}

http {
datadog_trace_locations on;

server {
listen 80;

datadog_location_resource_name "fuzzy.pumpkin";

location /foo {
proxy_pass http://http:8080;
}
}
}
Loading