Skip to main content

datadog_agent_apm/semantics/
mod.rs

1//! Semantic attribute registry for OTLP.
2
3mod accessor;
4mod lookup;
5mod provider;
6mod registry;
7mod remote_config;
8
9#[cfg(any(test, feature = "test-util"))]
10pub mod test_util;
11
12pub use accessor::Accessor;
13pub use lookup::{lookup_float64, lookup_int64, lookup_string};
14pub use provider::SemanticRegistryProvider;
15pub use registry::{Condition, Provider, Registry, TagInfo, ValueType, EMBEDDED_REGISTRY};
16
17/// A named semantic concept—the canonical identity of an attribute that may
18/// have multiple representations across OpenTelemetry versions and Datadog
19/// legacy conventions.
20///
21/// Ported from upstream's `Concept` constants in `semantics.go`. Grouping is
22/// retained for ease of syncing.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub enum Concept {
25    // ---- Peer Tags ----
26    /// The `peer.service` concept.
27    PeerService,
28    /// The `peer.hostname` concept.
29    PeerHostname,
30    /// The `peer.db.name` concept.
31    PeerDbName,
32    /// The `peer.db.system` concept.
33    PeerDbSystem,
34    /// The `peer.cassandra.contact.points` concept.
35    PeerCassandraContactPoints,
36    /// The `peer.couchbase.seed.nodes` concept.
37    PeerCouchbaseSeedNodes,
38    /// The `peer.messaging.destination` concept.
39    PeerMessagingDestination,
40    /// The `peer.messaging.system` concept.
41    PeerMessagingSystem,
42    /// The `peer.kafka.bootstrap.servers` concept.
43    PeerKafkaBootstrapServers,
44    /// The `peer.rpc.service` concept.
45    PeerRpcService,
46    /// The `peer.rpc.system` concept.
47    PeerRpcSystem,
48    /// The `peer.aws.s3.bucket` concept.
49    PeerAwsS3Bucket,
50    /// The `peer.aws.sqs.queue` concept.
51    PeerAwsSqsQueue,
52    /// The `peer.aws.dynamodb.table` concept.
53    PeerAwsDynamoDbTable,
54    /// The `peer.aws.kinesis.stream` concept.
55    PeerAwsKinesisStream,
56
57    // ---- Stats Aggregation ----
58    /// The `http.status_code` concept.
59    HttpStatusCode,
60    /// The `http.method` concept.
61    HttpMethod,
62    /// The `http.route` concept.
63    HttpRoute,
64    /// The `url.template` concept.
65    UrlTemplate,
66    /// The `rpc.grpc.status_code` concept.
67    RpcGrpcStatusCode,
68    /// The `span.kind` concept.
69    SpanKind,
70    /// The `_dd.base_service` concept.
71    DdBaseService,
72
73    // ---- Service & Resource Identification ----
74    /// The `service.name` concept.
75    ServiceName,
76    /// The `resource.name` concept.
77    ResourceName,
78    /// The `operation.name` concept.
79    OperationName,
80    /// The `span.type` concept.
81    SpanType,
82    /// The `db.system` concept.
83    DbSystem,
84    /// The `db.statement` concept.
85    DbStatement,
86    /// The `db.namespace` concept.
87    DbNamespace,
88    /// The `rpc.system` concept.
89    RpcSystem,
90    /// The `rpc.service` concept.
91    RpcService,
92    /// The `messaging.system` concept.
93    MessagingSystem,
94    /// The `messaging.destination` concept.
95    MessagingDestination,
96    /// The `deployment.environment` concept.
97    DeploymentEnvironment,
98    /// The `service.version` concept.
99    ServiceVersion,
100    /// The `container.id` concept.
101    ContainerId,
102    /// The `k8s.pod.uid` concept.
103    K8sPodUid,
104
105    // ---- Obfuscation ----
106    /// The `db.query` concept.
107    DbQuery,
108    /// The `mongodb.query` concept.
109    MongoDbQuery,
110    /// The `elasticsearch.body` concept.
111    ElasticsearchBody,
112    /// The `opensearch.body` concept.
113    OpenSearchBody,
114    /// The `redis.raw_command` concept.
115    RedisRawCommand,
116    /// The `valkey.raw_command` concept.
117    ValkeyRawCommand,
118    /// The `memcached.command` concept.
119    MemcachedCommand,
120    /// The `http.url` concept.
121    HttpUrl,
122
123    // ---- Normalization ----
124    /// The `messaging.operation` concept.
125    MessagingOperation,
126    /// The `graphql.operation.type` concept.
127    GraphQlOperationType,
128    /// The `graphql.operation.name` concept.
129    GraphQlOperationName,
130    /// The `faas.invoked.provider` concept.
131    FaasInvokedProvider,
132    /// The `faas.invoked.name` concept.
133    FaasInvokedName,
134    /// The `faas.trigger` concept.
135    FaasTrigger,
136    /// The `network.protocol.name` concept.
137    NetworkProtocolName,
138    /// The `rpc.method` concept.
139    RpcMethod,
140    /// The `component` concept.
141    Component,
142    /// The `link.name` concept.
143    LinkName,
144
145    // ---- Sampling ----
146    /// The `_dd.measured` concept.
147    DdMeasured,
148    /// The `_dd.top_level` concept.
149    DdTopLevel,
150    /// The `_sampling_priority_v1` concept.
151    SamplingPriority,
152    /// The `otel.trace_id` concept.
153    OtelTraceId,
154    /// The `_dd.p.tid` concept.
155    DdPTid,
156    /// The `_dd.partial_version` concept.
157    DdPartialVersion,
158    /// The `_dd.origin` concept.
159    DdOrigin,
160
161    // ---- Datadog tags ----
162    /// The `env` concept.
163    DdEnv,
164    /// The `version` concept.
165    DdVersion,
166    /// The `_dd.hostname` concept.
167    DdHostname,
168    /// The `_dd.git.commit.sha` concept.
169    DdGitCommitSha,
170    /// The `_dd.p.dm` concept.
171    DdDecisionMaker,
172    /// The `_dd.apm_mode` concept.
173    DdApmMode,
174}
175
176impl Concept {
177    /// All known concepts, in declaration order. Used by tests to verify that
178    /// every variant has a corresponding entry in `mappings.json`.
179    pub const ALL: &'static [Concept] = &[
180        // Peer Tags
181        Concept::PeerService,
182        Concept::PeerHostname,
183        Concept::PeerDbName,
184        Concept::PeerDbSystem,
185        Concept::PeerCassandraContactPoints,
186        Concept::PeerCouchbaseSeedNodes,
187        Concept::PeerMessagingDestination,
188        Concept::PeerMessagingSystem,
189        Concept::PeerKafkaBootstrapServers,
190        Concept::PeerRpcService,
191        Concept::PeerRpcSystem,
192        Concept::PeerAwsS3Bucket,
193        Concept::PeerAwsSqsQueue,
194        Concept::PeerAwsDynamoDbTable,
195        Concept::PeerAwsKinesisStream,
196        // Stats Aggregation
197        Concept::HttpStatusCode,
198        Concept::HttpMethod,
199        Concept::HttpRoute,
200        Concept::UrlTemplate,
201        Concept::RpcGrpcStatusCode,
202        Concept::SpanKind,
203        Concept::DdBaseService,
204        // Service & Resource Identification
205        Concept::ServiceName,
206        Concept::ResourceName,
207        Concept::OperationName,
208        Concept::SpanType,
209        Concept::DbSystem,
210        Concept::DbStatement,
211        Concept::DbNamespace,
212        Concept::RpcSystem,
213        Concept::RpcService,
214        Concept::MessagingSystem,
215        Concept::MessagingDestination,
216        Concept::DeploymentEnvironment,
217        Concept::ServiceVersion,
218        Concept::ContainerId,
219        Concept::K8sPodUid,
220        // Obfuscation
221        Concept::DbQuery,
222        Concept::MongoDbQuery,
223        Concept::ElasticsearchBody,
224        Concept::OpenSearchBody,
225        Concept::RedisRawCommand,
226        Concept::ValkeyRawCommand,
227        Concept::MemcachedCommand,
228        Concept::HttpUrl,
229        // Normalization
230        Concept::MessagingOperation,
231        Concept::GraphQlOperationType,
232        Concept::GraphQlOperationName,
233        Concept::FaasInvokedProvider,
234        Concept::FaasInvokedName,
235        Concept::FaasTrigger,
236        Concept::NetworkProtocolName,
237        Concept::RpcMethod,
238        Concept::Component,
239        Concept::LinkName,
240        // Sampling
241        Concept::DdMeasured,
242        Concept::DdTopLevel,
243        Concept::SamplingPriority,
244        Concept::OtelTraceId,
245        Concept::DdPTid,
246        Concept::DdPartialVersion,
247        Concept::DdOrigin,
248        // Datadog tags
249        Concept::DdEnv,
250        Concept::DdVersion,
251        Concept::DdHostname,
252        Concept::DdGitCommitSha,
253        Concept::DdDecisionMaker,
254        Concept::DdApmMode,
255    ];
256
257    /// Canonical string identifier as used in `mappings.json`.
258    pub const fn as_str(&self) -> &'static str {
259        match self {
260            // Peer Tags
261            Concept::PeerService => "peer.service",
262            Concept::PeerHostname => "peer.hostname",
263            Concept::PeerDbName => "peer.db.name",
264            Concept::PeerDbSystem => "peer.db.system",
265            Concept::PeerCassandraContactPoints => "peer.cassandra.contact.points",
266            Concept::PeerCouchbaseSeedNodes => "peer.couchbase.seed.nodes",
267            Concept::PeerMessagingDestination => "peer.messaging.destination",
268            Concept::PeerMessagingSystem => "peer.messaging.system",
269            Concept::PeerKafkaBootstrapServers => "peer.kafka.bootstrap.servers",
270            Concept::PeerRpcService => "peer.rpc.service",
271            Concept::PeerRpcSystem => "peer.rpc.system",
272            Concept::PeerAwsS3Bucket => "peer.aws.s3.bucket",
273            Concept::PeerAwsSqsQueue => "peer.aws.sqs.queue",
274            Concept::PeerAwsDynamoDbTable => "peer.aws.dynamodb.table",
275            Concept::PeerAwsKinesisStream => "peer.aws.kinesis.stream",
276            // Stats Aggregation
277            Concept::HttpStatusCode => "http.status_code",
278            Concept::HttpMethod => "http.method",
279            Concept::HttpRoute => "http.route",
280            Concept::UrlTemplate => "url.template",
281            Concept::RpcGrpcStatusCode => "rpc.grpc.status_code",
282            Concept::SpanKind => "span.kind",
283            Concept::DdBaseService => "_dd.base_service",
284            // Service & Resource Identification
285            Concept::ServiceName => "service.name",
286            Concept::ResourceName => "resource.name",
287            Concept::OperationName => "operation.name",
288            Concept::SpanType => "span.type",
289            Concept::DbSystem => "db.system",
290            Concept::DbStatement => "db.statement",
291            Concept::DbNamespace => "db.namespace",
292            Concept::RpcSystem => "rpc.system",
293            Concept::RpcService => "rpc.service",
294            Concept::MessagingSystem => "messaging.system",
295            Concept::MessagingDestination => "messaging.destination",
296            Concept::DeploymentEnvironment => "deployment.environment",
297            Concept::ServiceVersion => "service.version",
298            Concept::ContainerId => "container.id",
299            Concept::K8sPodUid => "k8s.pod.uid",
300            // Obfuscation
301            Concept::DbQuery => "db.query",
302            Concept::MongoDbQuery => "mongodb.query",
303            Concept::ElasticsearchBody => "elasticsearch.body",
304            Concept::OpenSearchBody => "opensearch.body",
305            Concept::RedisRawCommand => "redis.raw_command",
306            Concept::ValkeyRawCommand => "valkey.raw_command",
307            Concept::MemcachedCommand => "memcached.command",
308            Concept::HttpUrl => "http.url",
309            // Normalization
310            Concept::MessagingOperation => "messaging.operation",
311            Concept::GraphQlOperationType => "graphql.operation.type",
312            Concept::GraphQlOperationName => "graphql.operation.name",
313            Concept::FaasInvokedProvider => "faas.invoked.provider",
314            Concept::FaasInvokedName => "faas.invoked.name",
315            Concept::FaasTrigger => "faas.trigger",
316            Concept::NetworkProtocolName => "network.protocol.name",
317            Concept::RpcMethod => "rpc.method",
318            Concept::Component => "component",
319            Concept::LinkName => "link.name",
320            // Sampling
321            Concept::DdMeasured => "_dd.measured",
322            Concept::DdTopLevel => "_dd.top_level",
323            Concept::SamplingPriority => "_sampling_priority_v1",
324            Concept::OtelTraceId => "otel.trace_id",
325            Concept::DdPTid => "_dd.p.tid",
326            Concept::DdPartialVersion => "_dd.partial_version",
327            Concept::DdOrigin => "_dd.origin",
328            // Datadog tags
329            Concept::DdEnv => "env",
330            Concept::DdVersion => "version",
331            Concept::DdHostname => "_dd.hostname",
332            Concept::DdGitCommitSha => "_dd.git.commit.sha",
333            Concept::DdDecisionMaker => "_dd.p.dm",
334            Concept::DdApmMode => "_dd.apm_mode",
335        }
336    }
337
338    /// Parse a concept identifier from its canonical string form.
339    ///
340    /// Registry loaders use this to skip concepts without a variant in both embedded and Remote Configuration mappings.
341    fn from_name(s: &str) -> Option<Concept> {
342        Concept::ALL.iter().copied().find(|c| c.as_str() == s)
343    }
344}
345
346// Tests that read embedded mappings must tolerate new concepts and supported fallbacks: automated updates change
347// only the snapshot and its source revision, not Rust code. Assert that required entries remain present rather than
348// pinning counts, hashes, or full derived lists. Removed required entries and unsupported mappings for known concepts
349// should still fail.
350#[cfg(test)]
351mod tests {
352    use super::*;
353
354    #[test]
355    fn concept_all_entries_are_unique() {
356        let mut seen = std::collections::HashSet::new();
357        for c in Concept::ALL {
358            assert!(seen.insert(c.as_str()), "duplicate concept string: {}", c.as_str());
359        }
360    }
361
362    #[test]
363    fn concept_from_name_roundtrip() {
364        for c in Concept::ALL {
365            assert_eq!(Concept::from_name(c.as_str()), Some(*c));
366        }
367        assert_eq!(Concept::from_name("nope.not.a.concept"), None);
368    }
369}