Skip to content

Commit e9bb286

Browse files
RUM telemetry
1 parent a2e2d29 commit e9bb286

10 files changed

+168
-11
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ if(NGINX_DATADOG_RUM_ENABLED)
184184
PRIVATE
185185
src/rum/config.cpp
186186
src/rum/injection.cpp
187+
src/rum/telemetry.cpp
187188
)
188189
target_compile_definitions(ngx_http_datadog_objs PUBLIC WITH_RUM)
189190
endif()

src/datadog_conf.h

+2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ struct datadog_loc_conf_t {
213213
#ifdef WITH_RUM
214214
ngx_flag_t rum_enable = NGX_CONF_UNSET;
215215
Snippet *rum_snippet = nullptr;
216+
std::string rum_application_id_tag;
217+
std::string rum_remote_config_tag;
216218
#endif
217219
};
218220

src/datadog_context.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ void DatadogContext::on_log_request(ngx_http_request_t *request) {
191191
throw std::runtime_error{"on_log_request failed: could not get loc conf"};
192192
}
193193

194+
#ifdef WITH_RUM
195+
if (loc_conf->rum_enable) {
196+
rum_ctx_.on_log_request(request);
197+
}
198+
#endif
199+
194200
if (!loc_conf->enable_tracing) {
195201
return;
196202
}

src/ngx_http_datadog_module.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ static auto datadog_commands =
9797

9898
#ifdef WITH_RUM
9999
,
100-
rum_directives
100+
datadog::nginx::rum::rum_directives
101101
#endif
102102
);
103103

@@ -488,7 +488,7 @@ static char *merge_datadog_loc_conf(ngx_conf_t *cf, void *parent,
488488
#endif
489489

490490
#ifdef WITH_RUM
491-
datadog_rum_merge_loc_config(cf, prev, conf);
491+
datadog::nginx::rum::datadog_rum_merge_loc_config(cf, prev, conf);
492492
#endif
493493

494494
return NGX_CONF_OK;

src/rum/config.cpp

+23-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ std::optional<int> parse_rum_version(std::string_view config_version) {
109109

110110
} // namespace
111111

112-
extern "C" {
112+
namespace datadog::nginx::rum {
113113

114114
char *on_datadog_rum_config(ngx_conf_t *cf, ngx_command_t *command,
115115
void *conf) {
@@ -164,6 +164,19 @@ char *on_datadog_rum_config(ngx_conf_t *cf, ngx_command_t *command,
164164
}
165165

166166
loc_conf->rum_snippet = snippet;
167+
168+
loc_conf->rum_remote_config_tag = "remote_config_used:false";
169+
170+
if (auto it = rum_config.find("applicationId");
171+
it != rum_config.end() && !it->second.empty()) {
172+
loc_conf->rum_application_id_tag = "application_id:" + it->second[0];
173+
}
174+
175+
if (auto it = rum_config.find("remoteConfigurationId");
176+
it != rum_config.end() && !it->second.empty()) {
177+
loc_conf->rum_remote_config_tag = "remote_config_used:true";
178+
}
179+
167180
return NGX_CONF_OK;
168181
}
169182

@@ -175,6 +188,14 @@ char *datadog_rum_merge_loc_config(ngx_conf_t *cf,
175188
child->rum_snippet = parent->rum_snippet;
176189
}
177190

191+
if (child->rum_application_id_tag.empty()) {
192+
child->rum_application_id_tag = parent->rum_application_id_tag;
193+
}
194+
195+
if (child->rum_remote_config_tag.empty()) {
196+
child->rum_remote_config_tag = parent->rum_remote_config_tag;
197+
}
198+
178199
return NGX_OK;
179200
}
180-
}
201+
} // namespace datadog::nginx::rum

src/rum/config.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ extern "C" {
88
#include <ngx_config.h>
99
#include <ngx_core.h>
1010
#include <ngx_http.h>
11+
}
1112

