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 monitoring và observability. 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ột | Câu hỏi trả lời | Dịch vụ AWS | Dạng dữ liệu |
|---|---|---|---|
| Metrics | Có khỏe không? Bao nhiêu? | CloudWatch Metrics | Chuỗi thời gian số có dimension |
| Logs | Chính xác đã xảy ra gì? | CloudWatch Logs | Sự kiện text/JSON có timestamp |
| Traces | Thời gian/lỗi đi đâu? | X-Ray / ADOT | Spans 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/EC2 → CPUUtilization → {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í.
- Namespaces — container cho metrics. Dịch vụ AWS dùng
AWS/<Service>(ví dụAWS/Lambda); của bạn dùng bất kỳ tên khác (ví dụMyApp/Checkout). - Dimensions — tối đa 30 cặp name/value scope một metric. Nhiều dimension = nhiều chuỗi = slice mịn hơn nhưng chi phí cao hơn.
- Resolution — metric chuẩn có độ mịn 1 phút; high-resolution custom metrics xuống tới 1 giây (đắt hơn).
- Statistics — bạn không bao giờ lưu điểm thô mãi mãi; bạn truy vấn các aggregation (
Average,Sum,p99,Maximum) trên một period. Percentile (p90,p99) quan trọng hơn nhiều so với average cho latency.
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:
- Period + Evaluation periods + Datapoints to alarm — “3 trong 5 period 5 phút vượt threshold” tránh flapping trên một spike đơn lẻ.
- Treat missing data —
notBreaching,breaching,ignore, hoặcmissing; chọn sai gây false alarm hoặc điểm mù âm thầm. - Composite alarms — kết hợp alarm con với
AND/ORđể bạn chỉ page khi nhiều điều kiện đồng thời (ví dụ latency cao VÀ error rate cao), giảm nhiễu. - Anomaly detection — CloudWatch huấn luyện một dải giá trị kỳ vọng; bạn alarm trên độ lệch thay vì threshold cố định, phù hợp với metric có tính mùa vụ theo ngày/tuần.
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 và 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 event | Ghi lại gì | Mặc định | Chi phí |
|---|---|---|---|
| Management events | Thao 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 events | Thao tác data-plane volume lớn (S3 GetObject, Lambda Invoke, thao tác item DynamoDB) | Tắt — phải bật | Tính phí theo event, có thể rất lớn |
| Insights events | Pattern rate/error API bất thường phát hiện bằng ML | Tắt — phải bật | Tí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.
- Config rules — kiểm tra trạng thái mong muốn, hoặc AWS-managed (ví dụ
s3-bucket-public-read-prohibited,encrypted-volumes) hoặc custom (Lambda / Guard). Tài nguyên được đánh dấuCOMPLIANThoặcNON_COMPLIANT. - Remediation — một tài nguyên non-compliant có thể kích hoạt một tài liệu SSM Automation tự động (ví dụ bật lại encryption, xóa một public ACL).
- Conformance packs — một gói các Config rule + remediation triển khai như một đơn vị, ánh xạ tới một framework (PCI-DSS, CIS, HIPAA). Triển khai qua StackSets khắp org cho guardrail nhất quán.
- Configuration timeline — với bất kỳ tài nguyên nào, xem chính xác nó trông thế nào tại bất kỳ thời điểm quá khứ và cái gì đã thay đổi nó, vô giá trong lúc xử lý sự cố.
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.
- Instrumentation — X-Ray SDK hoặc, ngày càng nhiều, OpenTelemetry qua ADOT. API Gateway, Lambda, và App Mesh có thể phát trace với ít code.
- Sampling — bạn không bao giờ trace 100% traffic volume lớn; một sampling rule giữ một tỷ lệ cố định (ví dụ 1 req/giây + 5% phần còn lại) để kiểm soát chi phí mà vẫn bắt được bất thường.
- Annotations vs. metadata — annotation là cặp key/value được index để bạn filter trace (ví dụ
customerTier=premium); metadata là context bổ sung không được index.
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 và đế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
- Đặ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 đó).
- 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ổ”
parsenhiều phút thành truy vấn một dòng và cho phép EMF metrics miễn phí. - 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.
- 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/breachingtheo 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. - 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ồ.
- Dùng EMF thay vì
PutMetricDatatrê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. - 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ủ.
- Đị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.
- 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ó.
- 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.
- 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.
- 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.
- 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ờ.
- 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.
- 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.
- 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
- Amazon CloudWatch User Guide
- CloudWatch Logs Insights query syntax
- CloudWatch Embedded Metric Format (EMF)
- Creating CloudWatch alarms
- Amazon EventBridge User Guide
- AWS CloudTrail User Guide
- AWS Config Developer Guide
- AWS Config conformance packs
- AWS X-Ray Developer Guide
- AWS Distro for OpenTelemetry
- CloudWatch Container Insights
- AWS Well-Architected — Operational Excellence Pillar
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
| Pillar | Question it answers | AWS service | Data shape |
|---|---|---|---|
| Metrics | Is it healthy? How much? | CloudWatch Metrics | Numeric time series with dimensions |
| Logs | What exactly happened? | CloudWatch Logs | Timestamped text/JSON events |
| Traces | Where did the time/error go? | X-Ray / ADOT | Spans 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/EC2 → CPUUtilization → {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.
- Namespaces — a container for metrics. AWS services use
AWS/<Service>(e.g.AWS/Lambda); your own use anything else (e.g.MyApp/Checkout). - Dimensions — up to 30 name/value pairs that scope a metric. More dimensions = more series = finer slicing but higher cost.
- Resolution — standard metrics are 1-minute granularity; high-resolution custom metrics go down to 1 second (more expensive).
- Statistics — you never store raw points forever; you query aggregations (
Average,Sum,p99,Maximum) over a period. Percentiles (p90,p99) matter far more than averages for latency.
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:
- Period + Evaluation periods + Datapoints to alarm — “3 of 5 five-minute periods above threshold” avoids flapping on a single spike.
- Treat missing data —
notBreaching,breaching,ignore, ormissing; wrong choice here causes false alarms or silent blind spots. - Composite alarms — combine child alarms with
AND/ORso you page only when several conditions hold (e.g. high latency AND high error rate), cutting alert noise. - Anomaly detection — CloudWatch trains a band of expected values; you alarm on deviation instead of a fixed threshold, which suits metrics with daily/weekly seasonality.
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 type | What it captures | Default | Cost |
|---|---|---|---|
| Management events | Control-plane ops (create/delete/modify, console logins, IAM changes) | Logged, last 90 days free in Event history | First copy free to a trail |
| Data events | High-volume data-plane ops (S3 GetObject, Lambda Invoke, DynamoDB item ops) | Off — opt in | Billed per event, can be large |
| Insights events | ML-detected unusual API rate/error patterns | Off — opt in | Extra 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.
- Config rules — desired-state checks, either AWS-managed (e.g.
s3-bucket-public-read-prohibited,encrypted-volumes) or custom (Lambda / Guard). Resources are flaggedCOMPLIANTorNON_COMPLIANT. - Remediation — a non-compliant resource can trigger an automatic SSM Automation document (e.g. re-enable encryption, remove a public ACL).
- Conformance packs — a bundle of Config rules + remediations deployed as a single unit, mapped to a framework (PCI-DSS, CIS, HIPAA). Deploy via StackSets across the org for consistent guardrails.
- Configuration timeline — for any resource, see exactly how it looked at any past moment and what changed it, which is invaluable during incidents.
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.
- Instrumentation — the X-Ray SDK or, increasingly, OpenTelemetry via ADOT. API Gateway, Lambda, and App Mesh can emit traces with minimal code.
- Sampling — you never trace 100% of high-volume traffic; a sampling rule keeps a fixed rate (e.g. 1 req/sec + 5% of the rest) to control cost while still catching anomalies.
- Annotations vs. metadata — annotations are indexed key/values you can filter traces by (e.g.
customerTier=premium); metadata is unindexed extra context.
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
- 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).
- Emit structured JSON logs, not free text. Rationale: Logs Insights can filter and aggregate on fields directly, turning multi-minute
parsearchaeology into one-line queries and enabling EMF metrics for free. - 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.
- Require multiple datapoints and set “treat missing data” deliberately. Use “M of N” evaluation and choose
notBreaching/breachingper metric. Rationale: single-datapoint alarms flap and cause pager fatigue; the wrong missing-data policy causes false alarms or silent blind spots. - 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.
- Use EMF instead of
PutMetricDataon 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. - 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
- Amazon CloudWatch User Guide
- CloudWatch Logs Insights query syntax
- CloudWatch Embedded Metric Format (EMF)
- Creating CloudWatch alarms
- Amazon EventBridge User Guide
- AWS CloudTrail User Guide
- AWS Config Developer Guide
- AWS Config conformance packs
- AWS X-Ray Developer Guide
- AWS Distro for OpenTelemetry
- CloudWatch Container Insights
- AWS Well-Architected — Operational Excellence Pillar