Understand AWS Lambda logs, JSON output, and retention

Read Lambda system records, configure supported JSON application logging, share logger configuration through a layer, and validate collection and cost changes.

Best practices
Understand AWS Lambda logs, JSON output, and retention

Serverless logging still needs explicit collection, permissions, and retention. In AWS Lambda, troubleshooting starts by connecting a request's logs with its duration, memory use, and outcome. This guide covers system records, JSON output, reusable logger configuration, retention, and a documented path for sending logs to Guance.

The examples focus on Lambda Event Functions. Lambda Managed Instances only support JSON logging and have a different execution model; do not apply the text-format example to them.

Documentation reviewed October 27, 2026. Examples are illustrative; cloud deployment, delivery, and cost tests were not performed for this article.

Key points

  • A normal text-log invocation commonly has START, END, and REPORT records. Additional records, failures, JSON format, and system-log filtering change what you see.
  • The default log group is /aws/lambda/<function-name>, but a function can use a configured custom group.
  • JSON logging supports system logs and supported runtime logging APIs. It does not convert every arbitrary stdout write into a structured application event.
  • Measure CloudWatch, forwarding, and destination costs together before changing retention or removing a logging path.

1. Read system records

This illustrative cold-start sequence uses the text format:

INIT_START Runtime Version: nodejs:22.v24 ...
START RequestId: 765b52b4-... Version: $LATEST
END RequestId: 765b52b4-...
REPORT RequestId: 765b52b4-... Duration: 259.72 ms Billed Duration: 449 ms
       Memory Size: 128 MB Max Memory Used: 69 MB Init Duration: 189.15 ms

The report is wrapped here for readability. Important distinctions are:

  • INIT_START: marks runtime initialization and identifies the runtime version. It does not itself contain the completed initialization duration.
  • START and END: identify invocation boundaries and the request ID.
  • REPORT: reports duration, billed duration, allocated memory, and observed memory usage. Initialization information and status fields depend on the invocation and format.

For the on-demand cold-start example, billed duration includes initialization under the billing change effective August 1, 2025. Do not calculate it by rounding handler duration alone.

Low memory use is a reason to benchmark another memory setting, not proof that lowering memory will reduce cost. Lambda's CPU allocation scales with memory, so a lower setting can lengthen execution. Max Memory Used can also reflect a high-water mark across invocations sharing an execution environment.

2. Understand groups and streams

With the required permissions, Lambda sends logs to the default or configured CloudWatch log group. Its execution role needs the relevant logs:CreateLogGroup, logs:CreateLogStream, and logs:PutLogEvents permissions. Streams identify execution environments and versions, commonly with a name shaped like YYYY/MM/DD/[version]<environment-id>. Reused environments continue to write to their stream.

Filter by request ID to investigate an invocation, and search the correct group and time window. Application or downstream logs need to include that identifier to participate in the same search; custom destinations and extensions may use another stream or schema.

3. Enable supported JSON logging

In the function's logging configuration, select JSON as the log format. A system report can look like this:

{
  "time": "2026-08-25T14:55:35.345Z",
  "type": "platform.report",
  "record": {
    "requestId": "88c76e69-...",
    "metrics": {
      "durationMs": 2226.333,
      "billedDurationMs": 2227,
      "memorySizeMB": 128,
      "maxMemoryUsedMB": 88
    },
    "status": "success"
  }
}

This example represents a report without an added cold-start initialization cost. Application JSON behavior depends on the runtime and logging API: supported Node.js console methods, for example, are handled differently from arbitrary raw stdout writes. Already-structured logger output is not necessarily wrapped into the same schema. Inspect a real event before writing field-based queries.

4. Share logging configuration in a layer

A layer can package a logger used by multiple functions. Make the module format explicit:

pino-layer/
└── nodejs/
    ├── index.mjs    # Exports the configured logger.
    └── node_modules/
        └── pino/    # Include this dependency and its dependencies.

For example, index.mjs can export the application logger:

import pino from 'pino';
export const logger = pino();

An ESM Lambda handler imports it with:

import { logger } from '/opt/nodejs/index.mjs';

Build and package the dependencies for the selected Lambda runtime and architecture. Attaching the same layer helps standardize output, but functions must use the exported logger and compatible settings. A layer version change does not automatically update every function.

5. Control retention and volume

  • CloudWatch log groups default to indefinite retention unless configured otherwise. Select a period such as 7–30 days only when it meets your investigation requirements.
  • Control application levels and unnecessary event volume before ingestion. Check what system and application log-level filtering your runtime supports.
  • Compare ingestion, forwarding, query, and retention costs on both sides of an integration. Shortening retention does not undo ingestion already billed.

6. Collect Lambda logs in Guance

The documented AWS Lambda extension is marked experimental. Validate it on a test function before relying on it:

  1. Choose the extension package for the function architecture, create the DataKit layer, and attach it.
  2. Configure ENV_DATAWAY for the workspace receiver and restrict access to its token.
  3. Run a successful invocation and a controlled failure. Verify function identity, time, logs, and duration at the destination; do not assume CloudWatch field names survive unchanged.
  4. Build queries and alerts from the received schema, then verify notifications. Test collection before changing the original retention policy.

Frequently asked questions

What does Init Duration mean?

It measures initialization reported for the relevant lifecycle phase. On-demand cold starts commonly expose it in REPORT; provisioned concurrency, SnapStart, failures, and suppressed initialization have different reporting behavior. Investigate dependencies and initialization work, and assess provisioned concurrency against its operational cost rather than treating it as a free fix.

Can logs identify a timeout?

Inspect the request's timeout message and platform status. A missing END record alone is insufficient: logs can be delayed or filtered. Validate the actual timeout and error fields at the destination before writing a detection rule.

What happens at high concurrency?

Different execution environments produce different streams. Use request identifiers and an appropriate cross-stream search rather than manually choosing one stream and assuming it contains the entire workload.

Can I send logs elsewhere without CloudWatch?

Evaluate an extension path, but first test failures, network interruption, and invocation shutdown. Confirm delivery and operational requirements before changing CloudWatch permissions or retention.

Related reading

References: Lambda log formats, execution lifecycle, and initialization billing change.

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting