Skip to content

Commit db03e5c

Browse files
committed
Add tag filters to /info
Signed-off-by: Bob Weinand <bob.weinand@datadoghq.com>
1 parent a102d48 commit db03e5c

File tree

6 files changed

+123
-27
lines changed

6 files changed

+123
-27
lines changed

datadog-ipc/src/platform/mem_handle.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use crate::platform::{mmap_handle, munmap_handle, OwnedFileHandle, PlatformHandl
66
#[cfg(feature = "tiny-bytes")]
77
use libdd_tinybytes::UnderlyingBytes;
88
use serde::{Deserialize, Serialize};
9-
use std::{ffi::CString, io, ptr::NonNull};
109
use std::os::fd::AsRawFd;
10+
use std::{ffi::CString, io, ptr::NonNull};
1111

1212
#[derive(Clone, Serialize, Deserialize, Debug)]
1313
pub struct ShmHandle {
@@ -93,7 +93,12 @@ where
9393
// Use fallocate on Linux to eagerly commit the new pages: ENOSPC at resize time is
9494
// recoverable; a later SIGBUS mid-execution is not.
9595
#[cfg(target_os = "linux")]
96-
nix::fcntl::fallocate(fd.as_raw_fd(), nix::fcntl::FallocateFlags::empty(), 0, new_size)?;
96+
nix::fcntl::fallocate(
97+
fd.as_raw_fd(),
98+
nix::fcntl::FallocateFlags::empty(),
99+
0,
100+
new_size,
101+
)?;
97102
#[cfg(not(target_os = "linux"))]
98103
nix::unistd::ftruncate(&fd, new_size)?;
99104
Ok(())

datadog-ipc/src/platform/unix/mem_handle.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ use crate::platform::{
77
use io_lifetimes::OwnedFd;
88
use libc::{chmod, off_t};
99
use nix::errno::Errno;
10-
use nix::fcntl::{open, OFlag};
1110
#[cfg(target_os = "linux")]
1211
use nix::fcntl::{fallocate, FallocateFlags};
12+
use nix::fcntl::{open, OFlag};
1313
use nix::sys::mman::{self, mmap, munmap, MapFlags, ProtFlags};
1414
use nix::sys::stat::Mode;
1515
use nix::unistd::{fchown, ftruncate, mkdir, unlink, Uid};

datadog-ipc/src/shm_stats.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,14 @@ mod tests {
853853
.unwrap();
854854
c.add_span(&span("svc", "res", 1_000_000));
855855
c.add_span(&span("svc", "res", 2_000_000));
856-
let bytes = c.flush(true, "h", "e", "v", "s", "r");
856+
let bytes = c.flush(
857+
true,
858+
"h".into(),
859+
"e".into(),
860+
"v".into(),
861+
"s".into(),
862+
"r".into(),
863+
);
857864
assert!(bytes.is_some());
858865
}
859866

@@ -870,7 +877,14 @@ mod tests {
870877
.unwrap();
871878
let worker = ShmSpanConcentrator::open(path.as_c_str()).unwrap();
872879
worker.add_span(&span("svc2", "res2", 5_000_000));
873-
let bytes = creator.flush(true, "h", "", "", "", "r");
880+
let bytes = creator.flush(
881+
true,
882+
"h".into(),
883+
"".into(),
884+
"".into(),
885+
"".into(),
886+
"r".into(),
887+
);
874888
assert!(bytes.is_some());
875889
}
876890

@@ -910,7 +924,16 @@ mod tests {
910924
DEFAULT_STRING_POOL_BYTES,
911925
)
912926
.unwrap();
913-
assert!(c.flush(false, "h", "e", "v", "s", "r").is_none());
927+
assert!(c
928+
.flush(
929+
false,
930+
"h".into(),
931+
"e".into(),
932+
"v".into(),
933+
"s".into(),
934+
"r".into()
935+
)
936+
.is_none());
914937
}
915938

916939
#[test]

datadog-sidecar/src/service/sidecar_server.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ use crate::service::debugger_diagnostics_bookkeeper::{
3535
};
3636
use crate::service::exception_hash_rate_limiter::EXCEPTION_HASH_LIMITER;
3737
use crate::service::remote_configs::{RemoteConfigNotifyTarget, RemoteConfigs};
38-
use crate::service::stats_flusher::{ensure_stats_concentrator, flush_all_stats_now, get_hostname, stats_endpoint, ConcentratorKey, SpanConcentratorState, StatsConfig};
38+
use crate::service::stats_flusher::{
39+
ensure_stats_concentrator, flush_all_stats_now, get_hostname, stats_endpoint, ConcentratorKey,
40+
SpanConcentratorState, StatsConfig,
41+
};
3942
use crate::service::tracing::trace_flusher::TraceFlusherStats;
4043
use crate::tokio_util::run_or_spawn_shared;
4144
use datadog_live_debugger::sender::{agent_info_supports_debugger_v2_endpoint, DebuggerType};
@@ -681,8 +684,17 @@ impl SidecarInterface for ConnectionSidecarHandler {
681684
*session.stats_config.lock_or_panic() = Some(StatsConfig {
682685
endpoint: stats_endpoint(&config.endpoint).unwrap_or_else(|| config.endpoint.clone()),
683686
flush_interval: config.flush_interval,
684-
hostname: if config.hostname.is_empty() { get_hostname() } else { config.hostname.clone() },
685-
process_tags: config.process_tags.iter().map(|t| t.to_string()).collect::<Vec<_>>().join(","),
687+
hostname: if config.hostname.is_empty() {
688+
get_hostname()
689+
} else {
690+
config.hostname.clone()
691+
},
692+
process_tags: config
693+
.process_tags
694+
.iter()
695+
.map(|t| t.to_string())
696+
.collect::<Vec<_>>()
697+
.join(","),
686698
root_service: config.root_service.clone(),
687699
language: config.language.clone(),
688700
tracer_version: config.tracer_version.clone(),
@@ -984,7 +996,11 @@ impl SidecarInterface for ConnectionSidecarHandler {
984996
.as_ref()
985997
.map(|c| c.root_service.clone())
986998
.unwrap_or_default();
987-
let map_key = ConcentratorKey { env, version, root_service: service };
999+
let map_key = ConcentratorKey {
1000+
env,
1001+
version,
1002+
root_service: service,
1003+
};
9881004
let guard = self
9891005
.server
9901006
.span_concentrators

datadog-sidecar/src/service/stats_flusher.rs

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
//! triggers creation for a given (env, version, service) is used as the runtime_id in the
1212
//! stats payload for that key.
1313
14+
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
15+
use base64::Engine;
1416
use datadog_ipc::shm_stats::{
1517
ShmSpanConcentrator, DEFAULT_SLOT_COUNT, DEFAULT_STRING_POOL_BYTES, RELOAD_FILL_RATIO,
1618
};
@@ -27,8 +29,6 @@ use std::hash::{Hash, Hasher};
2729
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering::*};
2830
use std::sync::{Arc, Mutex, Weak};
2931
use std::time::{Duration, SystemTime, UNIX_EPOCH};
30-
use base64::Engine;
31-
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
3232
use tracing::{error, info, warn};
3333
use zwohash::ZwoHasher;
3434

@@ -55,7 +55,9 @@ pub(crate) fn stats_endpoint(endpoint: &Endpoint) -> Option<Endpoint> {
5555
return None;
5656
}
5757
let mut parts = endpoint.url.clone().into_parts();
58-
parts.path_and_query = Some(PathAndQuery::from_static(libdd_trace_stats::stats_exporter::STATS_ENDPOINT_PATH));
58+
parts.path_and_query = Some(PathAndQuery::from_static(
59+
libdd_trace_stats::stats_exporter::STATS_ENDPOINT_PATH,
60+
));
5961
Some(Endpoint {
6062
url: http::Uri::from_parts(parts).ok()?,
6163
..endpoint.clone()
@@ -66,7 +68,7 @@ pub(crate) fn stats_endpoint(endpoint: &Endpoint) -> Option<Endpoint> {
6668
#[derive(Clone)]
6769
pub(crate) struct StatsConfig {
6870
/// Stats endpoint with final path already baked in.
69-
pub endpoint: Endpoint,
71+
pub endpoint: Endpoint,
7072
pub flush_interval: Duration,
7173
/// Machine hostname, forwarded to the stats payload `hostname` field.
7274
pub hostname: String,
@@ -149,20 +151,36 @@ impl SpanConcentratorState {
149151
/// Used for one-shot flushes (idle-removal, `flush_all_stats_now`). The retry-accumulator
150152
/// path in `run_stats_flush_loop` has its own send loop and does not use this.
151153
async fn send_and_emit(&self, client: &HttpClient, payload: pb::ClientStatsPayload) {
152-
let endpoint = self.endpoint.lock().unwrap_or_else(|e| e.into_inner()).clone();
154+
let endpoint = self
155+
.endpoint
156+
.lock()
157+
.unwrap_or_else(|e| e.into_inner())
158+
.clone();
153159
let spans = spans_in_payload(&payload);
154160
let buckets = payload.stats.len() as i64;
155-
match send_stats(client, &endpoint, &payload, self.language.clone(), self.tracer_version.clone()).await {
156-
StatsSendResult::Sent => emit_flush_metrics(&self.dogstatsd, &self.base_tags, spans, 1, buckets, 0),
157-
StatsSendResult::Error | StatsSendResult::Network => emit_flush_metrics(&self.dogstatsd, &self.base_tags, 0, 0, 0, 1),
161+
match send_stats(
162+
client,
163+
&endpoint,
164+
&payload,
165+
self.language.clone(),
166+
self.tracer_version.clone(),
167+
)
168+
.await
169+
{
170+
StatsSendResult::Sent => {
171+
emit_flush_metrics(&self.dogstatsd, &self.base_tags, spans, 1, buckets, 0)
172+
}
173+
StatsSendResult::Error | StatsSendResult::Network => {
174+
emit_flush_metrics(&self.dogstatsd, &self.base_tags, 0, 0, 0, 1)
175+
}
158176
}
159177
}
160178
}
161179

162180
/// RAII guard that keeps an (env, version, root-service) concentrator alive.
163181
///
164-
/// Stored in `ActiveApplication`. When the last guard for a given (env, version, root-service) is dropped,
165-
/// the flush loop will remove the concentrator after `IDLE_REMOVE_SECS` seconds.
182+
/// Stored in `ActiveApplication`. When the last guard for a given (env, version, root-service) is
183+
/// dropped, the flush loop will remove the concentrator after `IDLE_REMOVE_SECS` seconds.
166184
pub struct SpanConcentratorGuard {
167185
ref_count: Arc<AtomicUsize>,
168186
last_zero_secs: Arc<AtomicU64>,
@@ -198,7 +216,6 @@ pub fn env_stats_shm_path(env: &str, version: &str, service: &str) -> CString {
198216
CString::new(path).unwrap()
199217
}
200218

201-
202219
/// Result of a single stats payload send attempt.
203220
#[must_use]
204221
enum StatsSendResult {
@@ -395,7 +412,15 @@ pub async fn run_stats_flush_loop(
395412
let mut errors = 0i64;
396413
let endpoint = s.endpoint.lock().unwrap_or_else(|e| e.into_inner()).clone();
397414
for p in &pending {
398-
match send_stats(&client, &endpoint, &p, s.language.to_owned(), s.tracer_version.to_owned()).await {
415+
match send_stats(
416+
&client,
417+
&endpoint,
418+
&p,
419+
s.language.to_owned(),
420+
s.tracer_version.to_owned(),
421+
)
422+
.await
423+
{
399424
StatsSendResult::Sent => {
400425
to_drain += 1;
401426
payloads_sent += 1;
@@ -413,7 +438,14 @@ pub async fn run_stats_flush_loop(
413438
}
414439
}
415440
pending.drain(..to_drain);
416-
emit_flush_metrics(&s.dogstatsd, &s.base_tags, spans_sent, payloads_sent, buckets_sent, errors);
441+
emit_flush_metrics(
442+
&s.dogstatsd,
443+
&s.base_tags,
444+
spans_sent,
445+
payloads_sent,
446+
buckets_sent,
447+
errors,
448+
);
417449

418450
// Idle-removal check: if no app has held a guard for >= IDLE_REMOVE_SECS, retire this
419451
// concentrator with a final force-flush.
@@ -428,7 +460,11 @@ pub async fn run_stats_flush_loop(
428460
};
429461
let idle_secs = if s.ref_count.load(Acquire) == 0 {
430462
let last_zero = s.last_zero_secs.load(Acquire);
431-
if last_zero != u64::MAX { now_secs().saturating_sub(last_zero) } else { 0 }
463+
if last_zero != u64::MAX {
464+
now_secs().saturating_sub(last_zero)
465+
} else {
466+
0
467+
}
432468
} else {
433469
0
434470
};
@@ -455,13 +491,14 @@ pub async fn run_stats_flush_loop(
455491
/// Create (or look up) the SHM span concentrator for an (env, service, version) pair, increment its
456492
/// reference count, and return a guard.
457493
///
458-
/// Idempotent with respect to SHM creation: if a concentrator for this (env, service, version) already
459-
/// exists, only the reference count is incremented.
494+
/// Idempotent with respect to SHM creation: if a concentrator for this (env, service, version)
495+
/// already exists, only the reference count is incremented.
460496
///
461497
/// Returns `None` when no `SessionConfig` has been set yet for the calling session (caller should
462498
/// retry later) or when SHM creation fails.
463499
///
464-
/// - `concentrators`: the global per-(env,version,service) map from `SidecarServer::span_concentrators`
500+
/// - `concentrators`: the global per-(env,version,service) map from
501+
/// `SidecarServer::span_concentrators`
465502
/// - `env`: the environment name
466503
/// - `version`: the application version
467504
/// - `service_name`: the root service name reported by `set_universal_service_tags`

libdd-data-pipeline/src/agent_info/schema.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@ pub struct AgentInfoStruct {
3737
pub span_kinds_stats_computed: Option<Vec<String>>,
3838
/// Container tags hash from HTTP response header
3939
pub container_tags_hash: Option<String>,
40+
/// Exact-match tag filters applied before stats computation (root span only).
41+
pub filter_tags: Option<FilterTagsConfig>,
42+
/// Regex-match tag filters applied before stats computation (root span only).
43+
pub filter_tags_regex: Option<FilterTagsConfig>,
44+
/// Regex patterns for root-span resource names; matching traces are excluded from stats.
45+
pub ignore_resources: Option<Vec<String>>,
46+
}
47+
48+
/// Require/reject lists for tag-based trace filters exposed by the agent /info endpoint.
49+
#[derive(Clone, Serialize, Deserialize, Default, Debug, PartialEq)]
50+
pub struct FilterTagsConfig {
51+
/// All listed filters must match at least one root-span tag for the trace to be accepted.
52+
pub require: Option<Vec<String>>,
53+
/// If any listed filter matches a root-span tag the trace is rejected.
54+
pub reject: Option<Vec<String>>,
4055
}
4156

4257
#[allow(missing_docs)]

0 commit comments

Comments
 (0)