← Cloud · AWS← Cloud · AWS
Cloud · AWSCloud · AWS19 Th7, 2026Jul 19, 202617 phút đọc14 min read

Observability (Khả năng quan sát)Observability

Part of the Cloud knowledge base — AWS deep dive. Complements DevOps Roadmap.

Tổng quan

Observability là kỷ luật hiểu một hệ thống đang chạy làm gì từ bên ngoài — thông qua metrics, logs, và traces mà nó phát ra — để bạn có thể trả lời những câu hỏi mà bạn chưa lường trước khi xây dựng nó. Trên AWS, trung tâm là CloudWatch, thu thập metrics và logs từ gần như mọi dịch vụ, đánh giá alarm, và hiển thị dashboard. Xoay quanh nó là các dịch vụ chuyên biệt: CloudTrail cho audit trail ai đã làm gì, AWS Config cho lịch sử cấu hình và compliance của tài nguyên, X-Ray cho distributed tracing, và ADOT (AWS Distro for OpenTelemetry) là collector trung lập kết nối tất cả lại.

Sự chuyển đổi tư duy quan trọng với một DevOps engineer là sự khác biệt giữa monitoringobservability. Monitoring trả lời các câu hỏi đã định nghĩa trước (“CPU có trên 80% không?”) bằng dashboard và alarm bạn xây sẵn. Observability là thuộc tính cho phép bạn đặt câu hỏi mới cho hệ thống production mà không cần ship code mới — “tại sao chỉ user Canada trên luồng checkout gặp lỗi 500 trong 9 phút vừa qua?” Bạn đạt được điều đó bằng cách phát ra telemetry có cấu trúc, high-cardinality (metrics có dimension, JSON logs, traces được correlate) thay vì các counter đơn giản và dòng log tự do.

Trade-off chính là tín hiệu vs. chi phí. CloudWatch tính phí theo lượng log ingest, custom metrics, dashboard, và số lần đánh giá alarm; một cấu hình bất cẩn — log DEBUG từ mọi Lambda, một custom metric cho mỗi user ID — tạo ra hóa đơn lớn hơn cả compute mà nó quan sát. Kỹ năng là bắt đủ tín hiệu để debug và alert tốt trong khi kiểm soát chặt chẽ volume, cardinality, và retention. Trang này bao quát các building block của AWS và các thực hành giữ chúng hữu ích và tiết kiệm.

Kiến thức nền tảng

Ba trụ cột trên AWS

Trụ cộtCâu hỏi trả lờiDịch vụ AWSDạng dữ liệu
MetricsCó khỏe không? Bao nhiêu?CloudWatch MetricsChuỗi thời gian số có dimension
LogsChính xác đã xảy ra gì?CloudWatch LogsSự kiện text/JSON có timestamp
TracesThời gian/lỗi đi đâu?X-Ray / ADOTSpans qua ranh giới dịch vụ

Metrics rẻ để lưu và nhanh để truy vấn nhưng low-cardinality — tốt cho alerting và dashboard xu hướng. Logs phong phú và high-cardinality nhưng đắt để lưu và chậm để quét — tốt cho chi tiết forensic. Traces ghép một request qua nhiều dịch vụ để bạn thấy latency và lỗi lan truyền qua call graph. Một setup trưởng thành dùng cả ba và, quan trọng, correlate chúng (một trace ID trong log, một link log trên alarm) để bạn pivot từ “alarm bắn” sang “đây là request chính xác” trong vài giây.

Mô hình metrics của CloudWatch

Một CloudWatch metric được định danh duy nhất bởi namespace + name + tập các dimension. AWS/EC2CPUUtilization{InstanceId=i-0abc} là một chuỗi thời gian; một InstanceId khác là chuỗi khác. Mỗi tổ hợp dimension duy nhất là một custom metric tính phí riêng (với custom namespace), đó là lý do cardinality là đòn bẩy chi phí.

Mô hình logs

CloudWatch Logs tổ chức dữ liệu thành log group → log stream → log event. Log group là đơn vị của retention và access control (ví dụ /aws/lambda/checkout); một stream là chuỗi sự kiện từ một nguồn (một Lambda instance, một container). Retention được đặt theo group — mặc định là không bao giờ hết hạn, nguồn gốc phổ biến nhất của hóa đơn CloudWatch bất ngờ. Phát ra JSON có cấu trúc (thay vì text tự do) là chìa khóa để truy vấn, vì khi đó Logs Insights có thể filter và aggregate theo field.

Khái niệm chính

CloudWatch alarms

Một alarm theo dõi một metric (hoặc một biểu thức metric math / dải anomaly detection) và chuyển giữa OK, ALARM, và INSUFFICIENT_DATA dựa trên một threshold đánh giá qua N period. Hành động alarm có thể notify (SNS → email/Slack/PagerDuty), auto-scale (chính sách ASG), hoặc self-heal (EC2 recover/reboot).

Các núm điều chỉnh chính:

Ví dụ thực tế — alarm latency p99 (CLI):

aws cloudwatch put-metric-alarm \
  --alarm-name "checkout-p99-latency-high" \
  --alarm-description "Checkout p99 latency > 500ms for 3 of 5 minutes" \
  --namespace "AWS/ApplicationELB" \
  --metric-name "TargetResponseTime" \
  --dimensions Name=LoadBalancer,Value=app/checkout-alb/50dc6c495c0c9188 \
  --extended-statistic "p99" \
  --period 60 \
  --evaluation-periods 5 \
  --datapoints-to-alarm 3 \
  --threshold 0.5 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching \
  --alarm-actions arn:aws:sns:us-east-1:111122223333:oncall-pager

Hai chi tiết làm alarm này tốt: nó alarm trên p99, không phải average (average che giấu phần đuôi các request chậm mà user thực sự cảm nhận), và nó yêu cầu 3 trong 5 phút breaching với notBreaching khi thiếu dữ liệu, nên một blip đơn lẻ không page on-call lúc 3 giờ sáng.

Custom metrics: mẹo EMF

Bạn có thể publish custom metrics với PutMetricData, nhưng API tốn phí mỗi lần gọi và thêm latency vào luồng request. Pattern tốt hơn cho Lambda/container là Embedded Metric Format (EMF): bạn viết một dòng JSON log có cấu trúc đặc biệt, và CloudWatch trích xuất metric từ nó bất đồng bộ mà không tốn phí API mỗi lần gọi. Bạn có cả log event metric từ một lần ghi stdout.

{
  "_aws": {
    "Timestamp": 1699900000000,
    "CloudWatchMetrics": [{
      "Namespace": "MyApp/Checkout",
      "Dimensions": [["Service", "Currency"]],
      "Metrics": [{ "Name": "OrderValue", "Unit": "None" }]
    }]
  },
  "Service": "checkout",
  "Currency": "CAD",
  "OrderValue": 42.50,
  "traceId": "1-6564abcd-..."
}

Giữ danh sách Dimensions low-cardinality — đừng bao giờ đặt user ID hay request ID vào dimension của metric, vì mỗi giá trị duy nhất trở thành một chuỗi thời gian tính phí. Các định danh high-cardinality thuộc về field của log (truy vấn bằng Logs Insights), không phải dimension của metric.

CloudWatch Logs Insights

Logs Insights là ngôn ngữ truy vấn được thiết kế riêng cho CloudWatch Logs — hãy nghĩ như “SQL cho logs”. Nó parse field JSON tự động và hỗ trợ filter, stats, sort, parse, và limit. Bạn quét một khoảng thời gian đã chọn trên một hoặc nhiều log group và trả phí theo GB quét, nên hãy thu hẹp cửa sổ thời gian và pre-filter trước khi aggregate.

Ví dụ thực tế — top 10 request chậm nhất có lỗi:

fields @timestamp, @message, duration, statusCode, path
| filter statusCode >= 500
| stats count() as errors, avg(duration) as avgMs, pct(duration, 99) as p99Ms by path
| sort errors desc
| limit 10

Và một truy vấn “tìm kim đáy bể” kinh điển dùng parse trên log không cấu trúc:

fields @timestamp, @message
| parse @message "user=* action=* latency=*ms" as user, action, latency
| filter action = "checkout" and latency > 1000
| sort latency desc
| limit 20

Bài học: log có cấu trúc làm truy vấn đầu tiên trở nên tầm thường; log không cấu trúc buộc bạn phải “vật lộn” với parse. Hãy đầu tư vào JSON logging từ sớm.

CloudWatch dashboards & EventBridge

Dashboards là tập các widget định nghĩa bằng JSON (biểu đồ metric, giá trị đơn, bảng log, trạng thái alarm). Định nghĩa chúng bằng IaC (Terraform aws_cloudwatch_dashboard / CloudFormation) để chúng được version hóa và tái lập, không phải vẽ tay trong console. Một dashboard dịch vụ tốt dẫn dắt bằng các tín hiệu RED/USE (Rate, Errors, Duration / Utilization, Saturation, Errors) ở trên cùng và drill down phía dưới.

EventBridge là event bus phản ứng với thay đổi khắp AWS. Nó nhận sự kiện (thay đổi trạng thái EC2, một stage CodePipeline, một event app tùy chỉnh, hoặc một schedule dạng cron), khớp chúng với rules, và route đến target (Lambda, SQS, SNS, Step Functions). Về observability, đây là cách bạn biến một event CloudTrail/Config/GuardDuty thành phản ứng tự động — ví dụ “khi GuardDuty phát hiện một instance bị xâm nhập, cô lập security group của nó”. EventBridge Scheduler cũng thay thế các cron rule cũ của CloudWatch Events cho các job theo lịch.

CloudTrail: audit trail

CloudTrail ghi lại hoạt động API trong tài khoản — ai gọi gì, khi nào, từ đâu, và có thành công không. Đây là xương sống forensic và compliance của bạn; khi có gì đó thay đổi bất ngờ, CloudTrail cho bạn biết principal nào đã làm.

Loại eventGhi lại gìMặc địnhChi phí
Management eventsThao tác control-plane (tạo/xóa/sửa, đăng nhập console, thay đổi IAM)Được log, Event history 90 ngày miễn phíBản sao đầu tiên vào trail miễn phí
Data eventsThao tác data-plane volume lớn (S3 GetObject, Lambda Invoke, thao tác item DynamoDB)Tắt — phải bậtTính phí theo event, có thể rất lớn
Insights eventsPattern rate/error API bất thường phát hiện bằng MLTắt — phải bậtTính phí thêm

Best practice là một organization trail (tạo ở management account, áp dụng cho mọi member account) chuyển đến một S3 bucket trung tâm được khóa chặt ở một logging account riêng, với log file validation bật để phát hiện giả mạo. Data events mạnh nhưng ồn và tốn kém — chỉ scope chúng cho các bucket/function cụ thể quan trọng (ví dụ một bucket chứa PII), không phải mọi thứ.

AWS Config: trạng thái cấu hình & compliance

Nơi CloudTrail ghi hành động, AWS Config ghi trạng thái — một snapshot liên tục và lịch sử thay đổi của cấu hình mỗi tài nguyên — và đánh giá trạng thái đó theo rules.

X-Ray: distributed tracing

X-Ray theo một request khi nó chảy qua các dịch vụ, tạo ra một trace gồm các segment (một cho mỗi dịch vụ) và subsegment (một lời gọi DB, một lời gọi HTTP). Nó hiển thị một service map — một đồ thị trực quan của kiến trúc với latency và error rate trên mỗi cạnh — để bạn phát hiện một dependency downstream thêm 300 ms hoặc ném lỗi.

AWS Distro for OpenTelemetry (ADOT)

OpenTelemetry (OTel) là chuẩn CNCF trung lập với nhà cung cấp để tạo và thu thập metrics, logs, và traces với một bộ SDK và một giao thức truyền (OTLP). ADOT là bản phân phối được AWS hỗ trợ và vá lỗi bảo mật của OTel Collector cộng SDK, với các exporter được cấu hình sẵn cho CloudWatch, X-Ray, và Amazon Managed Service for Prometheus (AMP) / Grafana (AMG).

Tại sao quan trọng: instrument một lần với OTel, và bạn có thể gửi telemetry đến CloudWatch/X-Ray đến Prometheus/Grafana/Datadog/Jaeger mà không cần re-instrument khi đổi backend. ADOT chạy như một sidecar (ECS/EKS), một Lambda layer, hoặc một triển khai collector độc lập, nhận OTLP và phân phối ra các backend bạn chọn. Với bất kỳ instrumentation mới nào trong năm 2026, hãy ưu tiên OTel/ADOT hơn X-Ray SDK độc quyền để tránh lock-in.

Container Insights

Container Insights là observability turnkey của CloudWatch cho ECS, EKS, và Fargate: nó thu thập metrics ở cấp cluster, node, pod, và container (CPU, memory, network, disk) cộng performance logs, và ship dashboard được tuyển chọn. Phiên bản enhanced observability thêm metrics chi tiết per-container và control-plane. Trên EKS nó thường được triển khai qua CloudWatch Observability EKS add-on (đóng gói collector ADOT/Fluent Bit). Nó trả lời “pod nào đang bị throttle CPU?” và “node này có bị bão hòa memory không?” mà bạn không cần tự xây pipeline. Lambda Insights là tương đương cho function (cold start, memory, duration).

