3232//! The code in attribute_keys.rs loops only once and then stores the offsets at which the
3333//! attributes are stored, for the set of keys we are interested in.
3434
35- mod attribute_keys;
36- mod otel_util;
37- mod semconv_shim;
35+ pub mod attribute_keys;
36+ pub mod otel_util;
37+ pub mod semconv_shim;
3838
3939#[ cfg( test) ]
4040mod transform_tests;
4141
42- pub use otel_util:: DEFAULT_OTLP_SERVICE_NAME ;
43-
4442use attribute_keys:: * ;
4543use otel_util:: * ;
4644
@@ -53,49 +51,13 @@ use datadog_trace_utils::span::{
5351} ;
5452use opentelemetry:: {
5553 trace:: { Link , SpanKind } ,
56- Key , KeyValue , SpanId ,
54+ Key , KeyValue , SpanId , Value ,
5755} ;
5856use opentelemetry_sdk:: Resource ;
59- use opentelemetry_semantic_conventions as semconv;
57+ pub use opentelemetry_semantic_conventions as semconv;
6058use tinybytes:: BytesString ;
6159
62- use crate :: ddtrace_transform:: ExportSpan ;
63-
64- struct SpanExtractArgs < ' a > {
65- span : & ' a ExportSpan ,
66- span_attrs : AttributeIndices ,
67- }
68-
69- impl OtelSpan for SpanExtractArgs < ' _ > {
70- fn name ( & self ) -> Cow < ' static , str > {
71- self . span . name . clone ( )
72- }
73-
74- fn span_kind ( & self ) -> SpanKind {
75- self . span . span_kind . clone ( )
76- }
77-
78- fn has_attr ( & self , attr_key : AttributeKey ) -> bool {
79- self . span_attrs . get ( attr_key) . is_some ( )
80- }
81-
82- fn get_attr_str_opt ( & self , attr_key : AttributeKey ) -> Option < Cow < ' static , str > > {
83- let idx = self . span_attrs . get ( attr_key) ?;
84- let kv = self . span . attributes . get ( idx) ?;
85- Some ( Cow :: Owned ( kv. value . to_string ( ) ) )
86- }
87-
88- fn get_attr_num < T : TryFrom < i64 > > ( & self , attr_key : AttributeKey ) -> Option < T > {
89- let idx = self . span_attrs . get ( attr_key) ?;
90- let kv = self . span . attributes . get ( idx) ?;
91- let i = match kv. value {
92- opentelemetry:: Value :: I64 ( i) => i,
93- opentelemetry:: Value :: F64 ( i) if i == i. floor ( ) && i < i64:: MAX as f64 => i as i64 ,
94- _ => return None ,
95- } ;
96- T :: try_from ( i) . ok ( )
97- }
98- }
60+ use crate :: sdk_span:: SdkSpan ;
9961
10062fn set_meta_otlp ( k : BytesString , v : BytesString , dd_span : & mut DdSpan ) {
10163 match k. as_str ( ) {
@@ -125,10 +87,10 @@ fn set_meta_otlp_with_semconv_mappings(
12587 dd_span : & mut DdSpan ,
12688) {
12789 let mapped_key = get_dd_key_for_otlp_attribute ( k) ;
128- if mapped_key. is_empty ( ) {
90+ if mapped_key. as_str ( ) . is_empty ( ) {
12991 return ;
13092 }
131- let mapped_key = BytesString :: from_cow ( mapped_key) ;
93+ let mapped_key = BytesString :: from_cow ( mapped_key. into_static_cow ( ) ) ;
13294 if is_meta_key ( mapped_key. as_ref ( ) )
13395 && !dd_span
13496 . meta
@@ -159,7 +121,7 @@ fn set_metric_otlp(s: &mut DdSpan, k: BytesString, v: f64) {
159121
160122fn set_metric_otlp_with_semconv_mappings ( k : & str , value : f64 , dd_span : & mut DdSpan ) {
161123 let mapped_key = get_dd_key_for_otlp_attribute ( k) ;
162- let mapped_key = BytesString :: from_cow ( mapped_key) ;
124+ let mapped_key = BytesString :: from_cow ( mapped_key. into_static_cow ( ) ) ;
163125
164126 if !mapped_key. is_empty ( ) {
165127 if is_meta_key ( mapped_key. as_str ( ) ) && dd_span. metrics . contains_key ( & mapped_key) {
@@ -170,11 +132,7 @@ fn set_metric_otlp_with_semconv_mappings(k: &str, value: f64, dd_span: &mut DdSp
170132}
171133
172134/// https://github.com/DataDog/datadog-agent/blob/main/pkg/trace/transform/transform.go#L69
173- fn otel_span_to_dd_span_minimal (
174- span : & SpanExtractArgs ,
175- res : & Resource ,
176- is_top_level : bool ,
177- ) -> DdSpan {
135+ fn otel_span_to_dd_span_minimal ( span : & SpanExtractArgs , is_top_level : bool ) -> DdSpan {
178136 let ( trace_id_lower_half, _) = otel_trace_id_to_dd_id ( span. span . span_context . trace_id ( ) ) ;
179137 let span_id = otel_span_id_to_dd_id ( span. span . span_context . span_id ( ) ) ;
180138 let parent_id = otel_span_id_to_dd_id ( span. span . parent_span_id ) ;
@@ -221,18 +179,18 @@ fn otel_span_to_dd_span_minimal(
221179 }
222180
223181 if dd_span. service . is_empty ( ) {
224- dd_span. service = BytesString :: from_cow ( get_otel_service ( res ) ) ;
182+ dd_span. service = BytesString :: from_cow ( get_otel_service ( span ) ) ;
225183 }
226184
227185 if dd_span. name . is_empty ( ) {
228186 dd_span. name = BytesString :: from_cow ( get_otel_operation_name_v2 ( span) ) ;
229187 }
230188
231189 if dd_span. resource . is_empty ( ) {
232- dd_span. resource = BytesString :: from_cow ( get_otel_resource_v2 ( span, res ) ) ;
190+ dd_span. resource = BytesString :: from_cow ( get_otel_resource_v2 ( span) ) ;
233191 }
234192 if dd_span. r#type . is_empty ( ) {
235- dd_span. r#type = BytesString :: from_cow ( get_otel_span_type ( span, res ) ) ;
193+ dd_span. r#type = BytesString :: from_cow ( get_otel_span_type ( span) ) ;
236194 }
237195 let code: u32 = if let Some ( http_status_code) = span. get_attr_num ( DATADOG_HTTP_STATUS_CODE ) {
238196 http_status_code
@@ -438,6 +396,58 @@ fn is_meta_key(key: &str) -> bool {
438396 )
439397}
440398
399+ struct SpanExtractArgs < ' a > {
400+ span : & ' a SdkSpan ,
401+ resource : & ' a Resource ,
402+ span_attrs : AttributeIndices ,
403+ }
404+
405+ impl < ' a > SpanExtractArgs < ' a > {
406+ pub fn new ( span : & ' a SdkSpan , resource : & ' a Resource ) -> Self {
407+ let span_attrs = AttributeIndices :: from_attribute_slice ( & span. attributes ) ;
408+ Self {
409+ span,
410+ span_attrs,
411+ resource,
412+ }
413+ }
414+ }
415+
416+ impl OtelSpan for SpanExtractArgs < ' _ > {
417+ fn name ( & self ) -> Cow < ' static , str > {
418+ self . span . name . clone ( )
419+ }
420+
421+ fn span_kind ( & self ) -> SpanKind {
422+ self . span . span_kind . clone ( )
423+ }
424+
425+ fn has_attr ( & self , attr_key : AttributeKey ) -> bool {
426+ self . span_attrs . get ( attr_key) . is_some ( )
427+ }
428+
429+ fn get_attr_str_opt ( & self , attr_key : AttributeKey ) -> Option < Cow < ' static , str > > {
430+ let idx = self . span_attrs . get ( attr_key) ?;
431+ let kv = self . span . attributes . get ( idx) ?;
432+ Some ( Cow :: Owned ( kv. value . to_string ( ) ) )
433+ }
434+
435+ fn get_attr_num < T : TryFrom < i64 > > ( & self , attr_key : AttributeKey ) -> Option < T > {
436+ let idx = self . span_attrs . get ( attr_key) ?;
437+ let kv = self . span . attributes . get ( idx) ?;
438+ let i = match kv. value {
439+ opentelemetry:: Value :: I64 ( i) => i,
440+ opentelemetry:: Value :: F64 ( i) if i == i. floor ( ) && i < i64:: MAX as f64 => i as i64 ,
441+ _ => return None ,
442+ } ;
443+ T :: try_from ( i) . ok ( )
444+ }
445+
446+ fn get_res_attribute_opt ( & self , attr_key : AttributeKey ) -> Option < Value > {
447+ self . resource . get ( & Key :: from_static_str ( attr_key. key ( ) ) )
448+ }
449+ }
450+
441451/// Converts an OpenTelemetry span to a Datadog span.
442452/// https://github.com/DataDog/datadog-agent/blob/d91c1b47da4f5f24559f49be284e547cc847d5e2/pkg/trace/transform/transform.go#L236
443453///
@@ -448,7 +458,7 @@ fn is_meta_key(key: &str) -> bool {
448458/// * `enable_otlp_compute_top_level_by_span_kind` => default to true
449459/// * `IgnoreMissingDatadogFields` => default to false
450460/// * `disable_operation_and_resource_name_logic_v2` => default to false
451- pub fn otel_span_to_dd_span ( otel_span : ExportSpan , otel_resource : & Resource ) -> DdSpan {
461+ pub fn otel_span_to_dd_span ( otel_span : SdkSpan , otel_resource : & Resource ) -> DdSpan {
452462 // There is a performance otpimization possible here:
453463 // The otlp receiver splits span conversion into two steps
454464 // 1. The minimal fields used by Stats computation
@@ -457,15 +467,11 @@ pub fn otel_span_to_dd_span(otel_span: ExportSpan, otel_resource: &Resource) ->
457467 // If we use CSS we could probably do only 1. if we know the span is going to be dropped before
458468 // being sent...
459469
460- let span_attrs = AttributeIndices :: from_attribute_slice ( & otel_span. attributes ) ;
461- let span_extracted = SpanExtractArgs {
462- span : & otel_span,
463- span_attrs,
464- } ;
470+ let span_extracted = SpanExtractArgs :: new ( & otel_span, otel_resource) ;
465471 let is_top_level = otel_span. parent_span_id == SpanId :: INVALID
466472 || matches ! ( otel_span. span_kind, SpanKind :: Server | SpanKind :: Consumer ) ;
467473
468- let mut dd_span = otel_span_to_dd_span_minimal ( & span_extracted, otel_resource , is_top_level) ;
474+ let mut dd_span = otel_span_to_dd_span_minimal ( & span_extracted, is_top_level) ;
469475
470476 for ( dd_semantics_key, meta_key) in DD_SEMANTICS_KEY_TO_META_KEY {
471477 let value = span_extracted. get_attr_str ( * dd_semantics_key) ;
@@ -526,7 +532,7 @@ pub fn otel_span_to_dd_span(otel_span: ExportSpan, otel_resource: &Resource) ->
526532 }
527533
528534 if let hash_map:: Entry :: Vacant ( env_slot) = dd_span. meta . entry ( BytesString :: from_static ( "env" ) ) {
529- let env = get_otel_env ( otel_resource ) ;
535+ let env = get_otel_env ( & span_extracted ) ;
530536 if !env. is_empty ( ) {
531537 env_slot. insert ( BytesString :: from_cow ( env) ) ;
532538 }
0 commit comments