What Is CloudWatch Logs? Insights, Retention & AWS Examples

Amazon CloudWatch Logs is a managed log storage and analysis service. When a Lambda function runs, an EC2 application writes an event, or a container emits output, that data flows into CloudWatch Logs where you store it, search it, and set alerts on it. It is the default log destination for most AWS services.

Teams use it to investigate production incidents with CloudWatch Logs Insights queries, to convert log patterns into alarms with metric filters, and to control costs with retention policies that automatically expire old data. Getting comfortable with CloudWatch Logs means getting faster at every debugging task on AWS.

Simple explanation

Think of CloudWatch Logs like the activity log kept at a busy post office. Every package sorted, every delivery attempted, every address scan gets recorded with a timestamp. If a package goes missing, you do not guess what happened. You pull the log for that tracking number and read exactly what occurred at each step and where the chain broke.

CloudWatch Logs works the same way for your AWS services. Every event your code emits gets timestamped and stored in an organized log stream. When something breaks at 2 AM, you go to the logs to read the story of what happened.

You do not manage servers, disks, or log rotation. CloudWatch handles all of that. Your job is to send logs in, set a retention period so you are not paying forever, and know how to search them when you need answers.

Why CloudWatch Logs matters

An alarm firing at 2 AM tells you your error rate spiked. It does not tell you which request failed, what the error message was, or what the call stack looked like. That detail lives in your logs.

CloudWatch Logs is the default log destination for Lambda, ECS, API Gateway, and many other AWS-managed services. You will encounter it immediately when debugging anything on AWS. Learning to query it well with Logs Insights cuts your time-to-resolution significantly during incidents.

Beyond debugging, it provides the audit trail required for compliance in regulated industries, feeds security pipelines via subscription filters, and enables you to build log-based metrics that turn log patterns into actionable alarms.

How CloudWatch Logs works

The data path from source to storage to analysis looks like this:

source emits logslog streamlog groupretention + encryption appliedsearch / query / alert / archive

Every log event originates somewhere: a Lambda invocation, an EC2 daemon, a container. That event flows into a log stream, a time-ordered sequence from a single source. Log streams are grouped inside a log group, which is where you set retention, encryption, and data protection policies. Once stored, you can search with filter patterns, run analytical queries with Logs Insights, stream events to another destination via subscription filters, or export to S3 for long-term archival.

This is the mental model to internalize before anything else on this page.

Core concepts

Log groups vs log streams

A log group is a named container for a set of related log streams. The standard pattern is one log group per service, application, or resource. Lambda automatically creates /aws/lambda/<function-name> for each function. You do not create it manually.

A log stream is a sequence of log events from a single source instance. Each Lambda function instance writes to its own stream. An EC2 instance typically has one stream per log file it ships.

Use Logs Insights queries at the log group level to search across all instances of a service simultaneously. Drill into a specific log stream only when you need to isolate output from exactly one instance.

Retention policies

By default, log groups never expire. Every log event you ingest is stored indefinitely, and you pay for it indefinitely. This is the single most common source of unexpected CloudWatch costs for teams new to AWS.

Set a retention policy on every log group. Common choices:

  • Development environments: 7 days
  • Production applications: 30 to 90 days
  • Compliance or audit logs: 1 to 7 years (consider exporting to S3 for cheaper long-term storage)
# Set a 30-day retention policy
aws logs put-retention-policy \
  --log-group-name /aws/lambda/<function-name> \
  --retention-in-days 30

# Find log groups with no retention policy set
aws logs describe-log-groups \
  --query 'logGroups[?!retentionInDays].logGroupName' \
  --output text
Cost trap

The default retention is never-expire. A production service generating 500 MB per day accumulates 180 GB in a year with no policy set. Automate this: manage log groups via Terraform or CloudFormation, or create an Amazon EventBridge rule that applies your default retention policy whenever a new log group is created.

Log classes

CloudWatch Logs offers two storage classes for log groups:

  • Standard. Full feature support including Logs Insights, metric filters, and subscription filters. The right choice for any log group you actively query.

  • Infrequent Access. Lower storage cost, but queries carry a higher per-GB scan rate and some features are not supported. Use this for logs you keep for compliance but rarely search.

There is also a Delivery class used for specific AWS service delivery logs such as VPC Flow Logs and CloudFront access logs via newer delivery methods. You will see it in the console but do not configure it yourself.