Best Practices

  1. Đặt chính sách retention cho mọi log group. Đừng bao giờ để mặc định “không hết hạn”. Lý do: retention log vô hạn là hóa đơn CloudWatch bất ngờ số một; khớp retention với nhu cầu điều tra và compliance thực tế (ví dụ 30 ngày hot, archive sang S3/Glacier sau đó).
  2. Phát ra JSON logs có cấu trúc, không phải text tự do. Lý do: Logs Insights có thể filter và aggregate theo field trực tiếp, biến việc “khảo cổ” parse nhiều phút thành truy vấn một dòng và cho phép EMF metrics miễn phí.
  3. Alarm trên percentile (p95/p99), không phải average. Lý do: average che giấu phần đuôi chậm mà user thực sự trải nghiệm; một average khỏe mạnh có thể giấu 1% request bị timeout.
  4. Yêu cầu nhiều datapoint và đặt “treat missing data” có chủ đích. Dùng đánh giá “M trong N” và chọn notBreaching/breaching theo từng metric. Lý do: alarm một datapoint sẽ flapping và gây mệt mỏi cho on-call; chính sách missing-data sai gây false alarm hoặc điểm mù âm thầm.
  5. Giữ dimension của metric low-cardinality; đặt ID vào field của log. Lý do: mỗi tổ hợp dimension duy nhất là một chuỗi thời gian tính phí riêng — một dimension user-ID có thể bùng nổ thành hàng triệu metric và hóa đơn khổng lồ.
  6. Dùng EMF thay vì PutMetricData trên luồng request. Lý do: EMF suy ra metric từ một lần ghi log mà không cần lời gọi API đồng bộ, loại bỏ latency và chi phí mỗi lần gọi khỏi luồng nóng.
  7. Route alarm qua SNS đến hệ thống paging thực, và dùng composite alarm. Lý do: chỉ email sẽ bị bỏ qua; composite alarm (latency VÀ errors) chỉ bắn trên sự cố thực, giảm nhiễu mà vẫn giữ độ phủ.
  8. Định nghĩa dashboard và alarm bằng IaC. Lý do: dashboard vẽ trong console không được version hóa và biến mất cùng người tạo; Terraform/CloudFormation làm observability tái lập và review được.
  9. Bật organization CloudTrail đến một S3 bucket trung tâm được khóa ở một account riêng. Bật log-file validation và block public access. Lý do: một audit log chống giả mạo, out-of-band là thiết yếu cho forensic sự cố và compliance, và tập trung hóa ngăn một account bị xâm nhập xóa dấu vết của chính nó.
  10. Scope data events của CloudTrail hẹp. Chỉ bật chúng trên các bucket/function nhạy cảm. Lý do: data events có volume lớn và tính phí theo event; bật đại trà có thể tốn hơn cả workload với ít giá trị thêm.
  11. Triển khai AWS Config với conformance pack và auto-remediation. Lý do: đánh giá compliance liên tục cộng remediation tự động bắt drift (bucket public, volume chưa encrypt) trong vài phút thay vì đến kỳ audit sau.
  12. Sampling trace; đừng trace 100% traffic lớn. Lý do: tracing đầy đủ ở quy mô lớn tốn kém và hiếm khi cần thiết; một sampling rule giữ chi phí có giới hạn mà vẫn phát hiện bất thường latency và lỗi.
  13. Correlate ba trụ cột bằng trace/request ID. Đặt X-Ray/trace ID vào mỗi dòng log và link log từ alarm. Lý do: correlation là thứ biến “một alarm bắn” thành “đây là request lỗi chính xác” trong vài giây thay vì hàng giờ.
  14. Chuẩn hóa trên OpenTelemetry/ADOT cho instrumentation mới. Lý do: instrument-một-lần, export-mọi-nơi tránh lock-in backend và cho phép đổi hoặc thêm nhà cung cấp observability mà không đụng vào code ứng dụng.
  15. Bật Container Insights (và Lambda Insights) cho compute được quản lý. Lý do: dashboard cluster/pod/function được tuyển chọn bắt được bão hòa tài nguyên và hồi quy cold-start mà bạn có thể bỏ lỡ, gần như không cần setup.
  16. Theo dõi chính hóa đơn observability. Track chi phí CloudWatch/CloudTrail/Config như một metric và alarm trên bất thường. Lý do: chi phí telemetry có thể âm thầm vượt chi phí compute; coi nó là một hạng mục ngân sách hạng nhất giữ cho một debug-log để quên trong prod không làm phá sản đội.

Tài liệu tham khảo

Part of the Cloud knowledge base — AWS deep dive. Complements DevOps Roadmap.

Overview

Observability is the discipline of understanding what a running system is doing from the outside — through the metrics, logs, and traces it emits — so you can answer questions you did not anticipate when you built it. On AWS the center of gravity is CloudWatch, which collects metrics and logs from nearly every service, evaluates alarms, and renders dashboards. Around it sit specialized services: CloudTrail for the audit trail of who did what, AWS Config for the configuration history and compliance of your resources, X-Ray for distributed traces, and ADOT (AWS Distro for OpenTelemetry) as the vendor-neutral collector that ties it all together.

The important mental shift for a DevOps engineer is the difference between monitoring and observability. Monitoring answers pre-defined questions (“is CPU above 80%?”) with dashboards and alarms you built in advance. Observability is the property that lets you ask new questions of a system in production without shipping new code — “why are only Canadian users on the checkout path seeing 500s in the last nine minutes?” You get there by emitting high-cardinality, structured telemetry (dimensioned metrics, JSON logs, correlated traces) rather than scalar counters and free-text log lines.

The governing trade-off is signal vs. cost. CloudWatch bills for ingested log data, custom metrics, dashboards, and alarm evaluations, and a careless setup — DEBUG logs from every Lambda, a custom metric per user ID — produces bills that dwarf the compute they observe. The craft is capturing enough signal to debug and alert well while ruthlessly controlling volume, cardinality, and retention. This page covers the AWS building blocks and the practices that keep them useful and affordable.

Fundamentals

The three pillars on AWS

