Skip to content

Commit b33e7a0

Browse files
authored
feature: add global labels and namespace support for dogstatsd exporter (#555)
1 parent e113ab4 commit b33e7a0

File tree

3 files changed

+282
-34
lines changed

3 files changed

+282
-34
lines changed

metrics-exporter-dogstatsd/src/builder.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{fmt, net::SocketAddr, sync::Arc, time::Duration};
22

3+
use metrics::Label;
34
use thiserror::Error;
45
use tracing::debug;
56

@@ -97,6 +98,8 @@ pub struct DogStatsDBuilder {
9798
histogram_sampling: bool,
9899
histogram_reservoir_size: usize,
99100
histograms_as_distributions: bool,
101+
global_labels: Vec<Label>,
102+
global_prefix: Option<String>,
100103
}
101104

102105
impl DogStatsDBuilder {
@@ -229,6 +232,29 @@ impl DogStatsDBuilder {
229232
self
230233
}
231234

235+
/// Set Global labels for all metrics to this exporter
236+
///
237+
/// Global labels are applied to all metrics.
238+
#[must_use]
239+
pub fn with_global_labels(mut self, labels: Vec<Label>) -> Self {
240+
self.global_labels = labels;
241+
self
242+
}
243+
244+
/// Adds a global prefix for every metric name.
245+
///
246+
/// Global prefix is applied to all metrics. Its intended use is to introduce a configurable
247+
/// namespace for every metric generated by the application such that different deployments
248+
/// can operate on their own family of metrics without overlap.
249+
#[must_use]
250+
pub fn set_global_prefix<P>(mut self, prefix: P) -> Self
251+
where
252+
P: Into<String>,
253+
{
254+
self.global_prefix = Some(prefix.into());
255+
self
256+
}
257+
232258
/// Sets whether or not to enable telemetry for the exporter.
233259
///
234260
/// When enabled, additional metrics will be sent to the configured remote server that provide insight into the
@@ -321,6 +347,8 @@ impl DogStatsDBuilder {
321347
histogram_sampling: self.histogram_sampling,
322348
histogram_reservoir_size: self.histogram_reservoir_size,
323349
histograms_as_distributions: self.histograms_as_distributions,
350+
global_labels: self.global_labels,
351+
global_prefix: self.global_prefix,
324352
};
325353

326354
let state = Arc::new(State::new(state_config));
@@ -387,6 +415,8 @@ impl Default for DogStatsDBuilder {
387415
histogram_sampling: false,
388416
histogram_reservoir_size: DEFAULT_HISTOGRAM_RESERVOIR_SIZE,
389417
histograms_as_distributions: true,
418+
global_labels: Vec::default(),
419+
global_prefix: Option::default(),
390420
}
391421
}
392422
}

metrics-exporter-dogstatsd/src/state.rs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{collections::HashSet, time::SystemTime};
22

3-
use metrics::Key;
3+
use metrics::{Key, Label};
44
use metrics_util::registry::Registry;
55
use tracing::error;
66

@@ -27,6 +27,12 @@ pub struct StateConfiguration {
2727

2828
/// Whether or not to emit histograms as distributions.
2929
pub histograms_as_distributions: bool,
30+
31+
/// Global labels to add to all metrics
32+
pub global_labels: Vec<Label>,
33+
34+
/// Global prefix/namespace to use for all metrics
35+
pub global_prefix: Option<String>,
3036
}
3137

3238
/// Exporter state.
@@ -96,7 +102,19 @@ impl State {
96102

97103
active_counters += 1;
98104

99-
let result = writer.write_counter(&key, value, self.get_aggregation_timestamp());
105+
let prefix = if key.name().starts_with("datadog.dogstatsd.client") {
106+
None
107+
} else {
108+
self.config.global_prefix.as_deref()
109+
};
110+
111+
let result = writer.write_counter(
112+
&key,
113+
value,
114+
self.get_aggregation_timestamp(),
115+
prefix,
116+
&self.config.global_labels,
117+
);
100118
if result.any_failures() {
101119
let points_dropped = result.points_dropped();
102120
error!(
@@ -117,7 +135,18 @@ impl State {
117135

118136
for (key, gauge) in gauges {
119137
let (value, points_flushed) = gauge.flush();
120-
let result = writer.write_gauge(&key, value, self.get_aggregation_timestamp());
138+
let prefix = if key.name().starts_with("datadog.dogstatsd.client") {
139+
None
140+
} else {
141+
self.config.global_prefix.as_deref()
142+
};
143+
let result = writer.write_gauge(
144+
&key,
145+
value,
146+
self.get_aggregation_timestamp(),
147+
prefix,
148+
&self.config.global_labels,
149+
);
121150
if result.any_failures() {
122151
let points_dropped = result.points_dropped();
123152
error!(metric_name = key.name(), points_dropped, "Failed to build gauge payload.");
@@ -137,13 +166,30 @@ impl State {
137166
}
138167

139168
active_histograms += 1;
169+
let prefix = if key.name().starts_with("datadog.dogstatsd.client") {
170+
None
171+
} else {
172+
self.config.global_prefix.as_deref()
173+
};
140174

141175
histogram.flush(|maybe_sample_rate, values| {
142176
let points_len = values.len();
143177
let result = if self.config.histograms_as_distributions {
144-
writer.write_distribution(&key, values, maybe_sample_rate)
178+
writer.write_distribution(
179+
&key,
180+
values,
181+
maybe_sample_rate,
182+
prefix,
183+
&self.config.global_labels,
184+
)
145185
} else {
146-
writer.write_histogram(&key, values, maybe_sample_rate)
186+
writer.write_histogram(
187+
&key,
188+
values,
189+
maybe_sample_rate,
190+
prefix,
191+
&self.config.global_labels,
192+
)
147193
};
148194

149195
// Scale the points flushed/dropped values by the sample rate to determine the true number of points flushed/dropped.

0 commit comments

Comments
 (0)