Encryption, permissions, and sensitive-data protection

All data in CloudWatch Logs is encrypted at rest by default using AWS-managed keys (SSE). No configuration is needed to get baseline encryption.

For environments that require customer-controlled keys, associate a customer-managed AWS KMS key with a log group:

aws logs associate-kms-key \
  --log-group-name /aws/lambda/<function-name> \
  --kms-key-id arn:aws:kms:<region>:<account-id>:key/<key-id>
Sensitive data warning

Encryption protects log data at rest, but it does not hide log content from anyone with CloudWatch access in your account. Configure data protection policies on log groups to automatically detect and mask PII, credit card numbers, and secrets before they are stored. CloudWatch replaces matching content with ***. Even with masking in place, the safest rule is: never log secrets or card numbers at the application level at all.

For IAM permissions, the key grants are logs:CreateLogGroup, logs:CreateLogStream, and logs:PutLogEvents. Lambda functions get all three via AWSLambdaBasicExecutionRole. See AWS IAM Roles Explained for the broader permissions model behind CloudWatch access control.

When to use CloudWatch Logs

  • Lambda troubleshooting: function output lands here automatically. Your first stop during any Lambda investigation. See Monitoring AWS Lambda Functions with CloudWatch for a deeper walkthrough.

  • EC2 application logs: ship application log files from instances via the CloudWatch agent without managing your own log infrastructure.

  • ECS and Fargate containers: container stdout and stderr forwarded via the awslogs log driver with no application code changes.

  • EKS and Kubernetes: the CloudWatch Observability add-on deploys Fluent Bit on each node to collect pod logs and ship them to CloudWatch under /aws/containerinsights/<cluster-name>/application.

  • Security and audit pipelines: centralize security tool output and application events for compliance reporting and threat detection.

  • Debugging production incidents: Logs Insights queries let you reconstruct exactly what happened during an outage: request timelines, error sequences, downstream failures. See Debugging Production Systems in AWS for practical investigation workflows.

Sending logs from common AWS sources

Lambda

Lambda sends logs to CloudWatch automatically. Every print() in Python, console.log() in Node.js, or System.out.println() in Java goes to /aws/lambda/<function-name> with no configuration required. The execution role needs AWSLambdaBasicExecutionRole, which grants the three required log permissions.

EC2

EC2 does not send logs automatically. Install the CloudWatch agent, which runs as a daemon and tails log files you specify:

# Install on Amazon Linux 2
sudo yum install -y amazon-cloudwatch-agent

# Run the configuration wizard
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard

A minimal agent config to ship an application log file:

{
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/app/application.log",
            "log_group_name": "/ec2/<app-name>/application",
            "log_stream_name": "{instance_id}",
            "retention_in_days": 30
          }
        ]
      }
    }
  }
}

ECS and Fargate

Add the awslogs log driver to your container task definition:

{
  "logConfiguration": {
    "logDriver": "awslogs",
    "options": {
      "awslogs-group": "/ecs/<service-name>",
      "awslogs-region": "<region>",
      "awslogs-stream-prefix": "ecs"
    }
  }
}

Container stdout and stderr are then forwarded to CloudWatch automatically. No application code changes needed.

EKS and Kubernetes

Install the CloudWatch Observability add-on from the EKS console or via the AWS CLI. It deploys a Fluent Bit DaemonSet that collects pod logs and sends them to CloudWatch under /aws/containerinsights/<cluster-name>/application. See Monitoring EKS Clusters in AWS for the full setup walkthrough, including the IAM permissions required for the add-on.

Searching and analyzing logs

Filter patterns

Filter patterns are basic pattern matching built into CloudWatch. Use them in the console to search a log stream, or as the basis for metric filters and subscription filters. Patterns can match literal strings, JSON field values, or space-delimited log fields. They are simpler than Logs Insights but useful for quick checks and alerting setups.

CloudWatch Logs Insights

Logs Insights is the primary querying tool for CloudWatch log data. Think of it like SQL for your logs: you pick which log group to query, write a statement, set a time range, and get results back in seconds instead of scrolling through thousands of raw lines. It uses a purpose-built query language with five core commands:

  • fields: select which fields to display
  • filter: narrow results by field value or pattern
  • stats: compute aggregates (count, avg, sum, min, max, percentile)
  • sort: order results
  • limit: cap the number of rows returned
# Find the 20 most recent errors
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 20

# Error rate over time in 5-minute buckets
fields @timestamp
| filter @message like /ERROR/
| stats count(*) as errorCount by bin(5m)

# Lambda cold start analysis
fields @timestamp, @initDuration
| filter @type = "REPORT"
| stats avg(@initDuration), max(@initDuration), count(@initDuration) as coldStarts by bin(1h)

# Parse structured JSON logs and aggregate by error code
fields @timestamp
| filter ispresent(level)
| filter level = "ERROR"
| stats count(*) by errorCode
| sort count(*) desc
Query tip

Logs Insights automatically parses JSON log events into queryable fields. A plain string like “Error: payment failed” requires regex matching. A structured JSON log like {“level”:“error”,“code”:“PAYMENT_FAILED”} lets you filter on code directly — faster and cheaper. See the structured logging guide for how to implement this in Lambda, Node.js, and Python.

Field indexes

CloudWatch Logs lets you configure field indexes on a log group. An index tells CloudWatch which JSON fields to pre-index so queries filtering on those fields skip unindexed data instead of scanning everything. For high-volume log groups, adding indexes on frequently filtered fields like level, requestId, or statusCode reduces both query time and the GB scanned, which directly lowers cost.

Live Tail

Live Tail streams new log events in real time from the AWS Console. While Logs Insights queries historical data, Live Tail is for active monitoring: during a deployment, when you are reproducing a bug, or right after a production change when you want to watch what is happening now. You can apply filter patterns to the live stream to see only relevant events. No setup is required beyond having logs flowing into a log group.

Subscription filters and streaming

A subscription filter forwards log events to another destination in near real time. Common destinations:

  • Amazon Kinesis Data Streams (for custom downstream processing)
  • Amazon Kinesis Data Firehose (to deliver continuously to S3, Redshift, or a SIEM)
  • Another Lambda function (for real-time log processing or transformation)
  • A different AWS account (for centralized log aggregation across accounts)

Use subscription filters when you need to continuously ship logs to a security pipeline, data warehouse, or centralized observability platform. For one-time archival of historical data, use the export to S3 approach instead.

Turning log patterns into metrics

Metric filters watch a log group and emit a CloudWatch metric whenever a pattern is matched. This lets you alert on log-level events without writing application code to publish a custom metric. The resulting metric feeds directly into CloudWatch Alarms.

# Create a metric filter that counts ERROR log lines
aws logs put-metric-filter \
  --log-group-name /aws/lambda/<function-name> \
  --filter-name "ErrorCount" \
  --filter-pattern "ERROR" \
  --metric-transformations \
    metricName=ErrorCount,metricNamespace=MyApp/Lambda,metricValue=1,unit=Count

See the Log-Based Metrics in CloudWatch guide for filter pattern syntax, JSON field matching, and how to wire the resulting metric into an alarm.

Controlling costs

CloudWatch Logs has three cost components: ingestion, storage, and Logs Insights scan volume. Each has an optimization lever:

  • Retention policies: the highest-impact change. Set them on every log group at creation time. Unretained log groups accumulate storage costs indefinitely.

  • Narrower Insights query windows: Logs Insights bills per GB scanned. Use the tightest time window that covers the incident and expand only if needed.

  • Structured JSON logs: filter on parsed fields rather than full-text regex. Queries are more precise and scan less data.

  • Field indexes: index the JSON fields you filter on most often. Reduces scan volume significantly for common queries on high-volume log groups.

  • Infrequent Access log class: switch archival log groups to this class to reduce storage cost on data you rarely query.

  • Export to S3: for logs past their active query window, export to S3 and remove from CloudWatch. S3 is significantly cheaper for cold data.

  • Log level discipline in production: DEBUG-level logging in production Lambda functions and containers generates significant ingestion volume. Use configurable log levels and log at INFO or above in production.

Biggest win

If you do nothing else after reading this page, run the retention audit command from the Retention policies section above and set policies on every log group that is missing one. For most teams this is the single change with the largest immediate cost impact.

Exporting logs to S3

CloudWatch storage is more expensive than S3 for large volumes of old data. For logs you need to keep for compliance but rarely query, export to S3 and remove from CloudWatch.