PillarQuestion it answersAWS serviceData shape
MetricsIs it healthy? How much?CloudWatch MetricsNumeric time series with dimensions
LogsWhat exactly happened?CloudWatch LogsTimestamped text/JSON events
TracesWhere did the time/error go?X-Ray / ADOTSpans across service boundaries

Metrics are cheap to store and fast to query but low-cardinality — good for alerting and trend dashboards. Logs are rich and high-cardinality but expensive to store and slow to scan — good for forensic detail. Traces stitch a single request across many services so you can see latency and failure propagate through a call graph. A mature setup uses all three and, crucially, correlates them (a trace ID in your logs, a log link on a metric alarm) so you can pivot from “the alarm fired” to “here is the exact request” in seconds.

CloudWatch metrics model

A CloudWatch metric is uniquely identified by namespace + name + a set of dimensions. AWS/EC2CPUUtilization{InstanceId=i-0abc} is one time series; a different InstanceId is a different series. Each unique dimension combination is a separately-billed custom metric (for custom namespaces), which is why cardinality is the cost lever.

Logs model

CloudWatch Logs organizes data as log group → log stream → log event. A log group is the unit of retention and access control (e.g. /aws/lambda/checkout); a stream is a sequence of events from one source (one Lambda instance, one container). Retention is set per group — the default is never expire, which is the single most common source of surprise CloudWatch bills. Emitting structured JSON logs (rather than free text) is the unlock for querying, because Logs Insights can then filter and aggregate on fields.

Key Concepts

CloudWatch alarms

An alarm watches one metric (or a metric math expression / anomaly detection band) and transitions between OK, ALARM, and INSUFFICIENT_DATA based on a threshold evaluated over N periods. Alarm actions can notify (SNS → email/Slack/PagerDuty), auto-scale (ASG policies), or self-heal (EC2 recover/reboot).

Key knobs:

Worked example — a p99 latency alarm (CLI):

aws cloudwatch put-metric-alarm \
  --alarm-name "checkout-p99-latency-high" \
  --alarm-description "Checkout p99 latency > 500ms for 3 of 5 minutes" \
  --namespace "AWS/ApplicationELB" \
  --metric-name "TargetResponseTime" \
  --dimensions Name=LoadBalancer,Value=app/checkout-alb/50dc6c495c0c9188 \
  --extended-statistic "p99" \
  --period 60 \
  --evaluation-periods 5 \
  --datapoints-to-alarm 3 \
  --threshold 0.5 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching \
  --alarm-actions arn:aws:sns:us-east-1:111122223333:oncall-pager

Two details make this good: it alarms on p99, not average (averages hide the tail of slow requests users actually feel), and it requires 3 of 5 breaching minutes with notBreaching on gaps, so a single blip does not page the on-call at 3 a.m.

Custom metrics: the EMF trick

You can publish custom metrics with PutMetricData, but the API costs per call and adds latency to your request path. The better pattern for Lambda/containers is the Embedded Metric Format (EMF): you write a specially-structured JSON log line, and CloudWatch extracts metrics from it asynchronously at no per-call API cost. You get the log event and the metric from a single stdout write.

{
  "_aws": {
    "Timestamp": 1699900000000,
    "CloudWatchMetrics": [{
      "Namespace": "MyApp/Checkout",
      "Dimensions": [["Service", "Currency"]],
      "Metrics": [{ "Name": "OrderValue", "Unit": "None" }]
    }]
  },
  "Service": "checkout",
  "Currency": "CAD",
  "OrderValue": 42.50,
  "traceId": "1-6564abcd-..."
}

Keep the Dimensions list low-cardinality — never put a user ID or request ID in a metric dimension, because every unique value becomes a billed time series. High-cardinality identifiers belong in log fields (queried by Logs Insights), not metric dimensions.

CloudWatch Logs Insights

Logs Insights is a purpose-built query language for CloudWatch Logs — think “SQL-ish for logs.” It parses JSON fields automatically and supports filter, stats, sort, parse, and limit. You scan a chosen time range across one or more log groups and pay per GB scanned, so narrow the time window and pre-filter before aggregating.

