Lambda Log Buffering: Cut CloudWatch Ingestion Without Losing Correlation

Lambda Log Buffering: Cut CloudWatch Ingestion Without Losing Correlation

CloudWatch Logs charges for every ingested GB. Debug spam at INFO on hot Lambdas is a silent bill — until you sample blindly and lose the one correlation ID that would have closed the sev. Buffer, sample by level, and always keep correlation + error paths loud.

⚡ TL;DR: Use Powertools Logger with buffer-on-INFO / flush-on-ERROR; sample successful requests; never drop correlation_id / cold_start / error stacks. Pair with Lambda Powertools Node Structured Logs and OpenTelemetry for LLMs.

Buffer INFO, flush on failure

// handler.ts
import { Logger } from "@aws-lambda-powertools/logger";
import { injectLambdaContext } from "@aws-lambda-powertools/logger/middleware";
import middy from "@middy/core";

const logger = new Logger({
  serviceName: "checkout",
  logLevel: "INFO",
  // Powertools buffer: hold debug/info until error or explicit flush
});

export const handler = middy(async (event, ctx) => {
  logger.appendKeys({
    correlationId: event.headers?.["x-correlation-id"] ?? ctx.awsRequestId,
    tenantId: event.requestContext?.authorizer?.tenantId,
  });

  logger.info("start", { path: event.rawPath });
  try {
    const result = await checkout(event);
    // ✅ Sample successes: 1% INFO after success
    if (Math.random() < 0.01) logger.info("success_sample", { resultCode: result.code });
    return result;
  } catch (err) {
    // ✅ Errors always flush full buffer + stack
    logger.error("checkout_failed", { err });
    throw err;
  }
}).use(injectLambdaContext(logger, { clearState: true }));

Sampling policy that on-call accepts

Level Success path Error / timeout / DLQ
DEBUG off in prod flush last N buffered
INFO 1% sample 100%
WARN 100% 100%
ERROR 100% 100% + stack
// lib/sample.ts
export function shouldLogSuccess(sampleRate = 0.01) {
  return Math.random() < sampleRate;
}

❌ Sampling ERROR to “save money.” ✅ Cutting DEBUG/INFO volume while preserving every failed invoke’s correlation trail — same discipline as Node.js Event Loop Lag observability.

EMF metrics beat log-counting

import { Metrics, MetricUnit } from "@aws-lambda-powertools/metrics";
const metrics = new Metrics({ namespace: "Checkout", serviceName: "checkout" });

metrics.addMetric("CheckoutOk", MetricUnit.Count, 1);
metrics.publishStoredMetrics();

Prefer Embedded Metric Format for counts/latency; reserve logs for narrative context. That combination usually cuts ingestion more than aggressive sampling alone.

Closing checklist

✅ Dos
– ✅ Powertools Logger + correlation keys on every line
– ✅ Buffer INFO; flush on ERROR/timeout
– ✅ Sample successful INFO; never sample ERROR
– ✅ EMF for cardinality-safe counters
– ✅ Alarm on ingestion GB/day per log group

❌ Don’ts
– ❌ Don’t console.log unstructured strings in hot paths
– ❌ Don’t strip awsRequestId / tenant IDs when sampling
– ❌ Don’t keep DEBUG on in prod “just in case”
– ❌ Don’t create per-invoke log streams manually

Related reading

Last updated on September 11, 2026


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply