Skip to content

Commit 3aaaae2

Browse files
feat: add attributes to payload log records (#37)
1 parent e06e419 commit 3aaaae2

7 files changed

Lines changed: 68 additions & 9 deletions

File tree

integration-tests/tests/src/test-node-success.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
4141
{ message: "Handler invoked with event:" },
4242
{ message: "let's parse this as a warning", severity: "warn" },
4343
{ message: 'END RequestId: ' },
44-
{ message: JSON.stringify({ name: "dash0_payload", type: "lambda_event", message: { parameter1: "right", masked_field: "****" } }), isJson: true },
45-
{ message: JSON.stringify({ name: "dash0_payload", type: "lambda_return_value", message: { statusCode: 200 } }), isJson: true },
44+
{ message: JSON.stringify({ name: "dash0_payload", type: "lambda_event", message: { parameter1: "right", masked_field: "****" } }), isJson: true, attributes: { "dash0.faas.payload_type": "lambda_event" } },
45+
{ message: JSON.stringify({ name: "dash0_payload", type: "lambda_return_value", message: { statusCode: 200 } }), isJson: true, attributes: { "dash0.faas.payload_type": "lambda_return_value" } },
4646
]
4747
if (traced) {
4848
logsToBeChecked.push(
49-
{ message: JSON.stringify({ name: "dash0_payload", type: "http_request_body", message: { title: "foo", body: "bar", userId: 1 } }), isJson: true, spanId: httpSpanId },
50-
{ message: JSON.stringify({ name: "dash0_payload", type: "http_response_body" }), isJson: true, spanId: httpSpanId },
49+
{ message: JSON.stringify({ name: "dash0_payload", type: "http_request_body", message: { title: "foo", body: "bar", userId: 1 } }), isJson: true, spanId: httpSpanId, attributes: { "dash0.faas.payload_type": "http_request_body" } },
50+
{ message: JSON.stringify({ name: "dash0_payload", type: "http_response_body" }), isJson: true, spanId: httpSpanId, attributes: { "dash0.faas.payload_type": "http_response_body" } },
5151
);
5252
}
5353
if (!invocationEnd) {

integration-tests/tests/src/test-python-success.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ const verifySuccessInvocation = async (functionName: string, invocationEnd: bool
3838
{ message: 'START RequestId: ' },
3939
{ message: 'END RequestId: ' },
4040
{ message: "response.status_code:" },
41-
{ message: JSON.stringify({ name: "dash0_payload", type: "lambda_event", message: { parameter1: "right" } }), isJson: true },
42-
{ message: JSON.stringify({ name: "dash0_payload", type: "lambda_return_value", message: { statusCode: 200, body: '"Hello from Lambda!"' } }), isJson: true },
41+
{ message: JSON.stringify({ name: "dash0_payload", type: "lambda_event", message: { parameter1: "right" } }), isJson: true, attributes: { "dash0.faas.payload_type": "lambda_event" } },
42+
{ message: JSON.stringify({ name: "dash0_payload", type: "lambda_return_value", message: { statusCode: 200, body: '"Hello from Lambda!"' } }), isJson: true, attributes: { "dash0.faas.payload_type": "lambda_return_value" } },
4343
]
4444
if (traced) {
4545
logsToBeChecked.push(
46-
{ message: JSON.stringify({ name: "dash0_payload", type: "http_request_body", message: { title: "foo", userId: 1 } }), isJson: true, spanId: httpSpanId },
47-
{ message: JSON.stringify({ name: "dash0_payload", type: "http_response_body" }), isJson: true, spanId: httpSpanId },
46+
{ message: JSON.stringify({ name: "dash0_payload", type: "http_request_body", message: { title: "foo", userId: 1 } }), isJson: true, spanId: httpSpanId, attributes: { "dash0.faas.payload_type": "http_request_body" } },
47+
{ message: JSON.stringify({ name: "dash0_payload", type: "http_response_body" }), isJson: true, spanId: httpSpanId, attributes: { "dash0.faas.payload_type": "http_response_body" } },
4848
);
4949
}
5050
if (!invocationEnd) {

integration-tests/tests/src/utils.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {expect, it} from "vitest";
44
import {DASH0_ENDPOINT, DASH0_LAMBDA_TESTS_DATASET, DASH0_TOKEN, MAX_ATTEMPTS, RETRY_DELAY_MS} from "./config";
55
import {InvokeCommand, LambdaClient} from "@aws-sdk/client-lambda";
66

7-
export type LogToCheck = { message: string; severity?: string; isJson?: boolean; spanId?: string };
7+
export type LogToCheck = { message: string; severity?: string; isJson?: boolean; spanId?: string; attributes?: Record<string, string> };
88

99
export const RESOURCE_PREFIX = process.env.RESOURCE_PREFIX ?? '';
1010

@@ -201,6 +201,7 @@ export const checkLogs = async ({
201201
let hasJsonMatch = false;
202202
let jsonSeverity: string | null = null;
203203
let matchedSpanId: string | null = null;
204+
let matchedCheck: LogToCheck | null = null;
204205
let matched = false;
205206
for (const logToCheck of logsToBeChecked) {
206207
if (logToCheck.isJson) {
@@ -216,6 +217,7 @@ export const checkLogs = async ({
216217
}
217218
if (matched) {
218219
logsToBeCheckedCount[logToCheck.message] = true;
220+
matchedCheck = logToCheck;
219221
if (logToCheck.spanId) {
220222
matchedSpanId = logToCheck.spanId;
221223
}
@@ -253,6 +255,14 @@ export const checkLogs = async ({
253255
expectedSeverity = jsonSeverity ?? "info";
254256
}
255257
expect(logRecord.severityText.toLowerCase(), `Wrong severity: ${JSON.stringify(logRecord)}`).toEqual(expectedSeverity);
258+
259+
// Verify custom attributes if specified
260+
if (matchedCheck?.attributes) {
261+
const logAttrs = getAttributesMap(logRecord.attributes);
262+
for (const [key, value] of Object.entries(matchedCheck.attributes)) {
263+
expect(logAttrs[key]?.stringValue, `Missing or wrong attribute '${key}' on log: ${JSON.stringify(logRecord)}`).toEqual(value);
264+
}
265+
}
256266
}
257267
for (const logToCheck of logsToBeChecked) {
258268
expect(logsToBeCheckedCount[logToCheck.message], `Log not found: ${logToCheck.message}`).toBeTruthy();

src/otlp/log_mutations.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ pub fn build_payload_log(
169169
invocation_id: Some(invocation_id.to_string()),
170170
trace_id,
171171
span_id,
172+
custom_attributes: vec![(
173+
"dash0.faas.payload_type".to_string(),
174+
payload_type.to_string(),
175+
)],
172176
})
173177
}
174178

@@ -264,6 +268,19 @@ pub fn map_logs_to_otlp(logs: &[TelemetryLog]) -> Vec<LogRecord> {
264268
}
265269
}
266270

271+
for (key, value) in &log.custom_attributes {
272+
attributes.push(opentelemetry_proto::tonic::common::v1::KeyValue {
273+
key: key.clone(),
274+
value: Some(AnyValue {
275+
value: Some(
276+
opentelemetry_proto::tonic::common::v1::any_value::Value::StringValue(
277+
value.clone(),
278+
),
279+
),
280+
}),
281+
});
282+
}
283+
267284
let severity = if is_platform_log {
268285
"INFO"
269286
} else {
@@ -398,6 +415,7 @@ mod tests {
398415
invocation_id: Some("inv-123".to_string()),
399416
trace_id: None,
400417
span_id: None,
418+
custom_attributes: vec![],
401419
}];
402420

403421
let result = map_logs_to_otlp(&logs);
@@ -429,6 +447,7 @@ mod tests {
429447
invocation_id: Some("inv-123".to_string()),
430448
trace_id: None,
431449
span_id: None,
450+
custom_attributes: vec![],
432451
}];
433452

434453
let result = map_logs_to_otlp(&logs);
@@ -444,6 +463,7 @@ mod tests {
444463
invocation_id: Some("inv-123".to_string()),
445464
trace_id: None,
446465
span_id: None,
466+
custom_attributes: vec![],
447467
}];
448468

449469
let result = map_logs_to_otlp(&logs);
@@ -459,6 +479,7 @@ mod tests {
459479
invocation_id: Some("inv-123".to_string()),
460480
trace_id: None,
461481
span_id: None,
482+
custom_attributes: vec![],
462483
}];
463484

464485
let result = map_logs_to_otlp(&logs);
@@ -475,6 +496,7 @@ mod tests {
475496
invocation_id: None,
476497
trace_id: None,
477498
span_id: None,
499+
custom_attributes: vec![],
478500
}];
479501

480502
let result = map_logs_to_otlp(&logs);
@@ -492,6 +514,7 @@ mod tests {
492514
invocation_id: Some("1".to_string()),
493515
trace_id: None,
494516
span_id: None,
517+
custom_attributes: vec![],
495518
},
496519
TelemetryLog {
497520
time: "2023-10-26T12:00:01.000Z".to_string(),
@@ -500,6 +523,7 @@ mod tests {
500523
invocation_id: Some("2".to_string()),
501524
trace_id: None,
502525
span_id: None,
526+
custom_attributes: vec![],
503527
},
504528
TelemetryLog {
505529
time: "2023-10-26T12:00:02.000Z".to_string(),
@@ -508,6 +532,7 @@ mod tests {
508532
invocation_id: Some("3".to_string()),
509533
trace_id: None,
510534
span_id: None,
535+
custom_attributes: vec![],
511536
},
512537
];
513538

@@ -618,6 +643,7 @@ mod tests {
618643
invocation_id: Some(invocation_id.to_string()),
619644
trace_id: None,
620645
span_id: None,
646+
custom_attributes: vec![],
621647
}];
622648

623649
let result = map_logs_to_otlp(&logs);
@@ -652,6 +678,7 @@ mod tests {
652678
invocation_id: Some("inv-report-1".to_string()),
653679
trace_id: None,
654680
span_id: None,
681+
custom_attributes: vec![],
655682
}];
656683

657684
let result = map_logs_to_otlp(&logs);
@@ -693,6 +720,7 @@ mod tests {
693720
invocation_id: Some("inv-report-2".to_string()),
694721
trace_id: None,
695722
span_id: None,
723+
custom_attributes: vec![],
696724
}];
697725