13+
namespace datadog::nginx::rum {
1214
// Handler for `datadog_rum_json_config` directive.
1315
// Load a JSON RUM configuration file.
1416
char *on_datadog_rum_json_config(ngx_conf_t *cf, ngx_command_t *command,
@@ -23,7 +25,7 @@ char *datadog_rum_merge_loc_config(ngx_conf_t *cf,
2325
datadog::nginx::datadog_loc_conf_t *parent,
2426
datadog::nginx::datadog_loc_conf_t *child);
2527

26-
const datadog::nginx::directive rum_directives[] = {
28+
constexpr datadog::nginx::directive rum_directives[] = {
2729
{
2830
"datadog_rum",
2931
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
@@ -42,5 +44,5 @@ const datadog::nginx::directive rum_directives[] = {
4244
0,
4345
NULL,
4446
},
45-
}
46-
}
47+
};
48+
} // namespace datadog::nginx::rum

src/rum/injection.cpp

+57-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "injection.h"
22

3+
#include <datadog/telemetry/telemetry.h>
4+
35
extern "C" {
46
#include <ngx_core.h>
57
}
@@ -9,15 +11,15 @@ extern "C" {
911
#include "datadog_conf.h"
1012
#include "ngx_http_datadog_module.h"
1113
#include "string_util.h"
14+
#include "telemetry.h"
1215

1316
namespace datadog {
1417
namespace nginx {
1518
namespace rum {
1619
namespace {
1720

18-
ngx_table_elt_t *search_header(ngx_http_request_t *request,
19-
std::string_view key) {
20-
ngx_list_part_t *part = &request->headers_in.headers.part;
21+
ngx_table_elt_t *search_header(ngx_list_t &headers, std::string_view key) {
22+
ngx_list_part_t *part = &headers.part;
2123
auto *h = static_cast<ngx_table_elt_t *>(part->elts);
2224

2325
for (std::size_t i = 0;; i++) {
@@ -86,32 +88,59 @@ ngx_int_t InjectionHandler::on_header_filter(
8688
return next_header_filter(r);
8789
}
8890

89-
if (auto injected_header = search_header(r, "x-datadog-rum-injected");
91+
if (auto injected_header =
92+
search_header(r->headers_in.headers, "x-datadog-rum-injected");
9093
injected_header != nullptr) {
9194
if (nginx::to_string_view(injected_header->value) == "1") {
9295
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
9396
"RUM SDK injection skipped: resource may already have RUM "
9497
"SDK injected.");
98+
datadog::telemetry::counter::increment(
99+
telemetry::injection_skipped,
100+
telemetry::build_tags("reason:already_injected",
101+
cfg->rum_application_id_tag,
102+
cfg->rum_remote_config_tag));
103+
95104
return next_header_filter(r);
96105
}
97106
}
98107

99108
if (r->header_only || r->headers_out.content_length_n == 0) {
100109
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
101110
"RUM SDK injection skipped: empty content");
111+
112+
datadog::telemetry::counter::increment(
113+
telemetry::injection_skipped,
114+
telemetry::build_tags("reason:no_content", cfg->rum_application_id_tag,
115+
cfg->rum_remote_config_tag));
116+
102117
return next_header_filter(r);
103118
}
104119

105120
if (!is_html_content(&r->headers_out.content_type)) {
106121
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
107122
"RUM SDK injection skipped: not an HTML page");
123+
124+
datadog::telemetry::counter::increment(
125+
telemetry::injection_skipped,
126+
telemetry::build_tags("reason:invalid_content_type",
127+
cfg->rum_application_id_tag,
128+
cfg->rum_remote_config_tag));
129+
108130
return next_header_filter(r);
109131
}
110132

111133
if (auto content_encoding = r->headers_out.content_encoding;
112134
content_encoding != nullptr && content_encoding->value.len != 0) {
113135
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
114136
"RUM SDK injection skipped: compressed html content");
137+
138+
datadog::telemetry::counter::increment(
139+
telemetry::injection_skipped,
140+
telemetry::build_tags("reason:compressed_html",
141+
cfg->rum_application_id_tag,
142+
cfg->rum_remote_config_tag));
143+
115144
return next_header_filter(r);
116145
}
117146

@@ -176,6 +205,12 @@ ngx_int_t InjectionHandler::on_body_filter(
176205
state_ = state::injected;
177206
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
178207
"RUM SDK injected successfully injected");
208+
209+
datadog::telemetry::counter::increment(
210+
telemetry::injection_succeed,
211+
telemetry::build_tags(cfg->rum_application_id_tag,
212+
cfg->rum_remote_config_tag));
213+
179214
return output(r, output_chain, next_body_filter);
180215
}
181216
}
@@ -192,11 +227,29 @@ ngx_int_t InjectionHandler::on_body_filter(
192227

193228
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
194229
"RUM SDK injection failed: no injection point found");
230+
231+
datadog::telemetry::counter::increment(
232+
telemetry::injection_failed,
233+
telemetry::build_tags("reason:missing_header_tag",
234+
cfg->rum_application_id_tag,
235+
cfg->rum_remote_config_tag));
195236
}
196237

197238
return output(r, output_chain, next_body_filter);
198239
}
199240

241+
ngx_int_t InjectionHandler::on_log_request(ngx_http_request_t *r) {
242+
if (auto csp =
243+
search_header(r->headers_out.headers, "content-security-policy");
244+
csp != nullptr) {
245+
datadog::telemetry::counter::increment(
246+
telemetry::injection_failed,
247+
telemetry::build_tags("status:seen", "kind:header"));
248+
}
249+
250+
return NGX_OK;
251+
}
252+
200253
// NOTE(@dmehala): this function is not necessary for now, however,
201254
// it will when we will reuse buffer.
202255
ngx_int_t InjectionHandler::output(

src/rum/injection.h

+5
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ class InjectionHandler final {
6767
ngx_chain_t *in,
6868
ngx_http_output_body_filter_pt &next_body_filter);
6969

70+
// Handles the logging phase of an HTTP request.
71+
// @param r - HTTP request being processed.
72+
// @return ngx_int_t - Status code indicating success or failure.
73+
ngx_int_t on_log_request(ngx_http_request_t *r);
74+
7075
private:
7176
// Sends the output to the next body filter.
7277
// @param r - HTTP request being processed.

src/rum/telemetry.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "telemetry.h"
2+
3+
#include <datadog/telemetry/telemetry.h>
4+
5+
#include <format>
6+
#include <string_view>
7+
8+
#include "version.h"
9+
10+
using namespace datadog::telemetry;
11+
12+
namespace datadog {
13+
namespace nginx {
14+
namespace rum {
15+
namespace telemetry {
16+
17+
const datadog::telemetry::Counter injection_skipped = {"injection.skipped",
18+
"rum", true};
19+
20+
const datadog::telemetry::Counter injection_succeed = {"injection.succeed",
21+
"rum", true};
22+
23+
const datadog::telemetry::Counter injection_failed = {"injection.failed", "rum",
24+
true};
25+
26+
const datadog::telemetry::Counter content_security_policy = {
27+
"injection.content_security_policy", "rum", true};
28+
29+
} // namespace telemetry
30+
} // namespace rum
31+
} // namespace nginx
32+
} // namespace datadog

src/rum/telemetry.h

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include <datadog/telemetry/metrics.h>
2+
3+
#include <format>
4+
#include <string>
5+
#include <string_view>
6+
#include <utility>
7+
#include <vector>
8+
9+
#include "version.h"
10+
11+
namespace datadog {
12+
namespace nginx {
13+
namespace rum {
14+
namespace telemetry {
15+
16+
template <typename... T>
17+
auto build_tags(T&&... specific_tags) {
18+
std::vector<std::string> tags{std::forward<T>(specific_tags)...};
19+
tags.emplace_back("integration_name:nginx");
20+
tags.emplace_back("injector_version:0.1.0");
21+
tags.emplace_back(std::format("integration_version:{}",
22+
std::string_view(datadog_semver_nginx_mod)));
23+
24+
return tags;
25+
}
26+
27+
const extern datadog::telemetry::Counter injection_skipped;
28+
const extern datadog::telemetry::Counter injection_succeed;
29+
const extern datadog::telemetry::Counter injection_failed;
30+
const extern datadog::telemetry::Counter content_security_policy;
31+
32+
} // namespace telemetry
33+
} // namespace rum
34+
} // namespace nginx
35+
} // namespace datadog

0 commit comments

Comments
 (0)