目次
7 章

CloudWatch 入門 — ログ / メトリクス

CloudWatch Logs / Metrics / Alarms / Dashboards の構造、ロググループと retention、Metric Filter、Logs Insights クエリの基礎まで — すべての運用の目となる観測ツールを整理します。

第2章 から 第6章 までで AWS セットアップの基盤が集まりました。アカウント、IAM、コスト、CLI、SSO、セキュリティ — コンソールに入る前の頭の中の地図と日常のセットアップがひと通り整いました。いよいよ運用のもう一つの軸、何がどこで何をしているかを見る道具を扱います。

CloudWatch は AWS の観測(Observability)の標準です。AWS の中のほぼすべてのサービスがデフォルトでメトリクスを CloudWatch へ送り、ログも CloudWatch Logs が受け取ります。運用の最初の視界はここから始まります。

本章は1部の最後の章として、CloudWatch の4つの構成 — Logs / Metrics / Alarms / Dashboards — を整理します。より深い観測は 第26章 モニタリングと X-Ray で分散トレーシングとともに続きます。

大きな絵 — CloudWatch の4つの構成 #

構成要素何かよくある使いどころ
Logsテキストログの保存 / 検索EC2 / Lambda / ECS / API Gateway のログ
Metrics時系列の数値 (CPU%、リクエスト数など)すべての AWS サービスが自動送信
Alarmsメトリクスがしきい値を超えると通知 / アクション運用通知、自動スケール
Dashboardsグラフ / ウィジェットのページチーム / サービス別の一覧表示

この4つはログ → メトリクス → アラーム → ダッシュボードの順につながります。

CloudWatch Logs #

ロググループとログストリーム #

構造
Log Group           — 通常は一つのアプリケーション / サービス単位
  └── Log Stream    — 通常は一つのプロセス / コンテナ単位
        └── Log Event — 1行
項目
Log Group/aws/lambda/my-function, /ecs/my-service, /var/log/myapp
Log StreamLambda 実行環境 ID、ECS Task ID、EC2 インスタンス ID
Log Event1行のテキスト + timestamp

Lambda と ECS Fargate は自動でログを CloudWatch Logs へ送ります。EC2 は CloudWatch Agent または補助ツール(fluent-bit など)が必要です。

Retention — 最も重要な設定 #

デフォルトの retention は永久です。そのまま置くとログが永遠に溜まって費用が暴走します。登録直後、そして新しいロググループごとに retention を定める必要があります。

項目推奨 retention
一般アプリケーションのログ30 ~ 90日
デバッグ / 開発のログ7日
セキュリティ / 監査のログ (CloudTrail)1 ~ 7年 (S3 へ送る方が安い)
Lambda のログ14 ~ 30日
retention の設定
aws logs put-retention-policy \
  --log-group-name /aws/lambda/my-function \
  --retention-in-days 30
すべてのロググループに一括適用
aws logs describe-log-groups --query 'logGroups[].logGroupName' --output text \
  | tr '\t' '\n' \
  | while read name; do
      aws logs put-retention-policy --log-group-name "$name" --retention-in-days 30
    done

この設定一つで CloudWatch のコスト事故の半分以上を防げます(第3章 コスト管理 のログ暴走の事故も、この設定で解消されます)。

新しいロググループの自動 retention #

新しく作られるロググループに自動で retention を適用する方法は2つあります。一つ目は EventBridge + Lambda で、CreateLogGroup イベントを受けて自動適用する方式で、実戦でよく使います。二つ目はポリシーで強制して、作るときに retention を明示しなければ拒否する方式ですが、少し強めです。

Lambda のログを送る #

Lambda — ただ print
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def handler(event, context):
    logger.info("Received event: %s", event)
    return {"ok": True}

stdout / stderr が自動で CloudWatch Logs へ流れます。ロググループの名前は /aws/lambda/<関数名> です。

EC2 / ECS — CloudWatch Agent #

EC2 は自動ではありません。CloudWatch Agent のインストールが必要です。

Amazon Linux 2023 / Ubuntu
sudo yum install -y amazon-cloudwatch-agent       # AL
# または
wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i amazon-cloudwatch-agent.deb

設定ファイルは /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json です。

簡単な設定
{
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/myapp/*.log",
            "log_group_name": "/myapp/server",
            "log_stream_name": "{instance_id}",
            "retention_in_days": 30
          }
        ]
      }
    }
  },
  "metrics": {
    "metrics_collected": {
      "mem":  { "measurement": ["mem_used_percent"] },
      "disk": { "measurement": ["used_percent"], "resources": ["*"] }
    }
  }
}

ECS の Fargate はコンテナ定義に awslogs ドライバーを書けば自動です。これは 第15章 ECS と Fargate で詳しく扱います。

Logs Insights — クエリで検索 #

CloudWatch Logs の検索 / 分析ツールです。SQL に似た独自の文法を使います。

最も単純なクエリ
fields @timestamp, @message
| sort @timestamp desc
| limit 100
ERROR だけ
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 50
リクエスト時間の分布 (Lambda)
fields @timestamp, @duration
| filter @type = "REPORT"
| stats avg(@duration), max(@duration), count(*) by bin(5m)
API Gateway — 5xx 比率
fields @timestamp, status, path
| filter status >= 500
| stats count(*) as errors by path
| sort errors desc

よく使うコマンドは次のとおりです。

コマンド何か
fields表示するフィールド
filter条件フィルター
parse文字列からフィールドを抽出
stats集計 (count, avg, max, percentile)
sortソート
limit最大結果数
bin(5m)時間バケット

Logs Insights の費用に注意 #

クエリ時にスキャンしたデータの GB あたり課金されます(~$0.005/GB)。大きなロググループを無制限の時間でクエリすると費用事故が起こります。常に時間範囲を狭く取ります。

CloudWatch Metrics #

メトリクスは時系列の数値です。AWS のほぼすべてのサービスが自動送信します。

よく見るメトリクス #

サービスよく見るメトリクス
EC2CPUUtilization, NetworkIn/Out, DiskReadOps
RDSCPUUtilization, DatabaseConnections, FreeStorageSpace, ReadLatency
LambdaInvocations, Errors, Duration, Throttles, ConcurrentExecutions
ECSCPUUtilization, MemoryUtilization (Service / Task 別)
ALBRequestCount, TargetResponseTime, HTTPCode_Target_5XX_Count
API GatewayCount, Latency, 4XXError, 5XXError
S3BucketSizeBytes, NumberOfObjects (1日1回)
DynamoDBConsumedReadCapacity/WriteCapacity, ThrottledRequests

メトリクスのディメンション (Dimensions) #

同じメトリクスでもディメンションで分解されます。

例: CPUUtilization
Service: AWS/EC2
Metric:  CPUUtilization
Dimensions:
  - InstanceId: i-1234567890
  - InstanceId: i-2345678901
  - InstanceId: i-3456789012

ディメンションが異なれば別のメトリクスです。メトリクスの数がすなわち費用なので、ディメンションが爆発すると費用事故が起こります。

統計 (Statistic) #

統計何か
Sum合計 — Invocations、RequestCount
Average平均 — CPU、Latency
Maximum最大 — Spike 検知
Minimum最小
p95 / p99パーセンタイル — Latency
SampleCountデータポイントの数

ほとんどの場合、Average + p95 が意味を持ちます。p99 / p99.9 は SLA とユーザー体験に直接影響を与えます。

標準 vs 高解像度 #

種類解像度費用
標準1分標準
高解像度1秒高価 — スパイクが短い場合だけ

ほとんど標準1分で十分です。

カスタムメトリクスを送る #

アプリケーションが直接送信します。

Python — boto3
import boto3

cloudwatch = boto3.client("cloudwatch")
cloudwatch.put_metric_data(
    Namespace="MyApp",
    MetricData=[{
        "MetricName": "OrderCreated",
        "Value": 1,
        "Unit": "Count",
        "Dimensions": [
            {"Name": "Environment", "Value": "prod"},
            {"Name": "Region", "Value": "ap-northeast-2"},
        ],
    }],
)

費用はメトリクスあたり $0.30 / 月で、ディメンションの組み合わせごとに別です。ユーザー ID のような高カーディナリティのディメンションは絶対に禁止します。

EMF (Embedded Metric Format) — Lambda 用のパターン #

Lambda では put_metric_data の呼び出し自体が費用と遅延の負担です。ログに特定の JSON 形式で書くと、CloudWatch が自動でメトリクスに変換します。

EMF 形式
import json
print(json.dumps({
    "_aws": {
        "Timestamp": int(time.time() * 1000),
        "CloudWatchMetrics": [{
            "Namespace": "MyApp",
            "Dimensions": [["Environment"]],
            "Metrics": [{"Name": "OrderCreated", "Unit": "Count"}],
        }],
    },
    "Environment": "prod",
    "OrderCreated": 1,
}))

aws-embedded-metrics-python のような SDK がこれをよりきれいに助けてくれます。

Metric Filter — ログからメトリクスを作る #

すでにログにある情報(ERROR の発生、応答時間など)をメトリクスに変換します。

コンソールで作る
CloudWatch → Log groups → グループを選択 → Metric filters → Create
- Filter pattern: ERROR
- Metric namespace: MyApp
- Metric name: ErrorCount
- Metric value: 1

これで ERROR が一度発生するたびにメトリクスが +1 されます。アラームやダッシュボードに活用できます。

Filter pattern の例
ERROR                       # ERROR の単語を含む
[..., level="ERROR", ...]   # 構造化ログのフィールド
{ $.level = "ERROR" }       # JSON ログのキー

CloudWatch Alarms #

メトリクスがしきい値を超えるとアクションをします。通知の本拠地です。

最初のアラーム — Lambda Errors #

コンソール
CloudWatch → Alarms → Create alarm
- Metric: AWS/Lambda → Errors → Function: my-function
- Statistic: Sum
- Period: 1 minute
- Threshold: > 0 for 1 datapoint within 5 minutes
- Action: SNS → 通知トピック
- Name: lambda-my-function-errors

Alarm の状態 #

状態意味
OKしきい値内
ALARMしきい値超過 — アクション発生
INSUFFICIENT_DATAデータ不足 — 新しく作った場合 / メトリクスが来ない

INSUFFICIENT_DATA をアラーム処理(通知)するかは任意です。新しいアラームの評価中によく出る状態なので、一般的には無視します。

Composite Alarms #

複数のアラームの AND / OR で組み合わせます。「ALB 5xx ≥ 1% AND CPU > 80%」のようなパターンです。

組み合わせの例
ALARM("alb-5xx") AND ALARM("ec2-high-cpu")

誤検知を減らすのに効果的です。

Alarm アクション #

アクション何か
SNS Topicメール / Slack / SMS / Lambda などへ fanout
EC2 Actionインスタンスの stop / terminate / reboot / recover
Auto ScalingASG のスケール in / out
Systems ManagerOpsItem を作る

運用通知の大半は SNS → Slack / メールです。

Anomaly Detection #

基準線(band)を自動で学習した後、その外ならアラームを出します。トラフィックや CPU のようにパターンのあるメトリクスに効果的で、静的なしきい値より誤検知が少ないです。

SNS 統合 — 通知を送る方法 #

ほとんどのアラームが SNS Topic へ行き、そこから次の段階へ fanout します。

サブスクリプションどこへ
Emailメール
HTTPSSlack incoming webhook
Lambda加工後に別の段階
SMS携帯電話 (まれに)
SQSキューへ

Slack 連携 — Lambda パターン #

直接 webhook で送るか、AWS Chatbot で送ります。

Lambda — SNS → Slack 変換
import json, os, urllib.request

WEBHOOK = os.environ["SLACK_WEBHOOK"]

def handler(event, context):
    msg = json.loads(event["Records"][0]["Sns"]["Message"])
    payload = json.dumps({
        "text": f"🚨 *{msg['AlarmName']}* — {msg['NewStateValue']}",
        "blocks": [...]
    }).encode()
    req = urllib.request.Request(WEBHOOK, data=payload,
                                  headers={"Content-Type": "application/json"})
    urllib.request.urlopen(req)

第18章 API Gateway と Lambda第19章 EventBridge / SQS / SNS でより深く扱います。

CloudWatch Dashboards #

ウィジェットのページです。チーム / サービス別の一覧表示に使います。JSON で定義してコードで管理できます。

よく作るダッシュボード #

種類何か
サービスダッシュボード一つのサービスの核心メトリクス (リクエスト、遅延、エラー、インフラ)
インフラダッシュボードEC2/RDS の CPU / メモリ / ネットワーク
ビジネスダッシュボード登録 / 決済 / 注文のようなビジネスメトリクス
オンコールダッシュボードアクティブなアラーム / 最近の事故 / 核心指標

ウィジェットの種類 #

  • メトリクスグラフ(line、stacked、number)
  • ログ(Logs Insights クエリの結果)
  • テキスト(Markdown — ダッシュボードの案内)
  • Alarm status

良いダッシュボードは「この1ページを30秒見ればシステムの状態が分かる」になることです。

登録直後にオンにすべき設定 #

1部が終わる時点では、次の設定が揃っているべきです。

項目どこで
新しいロググループに retention を自動適用コンソール / EventBridge + Lambda
Lambda Errors アラーム関数ごと
RDS FreeStorageSpace アラームDB ごと
ALB 5xx アラームLB ごと
ビリングアラーム (第3章 コスト管理)アカウント単位
GuardDuty findings アラーム (第6章 セキュリティ基本)アカウント単位

この6つが小さな運用の通知基盤です。

よく出会う落とし穴 #

  • ログの retention が永久 — 最もよくある費用事故です。ロググループごとに retention を明示し、新しいグループは自動化します。この設定一つで費用を半分以上節約できます。
  • 高カーディナリティのカスタムメトリクスDimensions: [{Name: 'UserId', Value: user_id}] のようにすると、ユーザー1万人のときメトリクス1万個 × ディメンションの組み合わせで1ヶ月 $3000+ になります。ユーザー別はログ(Logs Insights)が答えです。
  • Logs Insights の無制限の時間クエリ — 大きなロググループに時間範囲を定めないと GB 単位のスキャン費用がかかります。常に時間範囲を狭く取ります。
  • Alarm の Period が短すぎる — 1分1データポイントでアラームをかけると、一時的な spike のたびにアラームが暴走します。通常は5分 / 3データポイント程度がノイズを適度に減らします。
  • Alarm アクションを付けない — アラームを作って SNS やアクションを付けないと、コンソールでだけ赤くなります。誰も知りません。作るときにアクションを一緒に付けます。
  • ダッシュボードだけ作って見ない — 作った直後は全員見ますが、時間が経つと忘れられます。オンコールや日々のスタンドアップの最初のチェック項目として定着させます。
  • Metric Math の未使用 — 複数のメトリクスの比率 / 合計 / 変換を計算できる Metric Math があります。「5xx / 総リクエスト = エラー率」のような計算です。うまく使えばダッシュボードとアラームがずっときれいになります。

練習問題 #

  1. §「Retention — 最も重要な設定」の一括適用スクリプトを自分の環境で dry-run として読んでみて、この設定が 第3章 コスト管理 の「ログの暴走」の事故をどう防ぐかを一段落で説明してみましょう。
  2. §「CloudWatch Metrics」のよく見るメトリクスの表で Lambda と ALB の行を選び、それぞれどのメトリクスにアラームをかければ最初の運用事故を捕まえられるかを §「登録直後にオンにすべき設定」の表と結びつけて書いてみましょう。
  3. §「高カーディナリティのカスタムメトリクス」の落とし穴を根拠に、ユーザー別の注文数を追跡したいときにカスタムメトリクスの代わりに Logs Insights を使うべき理由を費用の観点から説明してみましょう。

一行まとめ: CloudWatch は Logs · Metrics · Alarms · Dashboards の4構成で運用の目となり、ログからダッシュボードまで一続きでつながります。ログの retention を明示しなければ費用が暴走するので、登録直後の設定が必須です。メトリクスはディメンションの数がそのまま費用なので高カーディナリティのディメンションを禁止し、アラームは SNS アクションを必ず付けてこそ意味があります。

次の章 #

これで1部「AWS のはじまり」が終わりました。コンソール / アカウント / IAM / コスト / CLI / SSO / セキュリティ / CloudWatch — AWS の上で何かを始めるのに必要な道具箱がひとまとまりになりました。いよいよ本物のリソースを作る番です。2部の最初の章である 第8章 EC2 と VPC では、仮想マシン EC2 と、その EC2 が住む仮想ネットワーク VPC — Subnet / Internet Gateway / Route Table / Security Group / NACL — の構造を一筋に整理します。

X