698726
let result = map_logs_to_otlp(&logs);
@@ -731,6 +759,7 @@ mod tests {
731759
invocation_id: Some("inv-timeout-1".to_string()),
732760
trace_id: None,
733761
span_id: None,
762+
custom_attributes: vec![],
734763
}];
735764

736765
let result = map_logs_to_otlp(&logs);
@@ -779,6 +808,7 @@ mod tests {
779808
invocation_id: Some("inv-success-1".to_string()),
780809
trace_id: None,
781810
span_id: None,
811+
custom_attributes: vec![],
782812
}];
783813

784814
let result = map_logs_to_otlp(&logs);
@@ -819,6 +849,7 @@ mod tests {
819849
invocation_id: Some("inv-error-1".to_string()),
820850
trace_id: None,
821851
span_id: None,
852+
custom_attributes: vec![],
822853
}];
823854

824855
let result = map_logs_to_otlp(&logs);
@@ -846,6 +877,7 @@ mod tests {
846877
invocation_id: Some("inv-123".to_string()),
847878
trace_id: None,
848879
span_id: None,
880+
custom_attributes: vec![],
849881
},
850882
TelemetryLog {
851883
time: "2025-12-07T12:09:10.254Z".to_string(),
@@ -863,6 +895,7 @@ mod tests {
863895
invocation_id: Some("inv-123".to_string()),
864896
trace_id: None,
865897
span_id: None,
898+
custom_attributes: vec![],
866899
},
867900
];
868901