Worked example — top 10 slowest requests with errors:

fields @timestamp, @message, duration, statusCode, path
| filter statusCode >= 500
| stats count() as errors, avg(duration) as avgMs, pct(duration, 99) as p99Ms by path
| sort errors desc
| limit 10

And a classic “find the needle” query using parse on unstructured logs:

fields @timestamp, @message
| parse @message "user=* action=* latency=*ms" as user, action, latency
| filter action = "checkout" and latency > 1000
| sort latency desc
| limit 20

The lesson: structured logs make the first query trivial; unstructured logs force you into parse gymnastics. Invest in JSON logging early.

CloudWatch dashboards & EventBridge

Dashboards are JSON-defined collections of widgets (metric graphs, single values, log tables, alarm status). Define them in IaC (Terraform aws_cloudwatch_dashboard / CloudFormation) so they are versioned and reproducible, not hand-drawn in the console. A good service dashboard leads with the RED/USE signals (Rate, Errors, Duration / Utilization, Saturation, Errors) at the top and drills down below.

EventBridge is the event bus that reacts to changes across AWS. It receives events (an EC2 state change, a CodePipeline stage, a custom app event, or a cron schedule), matches them against rules, and routes to targets (Lambda, SQS, SNS, Step Functions). For observability it is how you turn a CloudTrail/Config/GuardDuty event into an automated response — e.g. “when GuardDuty finds a compromised instance, isolate its security group.” EventBridge Scheduler also replaces old CloudWatch Events cron rules for scheduled jobs.

CloudTrail: the audit trail

CloudTrail records API activity in your account — who called what, when, from where, and whether it succeeded. It is your forensic and compliance backbone; when something changes unexpectedly, CloudTrail tells you which principal did it.

Event typeWhat it capturesDefaultCost
Management eventsControl-plane ops (create/delete/modify, console logins, IAM changes)Logged, last 90 days free in Event historyFirst copy free to a trail
Data eventsHigh-volume data-plane ops (S3 GetObject, Lambda Invoke, DynamoDB item ops)Off — opt inBilled per event, can be large
Insights eventsML-detected unusual API rate/error patternsOff — opt inExtra charge

Best practice is one organization trail (created in the management account, applied to every member account) delivering to a central, locked-down S3 bucket in a separate logging account, with log file validation enabled so tampering is detectable. Data events are powerful but noisy and costly — scope them to the specific buckets/functions that matter (e.g. a bucket holding PII), not everything.

AWS Config: configuration state & compliance

Where CloudTrail records actions, AWS Config records state — a continuous snapshot and change history of every resource’s configuration — and evaluates that state against rules.

X-Ray: distributed tracing

X-Ray follows a request as it flows through your services, producing a trace made of segments (one per service) and subsegments (a DB call, an HTTP call). It renders a service map — a visual graph of your architecture with latency and error rates on each edge — so you can spot the one downstream dependency adding 300 ms or throwing errors.

AWS Distro for OpenTelemetry (ADOT)

OpenTelemetry (OTel) is the vendor-neutral, CNCF standard for generating and collecting metrics, logs, and traces with one set of SDKs and one wire protocol (OTLP). ADOT is AWS’s supported, security-patched distribution of the OTel Collector plus SDKs, with exporters pre-wired for CloudWatch, X-Ray, and Amazon Managed Service for Prometheus (AMP) / Grafana (AMG).

Why it matters: instrument once with OTel, and you can send telemetry to CloudWatch/X-Ray and to Prometheus/Grafana/Datadog/Jaeger without re-instrumenting when you change backends. ADOT runs as a sidecar (ECS/EKS), a Lambda layer, or a standalone collector deployment, receiving OTLP and fanning out to your chosen backends. For any greenfield instrumentation in 2026, prefer OTel/ADOT over the proprietary X-Ray SDK to avoid lock-in.

Container Insights

