Skip to content

Commit e85e1b8

Browse files
authored
chore(metrics): add v3 endpoint telemetry (#1888)
## Summary <!-- Please provide a brief summary about what this PR does. This should help the reviewers give feedback faster and with higher quality. --> Adds ADP telemetry needed for Metrics V3 rollout dashboards. New/remapped telemetry: - `serializer.v3_column_size{column,compressed}` - `serializer.v3_values_count{type}` - `serializer.v3_payload_split_reason{reason}` - `sketch_series.sketch_too_big` - transaction bytes by endpoint/domain/status ## Change Type - [ ] Bug fix - [ ] New feature - [x] Non-functional (chore, refactoring, docs) - [ ] Performance ## How did you test this PR? <!-- Please how you tested these changes here --> Deployed custom image to staging ## References <!-- Please list any issues closed by this PR. --> <!-- - Closes: <issue link> --> <!-- Any other issues or PRs relevant to this PR? Feel free to list them here. -->
1 parent f059af1 commit e85e1b8

13 files changed

Lines changed: 961 additions & 101 deletions

File tree

bin/agent-data-plane/src/state/metrics/rules/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use saluki_core::observability::metrics::RemapperRule;
33
mod aggregation;
44
mod compat;
55
mod dogstatsd;
6+
mod serializer;
67
mod transaction;
78

89
/// Returns the list of remapper rules relevant to metrics we send to the Datadog Agent via Remote Agent Registry (RAR).
@@ -14,6 +15,7 @@ pub fn get_datadog_agent_remappings() -> Vec<RemapperRule> {
1415
rules.extend(self::dogstatsd::get_dogstatsd_remappings());
1516
rules.extend(self::aggregation::get_aggregation_remappings());
1617
rules.extend(self::transaction::get_transaction_remappings());
18+
rules.extend(self::serializer::get_serializer_remappings());
1719
rules
1820
}
1921

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use super::RemapperRule;
2+
3+
pub fn get_serializer_remappings() -> Vec<RemapperRule> {
4+
vec![
5+
RemapperRule::by_name("adp.serializer.v3_column_size", "serializer.v3_column_size")
6+
.with_original_tags(["column", "compressed"])
7+
.with_help_text("Number of bytes occupied by each column"),
8+
RemapperRule::by_name("adp.serializer.v3_values_count", "serializer.v3_values_count")
9+
.with_original_tags(["type"])
10+
.with_help_text("Number of values encoded using a specific encoding type"),
11+
RemapperRule::by_name(
12+
"adp.serializer.v3_payload_split_reason",
13+
"serializer.v3_payload_split_reason",
14+
)
15+
.with_original_tags(["reason"])
16+
.with_help_text("Why payload was split"),
17+
RemapperRule::by_name("adp.serializer.v3_item_too_big", "sketch_series.sketch_too_big")
18+
.with_help_text("Number of payloads dropped because they were too big for the stream compressor"),
19+
]
20+
}

bin/agent-data-plane/src/state/metrics/rules/transaction.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@ use super::RemapperRule;
33
pub fn get_transaction_remappings() -> Vec<RemapperRule> {
44
vec![
55
// Transaction metrics.
6+
RemapperRule::by_name(
7+
"adp.network_http_requests_input_bytes_total",
8+
"transactions.input_bytes",
9+
)
10+
.with_original_tags(["domain", "endpoint"])
11+
.with_help_text("Incoming transaction sizes in bytes"),
12+
RemapperRule::by_name("adp.network_http_requests_input_total", "transactions.input_count")
13+
.with_original_tags(["domain", "endpoint"])
14+
.with_help_text("Incoming transaction count"),
615
RemapperRule::by_name("adp.network_http_requests_failed_total", "transactions.dropped")
716
.with_original_tags(["domain", "endpoint"])
817
.with_help_text("Transaction drop count"),

lib/saluki-components/src/common/datadog/io.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ use super::{
4343
METRIC_INTAKE_PATHS,
4444
};
4545

46+
type EndpointNameFn = dyn Fn(&Uri) -> Option<MetaString> + Send + Sync;
47+
4648
/// Size of buffer chunks for request builder buffers.
4749
///
4850
/// Used to influence the size of chunks in `ChunkedBytesBuffer`.
@@ -99,6 +101,7 @@ pub struct TransactionForwarder<B> {
99101
telemetry: ComponentTelemetry,
100102
metrics_builder: MetricsBuilder,
101103
client: HttpClient,
104+
endpoint_name: Arc<EndpointNameFn>,
102105
endpoints: Vec<RoutableEndpoint>,
103106
_marker: std::marker::PhantomData<B>,
104107
}
@@ -160,13 +163,18 @@ where
160163
F: Fn(&Uri) -> Option<MetaString> + Send + Sync + 'static,
161164
{
162165
let endpoints = config.build_routable_endpoints(live_config.clone())?;
166+
let endpoint_name: Arc<EndpointNameFn> = Arc::new(endpoint_name);
167+
let endpoint_name_for_client = Arc::clone(&endpoint_name);
163168
let mut client_builder = HttpClient::builder()
164169
.with_request_timeout(config.request_timeout())
165170
.with_max_idle_conns_per_host(config.max_idle_connections_per_host())
166171
.with_min_tls_version(config.min_tls_version())
167172
.with_http_protocol(config.http_protocol())
168173
.with_bytes_sent_counter(telemetry.bytes_sent().clone())
169-
.with_endpoint_telemetry(metrics_builder.clone(), Some(endpoint_name));
174+
.with_endpoint_telemetry(
175+
metrics_builder.clone(),
176+
Some(move |uri: &Uri| endpoint_name_for_client(uri)),
177+
);
170178
if let Some(path) = config.ssl_key_log_file_path() {
171179
client_builder = client_builder.with_tls_config(|builder| builder.with_key_log_file(path));
172180
}
@@ -189,6 +197,7 @@ where
189197
telemetry,
190198
metrics_builder,
191199
client,
200+
endpoint_name,
192201
endpoints,
193202
_marker: std::marker::PhantomData,
194203
})
@@ -210,6 +219,7 @@ where
210219
telemetry,
211220
metrics_builder,
212221
client,
222+
endpoint_name,
213223
endpoints,
214224
_marker,
215225
} = self;
@@ -225,6 +235,7 @@ where
225235
client,
226236
telemetry,
227237
metrics_builder,
238+
endpoint_name,
228239
endpoints,
229240
),
230241
);
@@ -241,7 +252,7 @@ async fn run_io_loop<B>(
241252
mut transactions_rx: mpsc::Receiver<Transaction<B>>, io_shutdown_tx: oneshot::Sender<()>,
242253
context: ComponentContext, config: ForwarderConfiguration, live_config: Option<GenericConfiguration>,
243254
service: HttpClient, telemetry: ComponentTelemetry, metrics_builder: MetricsBuilder,
244-
resolved_endpoints: Vec<RoutableEndpoint>,
255+
endpoint_name: Arc<EndpointNameFn>, resolved_endpoints: Vec<RoutableEndpoint>,
245256
) where
246257
B: Body + Buf + Clone + Send + Sync + 'static,
247258
B::Data: Send,
@@ -278,6 +289,7 @@ async fn run_io_loop<B>(
278289
service.clone(),
279290
telemetry.clone(),
280291
txnq_telemetry,
292+
Arc::clone(&endpoint_name),
281293
resolved_endpoint,
282294
),
283295
);
@@ -357,7 +369,8 @@ fn should_route_to_endpoint(is_metrics_request: bool, has_metrics_primary: bool,
357369
async fn run_endpoint_io_loop<B>(
358370
mut txns_rx: mpsc::Receiver<Transaction<B>>, task_barrier: Arc<Barrier>, context: ComponentContext,
359371
config: ForwarderConfiguration, live_config: Option<GenericConfiguration>, service: HttpClient,
360-
telemetry: ComponentTelemetry, txnq_telemetry: TransactionQueueTelemetry, endpoint: ResolvedEndpoint,
372+
telemetry: ComponentTelemetry, txnq_telemetry: TransactionQueueTelemetry, endpoint_name: Arc<EndpointNameFn>,
373+
endpoint: ResolvedEndpoint,
361374
) where
362375
B: Body + Buf + Clone + Send + Sync + 'static,
363376
B::Data: Send,
@@ -454,6 +467,14 @@ async fn run_endpoint_io_loop<B>(
454467
} else {
455468
strip_metrics_validation_headers(txn)
456469
};
470+
let transaction_size = txn.size_bytes();
471+
let transaction_endpoint_name = endpoint_name(txn.request_uri())
472+
.unwrap_or_else(|| MetaString::from(txn.request_uri().path()));
473+
telemetry.track_transaction_input(
474+
&endpoint_domain,
475+
&transaction_endpoint_name,
476+
transaction_size,
477+
);
457478

458479
match pending_txns.push_high_priority(txn).await {
459480
Ok(push_result) => track_queue_drops(&telemetry, &endpoint_domain, push_result),

lib/saluki-components/src/common/datadog/telemetry.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ const NETWORK_HTTP_REQUESTS_ERRORS_TOTAL: &str = "network_http_requests_errors_t
1212
const ERROR_TYPE_SENT_REQUEST: &str = "sent_request_error";
1313
const ERROR_SCOPE_TRANSACTION: &str = "transaction";
1414

15+
struct TransactionInputTelemetry {
16+
count: Counter,
17+
bytes: Counter,
18+
}
19+
1520
/// Component-specific telemetry.
1621
///
1722
/// This type covers high-level component telemetry, such as events/bytes sent, tailored to the Datadog destinations and
@@ -22,6 +27,7 @@ pub struct ComponentTelemetry {
2227
events_sent: Counter,
2328
events_sent_batch_size: Histogram,
2429
bytes_sent: Counter,
30+
transaction_input_by_endpoint: Arc<Mutex<HashMap<(String, String), TransactionInputTelemetry>>>,
2531
data_points_sent_by_domain: Arc<Mutex<HashMap<String, Gauge>>>,
2632
data_points_dropped_by_domain: Arc<Mutex<HashMap<String, Gauge>>>,
2733
events_dropped_http: Counter,
@@ -41,6 +47,7 @@ impl ComponentTelemetry {
4147
events_sent: builder.register_counter("component_events_sent_total"),
4248
events_sent_batch_size: builder.register_trace_histogram("component_events_sent_batch_size"),
4349
bytes_sent: builder.register_counter("component_bytes_sent_total"),
50+
transaction_input_by_endpoint: Arc::new(Mutex::new(HashMap::new())),
4451
data_points_sent_by_domain: Arc::new(Mutex::new(HashMap::new())),
4552
data_points_dropped_by_domain: Arc::new(Mutex::new(HashMap::new())),
4653
events_dropped_http: builder.register_counter_with_tags(
@@ -73,6 +80,29 @@ impl ComponentTelemetry {
7380
&self.bytes_sent
7481
}
7582

83+
/// Tracks a transaction entering the forwarder queue.
84+
pub fn track_transaction_input(&self, domain: &str, endpoint: &str, bytes: u64) {
85+
let mut telemetry = self.transaction_input_by_endpoint.lock().unwrap();
86+
let per_endpoint = telemetry
87+
// TODO: Avoid allocating key strings on every transaction if we can make the telemetry registry lookup
88+
// support borrowed endpoint/domain keys.
89+
.entry((domain.to_string(), endpoint.to_string()))
90+
.or_insert_with(|| {
91+
let tags = [("domain", domain.to_string()), ("endpoint", endpoint.to_string())];
92+
TransactionInputTelemetry {
93+
count: self
94+
.builder
95+
.register_counter_with_tags("network_http_requests_input_total", tags.clone()),
96+
bytes: self
97+
.builder
98+
.register_counter_with_tags("network_http_requests_input_bytes_total", tags),
99+
}
100+
});
101+
102+
per_endpoint.count.increment(1);
103+
per_endpoint.bytes.increment(bytes);
104+
}
105+
76106
/// Returns a reference to the "events dropped (encoder)" counter.
77107
pub fn events_dropped_encoder(&self) -> &Counter {
78108
&self.events_dropped_encoder

0 commit comments

Comments
 (0)