@@ -894,6 +927,7 @@ mod tests {
894927
invocation_id: Some("inv-start-1".to_string()),
895928
trace_id: None,
896929
span_id: None,
930+
custom_attributes: vec![],
897931
}];
898932

899933
let result = map_logs_to_otlp(&logs);
@@ -937,6 +971,7 @@ mod tests {
937971
invocation_id: Some("inv-end-1".to_string()),
938972
trace_id: None,
939973
span_id: None,
974+
custom_attributes: vec![],
940975
}];
941976

942977
let result = map_logs_to_otlp(&logs);
@@ -969,6 +1004,7 @@ mod tests {
9691004
invocation_id: Some("test-lifecycle".to_string()),
9701005
trace_id: None,
9711006
span_id: None,
1007+
custom_attributes: vec![],
9721008
},
9731009
TelemetryLog {
9741010
time: "2025-12-07T12:09:07.000Z".to_string(),
@@ -977,6 +1013,7 @@ mod tests {
9771013
invocation_id: Some("test-lifecycle".to_string()),
9781014
trace_id: None,
9791015
span_id: None,
1016+
custom_attributes: vec![],
9801017
},
9811018
TelemetryLog {
9821019
time: "2025-12-07T12:09:10.252Z".to_string(),
@@ -988,6 +1025,7 @@ mod tests {
9881025
invocation_id: Some("test-lifecycle".to_string()),
9891026
trace_id: None,
9901027
span_id: None,
1028+
custom_attributes: vec![],
9911029
},
9921030
TelemetryLog {
9931031
time: "2025-12-07T12:09:10.254Z".to_string(),
@@ -1004,6 +1042,7 @@ mod tests {
10041042
invocation_id: Some("test-lifecycle".to_string()),
10051043
trace_id: None,
10061044
span_id: None,
1045+
custom_attributes: vec![],
10071046
},
10081047
];
10091048

@@ -1043,6 +1082,7 @@ mod tests {
10431082
invocation_id: Some("test-severity".to_string()),
10441083
trace_id: None,
10451084
span_id: None,
1085+
custom_attributes: vec![],
10461086
},
10471087
TelemetryLog {
10481088
time: "2025-12-07T12:09:07.000Z".to_string(),
@@ -1051,6 +1091,7 @@ mod tests {
10511091
invocation_id: Some("test-severity".to_string()),
10521092
trace_id: None,
10531093
span_id: None,
1094+
custom_attributes: vec![],
10541095
},
10551096
TelemetryLog {
10561097
time: "2025-12-07T12:09:10.252Z".to_string(),
@@ -1062,6 +1103,7 @@ mod tests {
10621103
invocation_id: Some("test-severity".to_string()),
10631104
trace_id: None,
10641105
span_id: None,
1106+
custom_attributes: vec![],
10651107
},
10661108
TelemetryLog {
10671109
time: "2025-12-07T12:09:10.254Z".to_string(),
@@ -1078,6 +1120,7 @@ mod tests {
10781120
invocation_id: Some("test-severity".to_string()),
10791121
trace_id: None,
10801122
span_id: None,
1123+
custom_attributes: vec![],
10811124
},
10821125
];
10831126

@@ -1176,6 +1219,7 @@ mod tests {
11761219
invocation_id: Some("inv-sev-1".to_string()),
11771220
trace_id: None,
11781221
span_id: None,
1222+
custom_attributes: vec![],
11791223
}];
11801224

11811225
let result = map_logs_to_otlp(&logs);
@@ -1193,6 +1237,7 @@ mod tests {
11931237
invocation_id: Some("inv-sev-2".to_string()),
11941238
trace_id: None,
11951239
span_id: None,
1240+
custom_attributes: vec![],
11961241
}];
11971242

11981243
let result = map_logs_to_otlp(&logs);

src/state/invocation_data.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ pub struct TelemetryLog {
8888
pub trace_id: Option<String>,
8989
#[serde(skip_deserializing)]
9090
pub span_id: Option<String>,
91+
#[serde(skip_deserializing)]
92+
pub custom_attributes: Vec<(String, String)>,
9193
}
9294

9395
pub fn store_runtime_done_notifier(sender: tokio::sync::oneshot::Sender<()>) {

src/state/invocation_entry.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ mod tests {
355355
invocation_id: invocation_id.map(String::from),
356356
trace_id: None,
357357
span_id: None,
358+
custom_attributes: vec![],
358359
}
359360
}
360361

src/util/log_processing.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ mod tests {
180180
invocation_id,
181181
trace_id: None,
182182
span_id: None,
183+
custom_attributes: vec![],
183184
}
184185
}
185186

0 commit comments

Comments
 (0)