Container Insights is CloudWatch’s turnkey observability for ECS, EKS, and Fargate: it collects cluster-, node-, pod-, and container-level metrics (CPU, memory, network, disk) plus performance logs, and ships curated dashboards. The enhanced observability version adds granular per-container and control-plane metrics. On EKS it is typically deployed via the CloudWatch Observability EKS add-on (which bundles the ADOT/Fluent Bit collectors). It answers “which pod is throttling CPU?” and “is this node memory-saturated?” without you building the pipeline by hand. Lambda Insights is the equivalent for functions (cold starts, memory, duration).

Best Practices

  1. Set a retention policy on every log group. Never leave the default “never expire.” Rationale: unbounded log retention is the number-one surprise CloudWatch bill; match retention to actual investigative and compliance needs (e.g. 30 days hot, archive to S3/Glacier beyond).
  2. Emit structured JSON logs, not free text. Rationale: Logs Insights can filter and aggregate on fields directly, turning multi-minute parse archaeology into one-line queries and enabling EMF metrics for free.
  3. Alarm on percentiles (p95/p99), not averages. Rationale: averages mask the slow tail that real users experience; a healthy average can hide 1% of requests timing out.
  4. Require multiple datapoints and set “treat missing data” deliberately. Use “M of N” evaluation and choose notBreaching/breaching per metric. Rationale: single-datapoint alarms flap and cause pager fatigue; the wrong missing-data policy causes false alarms or silent blind spots.
  5. Keep metric dimensions low-cardinality; put IDs in log fields. Rationale: every unique dimension combination is a separately billed time series — a user-ID dimension can explode into millions of metrics and a huge bill.
  6. Use EMF instead of PutMetricData on the request path. Rationale: EMF derives metrics from a single log write with no synchronous API call, removing latency and per-call cost from your hot path.
  7. Route alarms through SNS to a real paging system, and use composite alarms. Rationale: email alone gets ignored; composite alarms (latency AND errors) fire only on genuine incidents, cutting noise while preserving coverage.
  8. Define dashboards and alarms in IaC. Rationale: console-drawn dashboards are unversioned and vanish with the person who made them; Terraform/CloudFormation makes observability reproducible and reviewable.
  9. Enable an organization CloudTrail to a locked, central S3 bucket in a separate account. Turn on log-file validation and block public access. Rationale: a tamper-evident, out-of-band audit log is essential for incident forensics and compliance, and centralizing it prevents a compromised account from deleting its own tracks.
  10. Scope CloudTrail data events narrowly. Enable them only on sensitive buckets/functions. Rationale: data events are high-volume and billed per event; blanket enablement can cost more than the workload itself with little added value.
  11. Deploy AWS Config with conformance packs and auto-remediation. Rationale: continuous compliance evaluation plus automatic remediation catches drift (public buckets, unencrypted volumes) in minutes instead of at the next audit.
  12. Sample traces; don’t trace 100% of high traffic. Rationale: full-fidelity tracing at scale is expensive and rarely necessary; a sampling rule keeps costs bounded while still surfacing latency and error anomalies.
  13. Correlate the three pillars with a trace/request ID. Put the X-Ray/trace ID in every log line and link logs from alarms. Rationale: correlation is what turns “an alarm fired” into “here is the exact failing request” in seconds instead of hours.
  14. Standardize on OpenTelemetry/ADOT for new instrumentation. Rationale: instrument-once, export-anywhere avoids backend lock-in and lets you change or add observability vendors without touching application code.
  15. Turn on Container Insights (and Lambda Insights) for managed compute. Rationale: curated cluster/pod/function dashboards catch resource saturation and cold-start regressions you would otherwise miss, with almost no setup.
  16. Watch the observability bill itself. Track CloudWatch/CloudTrail/Config spend as a metric and alarm on anomalies. Rationale: telemetry cost can quietly exceed compute cost; treating it as a first-class budget line keeps a debug-log left on in prod from bankrupting the team.

References