32
32
//! The code in attribute_keys.rs loops only once and then stores the offsets at which the
33
33
//! attributes are stored, for the set of keys we are interested in.
34
34
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;
38
38
39
39
#[ cfg( test) ]
40
40
mod transform_tests;
41
41
42
- pub use otel_util:: DEFAULT_OTLP_SERVICE_NAME ;
43
-
44
42
use attribute_keys:: * ;
45
43
use otel_util:: * ;
46
44
@@ -53,49 +51,13 @@ use datadog_trace_utils::span::{
53
51
} ;
54
52
use opentelemetry:: {
55
53
trace:: { Link , SpanKind } ,
56
- Key , KeyValue , SpanId ,
54
+ Key , KeyValue , SpanId , Value ,
57
55
} ;
58
56
use opentelemetry_sdk:: Resource ;
59
- use opentelemetry_semantic_conventions as semconv;
57
+ pub use opentelemetry_semantic_conventions as semconv;
60
58
use tinybytes:: BytesString ;
61
59
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 ;
99
61
100
62
fn set_meta_otlp ( k : BytesString , v : BytesString , dd_span : & mut DdSpan ) {
101
63
match k. as_str ( ) {
@@ -125,10 +87,10 @@ fn set_meta_otlp_with_semconv_mappings(
125
87
dd_span : & mut DdSpan ,
126
88
) {
127
89
let mapped_key = get_dd_key_for_otlp_attribute ( k) ;
128
- if mapped_key. is_empty ( ) {
90
+ if mapped_key. as_str ( ) . is_empty ( ) {
129
91
return ;
130
92
}
131
- let mapped_key = BytesString :: from_cow ( mapped_key) ;
93
+ let mapped_key = BytesString :: from_cow ( mapped_key. into_static_cow ( ) ) ;
132
94
if is_meta_key ( mapped_key. as_ref ( ) )
133
95
&& !dd_span
134
96
. meta
@@ -159,7 +121,7 @@ fn set_metric_otlp(s: &mut DdSpan, k: BytesString, v: f64) {
159
121
160
122
fn set_metric_otlp_with_semconv_mappings ( k : & str , value : f64 , dd_span : & mut DdSpan ) {
161
123
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 ( ) ) ;
163
125
164
126
if !mapped_key. is_empty ( ) {
165
127
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
170
132
}
171
133
172
134
/// 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 {
178
136
let ( trace_id_lower_half, _) = otel_trace_id_to_dd_id ( span. span . span_context . trace_id ( ) ) ;
179
137
let span_id = otel_span_id_to_dd_id ( span. span . span_context . span_id ( ) ) ;
180
138
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(
221
179
}
222
180
223
181
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 ) ) ;
225
183
}
226
184
227
185
if dd_span. name . is_empty ( ) {
228
186
dd_span. name = BytesString :: from_cow ( get_otel_operation_name_v2 ( span) ) ;
229
187
}
230
188
231
189
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) ) ;
233
191
}
234
192
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) ) ;
236
194
}
237
195
let code: u32 = if let Some ( http_status_code) = span. get_attr_num ( DATADOG_HTTP_STATUS_CODE ) {
238
196
http_status_code
@@ -438,6 +396,58 @@ fn is_meta_key(key: &str) -> bool {
438
396
)
439
397
}
440
398
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
+
441
451
/// Converts an OpenTelemetry span to a Datadog span.
442
452
/// https://github.com/DataDog/datadog-agent/blob/d91c1b47da4f5f24559f49be284e547cc847d5e2/pkg/trace/transform/transform.go#L236
443
453
///
@@ -448,7 +458,7 @@ fn is_meta_key(key: &str) -> bool {
448
458
/// * `enable_otlp_compute_top_level_by_span_kind` => default to true
449
459
/// * `IgnoreMissingDatadogFields` => default to false
450
460
/// * `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 {
452
462
// There is a performance otpimization possible here:
453
463
// The otlp receiver splits span conversion into two steps
454
464
// 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) ->
457
467
// If we use CSS we could probably do only 1. if we know the span is going to be dropped before
458
468
// being sent...
459
469
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) ;
465
471
let is_top_level = otel_span. parent_span_id == SpanId :: INVALID
466
472
|| matches ! ( otel_span. span_kind, SpanKind :: Server | SpanKind :: Consumer ) ;
467
473
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) ;
469
475
470
476
for ( dd_semantics_key, meta_key) in DD_SEMANTICS_KEY_TO_META_KEY {
471
477
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) ->
526
532
}
527
533
528
534
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 ) ;
530
536
if !env. is_empty ( ) {
531
537
env_slot. insert ( BytesString :: from_cow ( env) ) ;
532
538
}
0 commit comments