Skip to content
7 changes: 6 additions & 1 deletion bottlecap/src/bin/bottlecap/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,12 @@ async fn extension_loop_active(
match event {
Event::Metric(event) => {
debug!("Metric event: {:?}", event);
}
},
Event::OutOfMemory => {
let mut p = invocation_processor.lock().await;
p.on_out_of_memory_error();
drop(p);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this explicit drop?
They are all over the place and I think they are useless since it is done automatically at the end of the block

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not on the ones where we have it at the end, we can improve this later

},
Event::Telemetry(event) =>
match event.record {
TelemetryRecord::PlatformInitStart { .. } => {
Expand Down
1 change: 1 addition & 0 deletions bottlecap/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ impl MetricEvent {
pub enum Event {
Metric(MetricEvent),
Telemetry(TelemetryEvent),
OutOfMemory,
}
4 changes: 4 additions & 0 deletions bottlecap/src/lifecycle/invocation/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,4 +602,8 @@ impl Processor {
// todo: handle timeout
}
}

pub fn on_out_of_memory_error(&mut self) {
self.enhanced_metrics.increment_oom_metric();
}
}
38 changes: 30 additions & 8 deletions bottlecap/src/logs/lambda/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ pub struct LambdaProcessor {
event_bus: Sender<Event>,
}

const OOM_ERRORS: [&str; 7] = [
"fatal error: runtime: out of memory", // Go
"java.lang.OutOfMemoryError", // Java
"JavaScript heap out of memory", // Node
"Runtime exited with error: signal: killed", // Node
"MemoryError", // Python
"failed to allocate memory (NoMemoryError)", // Ruby
"OutOfMemoryException", // .NET
];

fn is_oom_error(error_msg: &str) -> bool {
OOM_ERRORS
.iter()
.any(|&oom_str| error_msg.contains(oom_str))
}

impl Processor<IntakeLog> for LambdaProcessor {}

impl LambdaProcessor {
Expand Down Expand Up @@ -71,16 +87,22 @@ impl LambdaProcessor {
_ => None,
};

if message.is_none() {
return Err("Unable to parse log".into());
if let Some(message) = message {
if is_oom_error(&message) {
if let Err(e) = self.event_bus.send(Event::OutOfMemory).await {
error!("Failed to send OOM event to the main event bus: {e}");
}
}

return Ok(Message::new(
message,
None,
self.function_arn.clone(),
event.time.timestamp_millis(),
));
}

Ok(Message::new(
message.expect("infallible"),
None,
self.function_arn.clone(),
event.time.timestamp_millis(),
))
Err("Unable to parse log".into())
}
TelemetryRecord::PlatformInitStart {
runtime_version,
Expand Down
4 changes: 4 additions & 0 deletions bottlecap/src/metrics/enhanced/lambda.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ impl Lambda {
self.increment_metric(constants::TIMEOUTS_METRIC);
}

pub fn increment_oom_metric(&self) {
self.increment_metric(constants::OUT_OF_MEMORY_METRIC);
}

pub fn set_init_duration_metric(&self, init_duration_ms: f64) {
if !self.config.enhanced_metrics {
return;
Expand Down
Loading