Skip to content

Commit 755a35a

Browse files
committed
MOre stringbuilder
1 parent 4d6e66a commit 755a35a

File tree

2 files changed

+100
-29
lines changed

2 files changed

+100
-29
lines changed

lib/saluki-components/src/common/otlp/traces/transform.rs

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ const DD_NAMESPACED_TO_APM_CONVENTIONS: &[(&str, &str)] = &[
9898
pub fn otel_span_to_dd_span(
9999
otel_span: &OtlpSpan, otel_resource: &Resource, instrumentation_scope: Option<&OtlpInstrumentationScope>,
100100
ignore_missing_fields: bool, compute_top_level_by_span_kind: bool, interner: &GenericMapInterner,
101+
string_builder: &mut StringBuilder<GenericMapInterner>,
101102
) -> DdSpan {
102103
let span_attributes = &otel_span.attributes;
103104
let resource_attributes = &otel_resource.attributes;
@@ -108,6 +109,7 @@ pub fn otel_span_to_dd_span(
108109
ignore_missing_fields,
109110
compute_top_level_by_span_kind,
110111
interner,
112+
string_builder,
111113
);
112114

113115
for (dd_key, apm_key) in DD_NAMESPACED_TO_APM_CONVENTIONS {
@@ -117,7 +119,14 @@ pub fn otel_span_to_dd_span(
117119
}
118120

119121
for attribute in span_attributes {
120-
map_attribute_generic(attribute, &mut meta, &mut metrics, ignore_missing_fields, interner);
122+
map_attribute_generic(
123+
attribute,
124+
&mut meta,
125+
&mut metrics,
126+
ignore_missing_fields,
127+
interner,
128+
string_builder,
129+
);
121130
}
122131

123132
if !otel_span.trace_id.is_empty() {
@@ -214,6 +223,7 @@ pub fn otel_span_to_dd_span(
214223
&mut metrics,
215224
ignore_missing_fields,
216225
interner,
226+
string_builder,
217227
);
218228
}
219229
}
@@ -239,6 +249,7 @@ pub fn otel_span_to_dd_span(
239249
pub fn otel_to_dd_span_minimal(
240250
otel_span: &OtlpSpan, otel_resource: &Resource, _instrumentation_scope: Option<&OtlpInstrumentationScope>,
241251
ignore_missing_fields: bool, compute_top_level_by_span_kind: bool, interner: &GenericMapInterner,
252+
string_builder: &mut StringBuilder<GenericMapInterner>,
242253
) -> (
243254
DdSpan,
244255
FastHashMap<MetaString, MetaString>,
@@ -323,10 +334,22 @@ pub fn otel_to_dd_span_minimal(
323334
service = get_otel_service(span_attributes, resource_attributes, true, interner);
324335
}
325336
if name.is_empty() {
326-
name = get_otel_operation_name_v2(otel_span, span_attributes, resource_attributes, interner);
337+
name = get_otel_operation_name_v2(
338+
otel_span,
339+
span_attributes,
340+
resource_attributes,
341+
interner,
342+
string_builder,
343+
);
327344
}
328345
if resource.is_empty() {
329-
resource = get_otel_resource_v2_truncated(otel_span, span_attributes, resource_attributes, interner);
346+
resource = get_otel_resource_v2_truncated(
347+
otel_span,
348+
span_attributes,
349+
resource_attributes,
350+
interner,
351+
string_builder,
352+
);
330353
// Agent normalizer sets resource = name when resource is empty
331354
// https://github.com/DataDog/datadog-agent/blob/main/pkg/trace/agent/normalizer.go#L245-248
332355
if resource.is_empty() {
@@ -381,7 +404,8 @@ fn get_otel_service(
381404
// GetOTelOperationNameV2 returns the DD operation name based on OTel span and resource attributes and given configs.
382405
// based on code from https://github.com/DataDog/datadog-agent/blob/instrument-otlp-traffic/pkg/trace/traceutil/otel_util.go#L424
383406
fn get_otel_operation_name_v2(
384-
otel_span: &OtlpSpan, span_attributes: &[KeyValue], resource_attributes: &[KeyValue], interner: &GenericMapInterner,
407+
otel_span: &OtlpSpan, span_attributes: &[KeyValue], resource_attributes: &[KeyValue],
408+
interner: &GenericMapInterner, string_builder: &mut StringBuilder<GenericMapInterner>,
385409
) -> MetaString {
386410
if let Some(value) = use_both_maps(span_attributes, resource_attributes, true, OPERATION_NAME_KEY, interner) {
387411
if !value.is_empty() {
@@ -392,7 +416,6 @@ fn get_otel_operation_name_v2(
392416
let span_kind = SpanKind::try_from(otel_span.kind).unwrap_or(SpanKind::Unspecified);
393417
let is_client = matches!(span_kind, SpanKind::Client);
394418
let is_server = matches!(span_kind, SpanKind::Server);
395-
let mut string_builder = StringBuilder::new();
396419

397420
// http
398421
for http_request_method_key in HTTP_REQUEST_METHOD_KEYS {
@@ -573,10 +596,10 @@ fn get_otel_operation_name_v2(
573596
// GetOTelResourceV2 returns the DD resource name based on OTel span and resource attributes.
574597
// based on this code https://github.com/DataDog/datadog-agent/blob/instrument-otlp-traffic/pkg/trace/traceutil/otel_util.go#L348
575598
fn get_otel_resource_v2(
576-
otel_span: &OtlpSpan, span_attributes: &[KeyValue], resource_attributes: &[KeyValue], interner: &GenericMapInterner,
599+
otel_span: &OtlpSpan, span_attributes: &[KeyValue], resource_attributes: &[KeyValue],
600+
interner: &GenericMapInterner, string_builder: &mut StringBuilder<GenericMapInterner>,
577601
) -> MetaString {
578602
let span_kind = SpanKind::try_from(otel_span.kind).unwrap_or(SpanKind::Unspecified);
579-
let mut string_builder = StringBuilder::new();
580603
if let Some(value) = use_both_maps(span_attributes, resource_attributes, true, RESOURCE_NAME_KEY, interner) {
581604
if !value.is_empty() {
582605
return value;
@@ -664,9 +687,16 @@ fn get_otel_resource_v2(
664687
}
665688

666689
fn get_otel_resource_v2_truncated(
667-
otel_span: &OtlpSpan, span_attributes: &[KeyValue], resource_attributes: &[KeyValue], interner: &GenericMapInterner,
690+
otel_span: &OtlpSpan, span_attributes: &[KeyValue], resource_attributes: &[KeyValue],
691+
interner: &GenericMapInterner, string_builder: &mut StringBuilder<GenericMapInterner>,
668692
) -> MetaString {
669-
let res_name = get_otel_resource_v2(otel_span, span_attributes, resource_attributes, interner);
693+
let res_name = get_otel_resource_v2(
694+
otel_span,
695+
span_attributes,
696+
resource_attributes,
697+
interner,
698+
string_builder,
699+
);
670700
if res_name.len() > MAX_RESOURCE_LEN {
671701
MetaString::from(truncate_utf8(&res_name, MAX_RESOURCE_LEN))
672702
} else {
@@ -753,7 +783,7 @@ const SQL_DB_SYSTEMS: &[&str] = &[
753783

754784
fn map_attribute_generic(
755785
attribute: &KeyValue, meta: &mut FastHashMap<MetaString, MetaString>, metrics: &mut FastHashMap<MetaString, f64>,
756-
ignore_missing_fields: bool, interner: &GenericMapInterner,
786+
ignore_missing_fields: bool, interner: &GenericMapInterner, string_builder: &mut StringBuilder<GenericMapInterner>,
757787
) {
758788
if attribute.key.is_empty() {
759789
return;
@@ -772,6 +802,7 @@ fn map_attribute_generic(
772802
metrics,
773803
ignore_missing_fields,
774804
interner,
805+
string_builder,
775806
);
776807
}
777808
OtlpValue::BoolValue(b) => {
@@ -783,6 +814,7 @@ fn map_attribute_generic(
783814
metrics,
784815
ignore_missing_fields,
785816
interner,
817+
string_builder,
786818
);
787819
}
788820
OtlpValue::BytesValue(bytes) => {
@@ -794,6 +826,7 @@ fn map_attribute_generic(
794826
metrics,
795827
ignore_missing_fields,
796828
interner,
829+
string_builder,
797830
);
798831
}
799832
OtlpValue::IntValue(i) => {
@@ -803,6 +836,7 @@ fn map_attribute_generic(
803836
metrics,
804837
ignore_missing_fields,
805838
interner,
839+
string_builder,
806840
);
807841
}
808842
OtlpValue::DoubleValue(d) => {
@@ -812,6 +846,7 @@ fn map_attribute_generic(
812846
metrics,
813847
ignore_missing_fields,
814848
interner,
849+
string_builder,
815850
);
816851
}
817852
_ => {
@@ -1041,9 +1076,9 @@ pub(super) fn otlp_value_to_string(value: &OtlpValue) -> Option<String> {
10411076

10421077
fn conditionally_map_otlp_attribute_to_meta(
10431078
key: &str, value: &str, meta: &mut FastHashMap<MetaString, MetaString>, metrics: &mut FastHashMap<MetaString, f64>,
1044-
ignore_missing_fields: bool, interner: &GenericMapInterner,
1079+
ignore_missing_fields: bool, interner: &GenericMapInterner, string_builder: &mut StringBuilder<GenericMapInterner>,
10451080
) {
1046-
if let Some(mapped_key) = get_dd_key_for_otlp_attribute(key, interner) {
1081+
if let Some(mapped_key) = get_dd_key_for_otlp_attribute(key, interner, string_builder) {
10471082
if meta.contains_key(&mapped_key) {
10481083
return;
10491084
}
@@ -1056,9 +1091,9 @@ fn conditionally_map_otlp_attribute_to_meta(
10561091

10571092
fn conditionally_map_otlp_attribute_to_metric(
10581093
key: &str, value: f64, metrics: &mut FastHashMap<MetaString, f64>, ignore_missing_fields: bool,
1059-
interner: &GenericMapInterner,
1094+
interner: &GenericMapInterner, string_builder: &mut StringBuilder<GenericMapInterner>,
10601095
) {
1061-
if let Some(mapped_key) = get_dd_key_for_otlp_attribute(key, interner) {
1096+
if let Some(mapped_key) = get_dd_key_for_otlp_attribute(key, interner, string_builder) {
10621097
if metrics.contains_key(&mapped_key) {
10631098
return;
10641099
}
@@ -1108,15 +1143,17 @@ fn set_metric_field_otlp_if_empty(key: MetaString, value: f64, metrics: &mut Fas
11081143
// OTLP HTTP convention. Otherwise, check if it is a Datadog APM convention key - if it is, it will be handled with
11091144
// specialized logic elsewhere, so return None. If it isn't, return the original key.
11101145
// based on the logic from the agent code https://github.com/DataDog/datadog-agent/blob/main/pkg/trace/transform/transform.go#L179
1111-
fn get_dd_key_for_otlp_attribute(key: &str, interner: &GenericMapInterner) -> Option<MetaString> {
1146+
fn get_dd_key_for_otlp_attribute(
1147+
key: &str, interner: &GenericMapInterner, string_builder: &mut StringBuilder<GenericMapInterner>,
1148+
) -> Option<MetaString> {
11121149
if let Some(mapped) = HTTP_MAPPINGS.get(key) {
11131150
return Some(MetaString::from_static(mapped));
11141151
}
11151152
if let Some(header_suffix) = key.strip_prefix(HTTP_REQUEST_HEADER_PREFIX) {
1116-
let mut builder = StringBuilder::new();
1117-
let _ = builder.push_str(HTTP_REQUEST_HEADERS_PREFIX);
1118-
let _ = builder.push_str(header_suffix);
1119-
return Some(MetaString::from_interner(builder.as_str(), interner));
1153+
string_builder.clear();
1154+
let _ = string_builder.push_str(HTTP_REQUEST_HEADERS_PREFIX);
1155+
let _ = string_builder.push_str(header_suffix);
1156+
return Some(MetaString::from_interner(string_builder.as_str(), interner));
11201157
}
11211158
if !is_datadog_apm_convention_key(key) {
11221159
return Some(MetaString::from_interner(key, interner));
@@ -1488,27 +1525,56 @@ mod tests {
14881525
let mut meta = FastHashMap::default();
14891526
let mut metrics = FastHashMap::default();
14901527
let interner = test_interner();
1528+
let mut string_builder = StringBuilder::new().with_interner(interner.clone());
14911529

14921530
let http_attr = kv_str("http.request.method", "GET");
1493-
map_attribute_generic(&http_attr, &mut meta, &mut metrics, false, &interner);
1531+
map_attribute_generic(
1532+
&http_attr,
1533+
&mut meta,
1534+
&mut metrics,
1535+
false,
1536+
&interner,
1537+
&mut string_builder,
1538+
);
14941539
assert_eq!(meta.get("http.method").map(|v| v.as_ref()), Some("GET"));
14951540

14961541
let sampling_attr = kv_int("sampling.priority", 2);
1497-
map_attribute_generic(&sampling_attr, &mut meta, &mut metrics, false, &interner);
1542+
map_attribute_generic(
1543+
&sampling_attr,
1544+
&mut meta,
1545+
&mut metrics,
1546+
false,
1547+
&interner,
1548+
&mut string_builder,
1549+
);
14981550
assert_eq!(metrics.get(SAMPLING_PRIORITY_METRIC_KEY), Some(&2.0));
14991551

15001552
let analytics_attr = kv_bool(ANALYTICS_EVENT_KEY, true);
1501-
map_attribute_generic(&analytics_attr, &mut meta, &mut metrics, false, &interner);
1553+
map_attribute_generic(
1554+
&analytics_attr,
1555+
&mut meta,
1556+
&mut metrics,
1557+
false,
1558+
&interner,
1559+
&mut string_builder,
1560+
);
15021561
assert_eq!(metrics.get(EVENT_EXTRACTION_METRIC_KEY), Some(&1.0));
15031562

15041563
let dd_attr = kv_str("datadog.service", "svc");
1505-
map_attribute_generic(&dd_attr, &mut meta, &mut metrics, false, &interner);
1564+
map_attribute_generic(&dd_attr, &mut meta, &mut metrics, false, &interner, &mut string_builder);
15061565
assert!(!meta.contains_key("datadog.service"));
15071566

15081567
let mut meta_ignore = FastHashMap::default();
15091568
let mut metrics_ignore = FastHashMap::default();
15101569
let env_attr = kv_str("env", "prod");
1511-
map_attribute_generic(&env_attr, &mut meta_ignore, &mut metrics_ignore, true, &interner);
1570+
map_attribute_generic(
1571+
&env_attr,
1572+
&mut meta_ignore,
1573+
&mut metrics_ignore,
1574+
true,
1575+
&interner,
1576+
&mut string_builder,
1577+
);
15121578
assert!(meta_ignore.is_empty());
15131579
}
15141580

@@ -1812,6 +1878,7 @@ mod tests {
18121878
];
18131879

18141880
let interner = test_interner();
1881+
let mut string_builder = StringBuilder::new().with_interner(interner.clone());
18151882
for tc in test_cases {
18161883
let span = OtlpSpan {
18171884
name: "test-span".to_string(),
@@ -1823,7 +1890,7 @@ mod tests {
18231890
..Default::default()
18241891
};
18251892

1826-
let dd_span = otel_span_to_dd_span(&span, &resource, None, false, true, &interner);
1893+
let dd_span = otel_span_to_dd_span(&span, &resource, None, false, true, &interner, &mut string_builder);
18271894
let meta = dd_span.meta();
18281895

18291896
if tc.should_map {

lib/saluki-components/src/common/otlp/traces/translator.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,13 @@ impl OtlpTracesTranslator {
6969

7070
pub fn translate_resource_spans(&mut self, resource_spans: ResourceSpans, metrics: &Metrics) -> Vec<Event> {
7171
let resource: OtlpResource = resource_spans.resource.unwrap_or_default();
72-
let resource_tags: TagSet = resource_attributes_to_tagset(&resource.attributes, &mut self.string_builder);
72+
let ignore_missing_fields = self.config.ignore_missing_datadog_fields;
73+
let compute_top_level = self.config.enable_otlp_compute_top_level_by_span_kind;
74+
let interner = &self.interner;
75+
let string_builder = &mut self.string_builder;
76+
let resource_tags: TagSet = resource_attributes_to_tagset(&resource.attributes, string_builder);
7377
let mut traces_by_id: FastHashMap<u64, Vec<DdSpan>> = FastHashMap::default();
7478
let mut priorities_by_id: FastHashMap<u64, i32> = FastHashMap::default();
75-
let ignore_missing_fields = self.config.ignore_missing_datadog_fields;
7679

7780
for scope_spans in resource_spans.scope_spans {
7881
let scope = scope_spans.scope;
@@ -85,8 +88,9 @@ impl OtlpTracesTranslator {
8588
&resource,
8689
scope_ref,
8790
ignore_missing_fields,
88-
self.config.enable_otlp_compute_top_level_by_span_kind,
89-
&self.interner,
91+
compute_top_level,
92+
interner,
93+
string_builder,
9094
);
9195

9296
// Track last-seen priority for this trace (overwrites previous values)

0 commit comments

Comments
 (0)