Skip to content

Commit 0861c5a

Browse files
authored
[forwarder][lambda]: don't fail to parse on managed instances report log (#1041)
* skip logs where keys dont exist * update comment * lint
1 parent d9b9f9d commit 0861c5a

File tree

2 files changed

+59
-12
lines changed

2 files changed

+59
-12
lines changed

aws/logs_monitoring/enhanced_lambda_metrics.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,9 @@ def parse_metrics_from_json_report_log(log_message):
289289
metrics = []
290290

291291
for record_key, metric_name in RUNTIME_METRICS_BY_RECORD_KEY.items():
292-
metric_point_value = record_metrics[record_key]
292+
metric_point_value = record_metrics.get(record_key)
293+
if metric_point_value is None:
294+
continue
293295

294296
if metric_name in METRIC_ADJUSTMENT_FACTORS:
295297
metric_point_value *= METRIC_ADJUSTMENT_FACTORS[metric_name]
@@ -301,9 +303,10 @@ def parse_metrics_from_json_report_log(log_message):
301303
)
302304
)
303305

304-
tags = [
305-
f"{MEMORY_ALLOCATED_FIELD_NAME}:{record_metrics[MEMORY_ALLOCATED_RECORD_KEY]}"
306-
]
306+
tags = []
307+
memory_allocated = record_metrics.get(MEMORY_ALLOCATED_RECORD_KEY)
308+
if memory_allocated is not None:
309+
tags.append(f"{MEMORY_ALLOCATED_FIELD_NAME}:{memory_allocated}")
307310

308311
init_duration = record_metrics.get(INIT_DURATION_RECORD_KEY)
309312
if init_duration:
@@ -317,15 +320,19 @@ def parse_metrics_from_json_report_log(log_message):
317320
else:
318321
tags.append("cold_start:false")
319322

320-
metrics.append(
321-
DatadogMetricPoint(
322-
f"{ENHANCED_METRICS_NAMESPACE_PREFIX}.{ESTIMATED_COST_METRIC_NAME}",
323-
calculate_estimated_cost(
324-
record_metrics[BILLED_DURATION_RECORD_KEY],
325-
record_metrics[MEMORY_ALLOCATED_RECORD_KEY],
326-
),
323+
# Billed duration only available for On-Demand Lambda functions,
324+
# for Managed Instances, this is no longer available.
325+
billed_duration = record_metrics.get(BILLED_DURATION_RECORD_KEY)
326+
if billed_duration is not None and memory_allocated is not None:
327+
metrics.append(
328+
DatadogMetricPoint(
329+
f"{ENHANCED_METRICS_NAMESPACE_PREFIX}.{ESTIMATED_COST_METRIC_NAME}",
330+
calculate_estimated_cost(
331+
billed_duration,
332+
memory_allocated,
333+
),
334+
)
327335
)
328-
)
329336

330337
if record.get("status") == "timeout":
331338
metrics.append(

aws/logs_monitoring/tests/test_enhanced_lambda_metrics.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,31 @@ class TestEnhancedLambdaMetrics(unittest.TestCase):
8686
},
8787
}
8888
)
89+
managed_instances_metrics_json_report = json.dumps(
90+
{
91+
"time": "2026-01-08T18:22:35.343Z",
92+
"type": "platform.report",
93+
"record": {
94+
"requestId": "4f423807-598d-47ae-9652-4f7ee31d4d10",
95+
"metrics": {
96+
"durationMs": 2.524,
97+
},
98+
"spans": [
99+
{
100+
"name": "responseLatency",
101+
"start": "2026-01-08T18:22:35.342Z",
102+
"durationMs": 0.642,
103+
},
104+
{
105+
"name": "responseDuration",
106+
"start": "2026-01-08T18:22:35.343Z",
107+
"durationMs": 0.075,
108+
},
109+
],
110+
"status": "success",
111+
},
112+
}
113+
)
89114

90115
def test_parse_lambda_tags_from_arn(self):
91116
verify_as_json(
@@ -129,6 +154,21 @@ def test_parse_metrics_from_timeout_json_report_log(self):
129154
parsed_metrics = parse_metrics_from_json_report_log(self.timeout_json_report)
130155
verify_as_json(parsed_metrics)
131156

157+
def test_parse_metrics_from_partial_metrics_json_report_log(self):
158+
"""Test that JSON report logs with partial/incomplete metrics don't raise KeyError"""
159+
parsed_metrics = parse_metrics_from_json_report_log(
160+
self.managed_instances_metrics_json_report
161+
)
162+
# Should only return metrics that are present (duration in this case)
163+
# Should not raise KeyError for missing billedDurationMs, maxMemoryUsedMB, memorySizeMB
164+
assert len(parsed_metrics) == 1 # Only duration metric
165+
assert parsed_metrics[0].name == "aws.lambda.enhanced.duration"
166+
# Duration should be converted from ms to seconds (2.524 * 0.001 = 0.002524)
167+
assert parsed_metrics[0].value == 0.002524
168+
# Tags should include cold_start:false but NOT memorysize since it's missing
169+
assert "cold_start:false" in parsed_metrics[0].tags
170+
assert not any(tag.startswith("memorysize:") for tag in parsed_metrics[0].tags)
171+
132172
def test_create_out_of_memory_enhanced_metric(self):
133173
go_out_of_memory_error = "fatal error: runtime: out of memory"
134174
self.assertEqual(

0 commit comments

Comments
 (0)