# Create an export task (timestamps are Unix milliseconds)
aws logs create-export-task \
  --log-group-name /aws/lambda/<function-name> \
  --from 1700000000000 \
  --to 1700086400000 \
  --destination <bucket-name> \
  --destination-prefix logs/lambda/<function-name>

# Check export task status
aws logs describe-export-tasks \
  --task-id <task-id>

Export tasks are asynchronous and can take hours for large log groups. For continuous archival, use a subscription filter to stream logs to Amazon Kinesis Data Firehose, which delivers to S3 in near real time.

CloudWatch Logs vs CloudWatch Metrics vs CloudTrail

Three services that confuse beginners. Here is the decision table:

CloudWatch LogsCloudWatch MetricsCloudTrail
What it capturesDetailed event and text output from services and applicationsNumeric time-series measurementsAWS API calls and account activity
When to use itDebugging errors, incident investigation, searching what happenedAlarms, dashboards, autoscaling triggersAuditing who did what in your AWS account
Query toolLogs InsightsMetrics console, CloudWatch AlarmsCloudTrail console, Athena on exported trails
Cost driverIngestion + storage + scan volumeNumber of metrics per accountTrail storage and event volume

The short version: use CloudWatch Metrics for numbers and trends you want to alarm on. Use CloudWatch Logs for the detail behind those numbers. Use CloudTrail when you need to know what AWS API calls were made, by whom, and from where.

Common beginner mistakes

  1. Not setting retention policies. The default is never-expire. A production service generating 500 MB per day accumulates 180 GB in a year. Set retention on every log group at creation time, ideally in infrastructure-as-code so it is never skipped.

  2. Wide Logs Insights time ranges. Queries bill per GB scanned. A 30-day query on a busy log group can be surprisingly expensive. Start with a narrow time range and expand only if the incident window is unclear.

  3. Missing Lambda logging permissions. If a Lambda function cannot write logs, the execution role is missing one of the three log permissions. AWSLambdaBasicExecutionRole covers all three. Check this first when Lambda logs are absent.

  4. Using unstructured log messages. Freeform text requires regex matching in Logs Insights. JSON-structured logs let you filter by field directly, and field indexes reduce scan cost further. See the structured logging guide.

  5. Logging sensitive data without protection. Log content is visible to anyone with CloudWatch access in your account. Configure data protection policies to mask PII automatically, and avoid logging secrets or card numbers at the application level regardless.

  6. Querying a single log stream instead of the log group. A log stream is one instance. During an incident with multiple Lambda invocations or EC2 instances, querying a single stream means you may miss errors from other instances. Run Logs Insights at the log group level.

Frequently asked questions

How do I get my application logs into CloudWatch?

It depends on where your application runs. Lambda sends logs automatically with no configuration required. For EC2, install the CloudWatch agent and configure it to tail your log files. For ECS and Fargate, add the awslogs log driver to your container task definition. For applications running elsewhere, use the AWS SDK to call PutLogEvents directly.

How much does CloudWatch Logs cost?

CloudWatch Logs charges for data ingestion per GB, storage per GB per month, and Logs Insights queries per GB scanned. The free tier covers 5 GB of ingestion and storage per month. Storage costs continue until data expires via a retention policy or is deleted, which is why setting retention on every log group matters.

What is CloudWatch Logs Insights?

CloudWatch Logs Insights is a query engine built into CloudWatch that lets you search and analyze log data using a purpose-built query language. It supports filtering by field value, aggregation, statistics, and visualization. It is much faster than manually browsing log streams and is the standard tool for incident investigation.

What is the difference between CloudWatch Logs and CloudTrail?

CloudWatch Logs captures application and service log output: your function errors, request traces, and application events. CloudTrail captures AWS API activity: who made which AWS API calls, when, and from where. Use CloudWatch Logs to debug your application. Use CloudTrail to audit AWS account activity.

How do I protect sensitive data in CloudWatch Logs?

CloudWatch Logs supports data protection policies that automatically detect and mask sensitive data such as credit card numbers, social security numbers, and other PII before it is stored. Matching content is replaced with asterisks. All log data is encrypted at rest by default using AWS-managed keys, and you can optionally associate a customer-managed KMS key for additional control.

Last verified: 3 May 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.