CloudWatch が PromQL 対応したので、Amazon Managed Grafana から接続してみた

CloudWatch が PromQL 対応したので、Amazon Managed Grafana から接続してみた

新規構築で無ければ、Amazon Managed Prometheus の出番は割と減るのでは?
2026.11.08

概要

2026 年 4 月に CloudWatch が OpenTelemetry メトリクスのネイティブサポートと、PromQL によるクエリに対応しました (GA は 6 月)。

https://aws.amazon.com/jp/blogs/news/introducing-opentelemetry-promql-support-in-amazon-cloudwatch/

従来 Grafana で CloudWatch データソースを使う場合は Metrics Insights など CloudWatch 独自のクエリ構文が必要でしたが、今後は PromQL でメトリクスを扱えるようになります。

cloudwatch-promql-grafana.png

PromQL は AWS 外でも汎用的に利用可能なクエリ言語であるため、後から AWS 外のデータソースを追加した際も同じ構文を利用できるメリットがあります。
また、ラベル付きの時系列データに対して柔軟な集計がしやすい特徴があるため、Metrics Insights よりクエリを書きやすいと感じる可能性が高いです。
特に EKS では、最初は CloudWatch Container Insights の組み込みダッシュボードを使い、必要に応じて後から Grafana に移行する方針を採用することができるため、メリットが大きいです。

Untitled(110).png

https://dev.classmethod.jp/articles/otel-container-insights-for-eks/

利用する Grafana データソースと制約条件について

CloudWatch で PromQL を利用する場合、https://monitoring.{REGION_NAME}.amazonaws.com に対して Sigv4 認証を使ってクエリを投げれば良いです。
この条件を満たしていれば Amazon Managed Grafana 以外 (セルフホスト、Grafana Cloud) も利用可能です。
また、Grafana データソースとしても CloudWatch データソースと、Amazon Managed Service for Prometheus データソース (AMP データソース) の両方を使うことができます。
Amazon Managed Service for Prometheus を利用しているわけでは無いのに AMP データソースを使うのは若干ややこしいですが、Sigv4 認証が通れば良いということでしょう。
ただし、対応している Grafana バージョンを利用している場合は CloudWatch データソースを使うことが推奨されます。

We recommend that you use the PromQL query type in the Amazon CloudWatch data source plugin.
https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-PromQL-Grafana.html

フローにすると下記のようになります。

基本的には CloudWatch データソースを選べば良いものの、2026 年 11 月時点では利用ユーザーが多そうな Amazon Managed Grafana v12.4 を利用している場合は AMP データソースが必要なので注意が必要です。

やってみた

セットアップ

今回は Amazon Managed Grafana (AMG) v13.2 を利用します。
EKS v1.37 に CloudWatch オブザーバビリティアドオンをインストールし、CloudWatch に OpenTelemetry メトリクスを発行します。

eks-grafana-cloudwatch.png

下記のように Counter を定義して、リクエストごとにカスタムメトリクスをカウントします。

_meter = _meter_provider.get_meter("demo-app")
REQUESTS = _meter.create_counter(
    "demo_http_requests_total",
    description="HTTP requests",
    unit="{request}",
)

カスタムメトリクスは CloudWatch エージェントに OTLP で転送し、CloudWatch の OTLP メトリクスエンドポイントに送信します。

_OTLP_METRICS_ENDPOINT = os.environ.get(
    "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
    "http://cloudwatch-agent.amazon-cloudwatch:4318/v1/metrics",
)
利用した Python アプリケーション
"""Demo app for CloudWatch OTel metrics, logs, and traces.

Metrics: OpenTelemetry SDK → CloudWatch agent OTLP (4318) → CloudWatch OTel Metrics.
Traces: Application Signals auto-instrumentation
(instrumentation.opentelemetry.io/inject-python). A local MeterProvider is used so
ADOT inject cannot replace app metrics.
Logs include the current trace_id when the injected OpenTelemetry SDK is present.
"""

from __future__ import annotations

import asyncio
import json
import logging
import os
import random
import time

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse, PlainTextResponse
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk.resources import Resource

_OTLP_METRICS_ENDPOINT = os.environ.get(
    "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
    "http://cloudwatch-agent.amazon-cloudwatch:4318/v1/metrics",
)
_EXPORT_INTERVAL_MS = int(os.environ.get("OTEL_METRIC_EXPORT_INTERVAL", "15000"))

# Keep the provider at module scope so the periodic reader is not garbage-collected.
# Do not call metrics.set_meter_provider(): ADOT inject may already own the global.
_meter_provider = MeterProvider(
    resource=Resource.create(
        {
            "service.name": os.environ.get("OTEL_SERVICE_NAME", "demo-app"),
            "service.namespace": "demo-app",
        }
    ),
    metric_readers=[
        PeriodicExportingMetricReader(
            OTLPMetricExporter(endpoint=_OTLP_METRICS_ENDPOINT),
            export_interval_millis=_EXPORT_INTERVAL_MS,
        )
    ],
)
_meter = _meter_provider.get_meter("demo-app")
REQUESTS = _meter.create_counter(
    "demo_http_requests_total",
    description="HTTP requests",
    unit="{request}",
)
LATENCY = _meter.create_histogram(
    "demo_http_request_duration_seconds",
    description="HTTP request duration in seconds",
    unit="s",
)

def _trace_fields() -> dict[str, str]:
    try:
        from opentelemetry import trace

        ctx = trace.get_current_span().get_span_context()
        if ctx is None or not ctx.is_valid:
            return {}
        return {
            "trace_id": format(ctx.trace_id, "032x"),
            "span_id": format(ctx.span_id, "016x"),
        }
    except Exception:
        return {}

class JsonFormatter(logging.Formatter):
    def format(self, record: logging.LogRecord) -> str:
        payload = {
            "level": record.levelname,
            "logger": record.name,
            "message": record.getMessage(),
            **_trace_fields(),
        }
        if record.exc_info:
            payload["exception"] = self.formatException(record.exc_info)
        return json.dumps(payload, ensure_ascii=False)

def configure_logging() -> None:
    handler = logging.StreamHandler()
    handler.setFormatter(JsonFormatter())
    root = logging.getLogger()
    root.handlers.clear()
    root.addHandler(handler)
    root.setLevel(logging.INFO)
    logging.getLogger("uvicorn.access").handlers.clear()

configure_logging()
log = logging.getLogger("demo-app")

app = FastAPI(title="demo-app", docs_url=None, redoc_url=None)

@app.middleware("http")
async def record_metrics(request: Request, call_next):
    started = time.perf_counter()
    response = await call_next(request)
    path = request.url.path
    method = request.method
    status = str(response.status_code)
    REQUESTS.add(1, {"method": method, "path": path, "status": status})
    LATENCY.record(time.perf_counter() - started, {"method": method, "path": path})
    return response

@app.get("/healthz", response_class=PlainTextResponse)
async def healthz() -> str:
    return "ok\n"

@app.get("/")
async def root() -> dict[str, str]:
    log.info("handled GET /")
    return {"service": "demo-app", "status": "ok"}

@app.get("/work")
async def work() -> dict[str, object]:
    delay = random.uniform(0.05, 0.25)
    try:
        from opentelemetry import trace

        tracer = trace.get_tracer("demo-app")
        with tracer.start_as_current_span("do-work") as span:
            span.set_attribute("work.delay_seconds", delay)
            await asyncio.sleep(delay)
    except ImportError:
        await asyncio.sleep(delay)
    log.info("completed work delay=%.3f", delay)
    return {"ok": True, "delay": round(delay, 3)}

@app.get("/error")
async def error() -> JSONResponse:
    log.error("simulated error")
    return JSONResponse({"error": "boom"}, status_code=500)

アクセス許可タイプは「サービスマネージド」を選択し、権限付与は AMG に任せます。

スクリーンショット 2026-11-07 18.04.17.png

PromQL でメトリクスをクエリするだけなら AWS X-Ray は不要ですが、今回はついでにトレースも見たいので付与しておきます。
セルフホスト版などで CloudWatch データソースを利用する場合、権限としては cloudwatch:GetMetricData と cloudwatch:ListMetrics が必要になります。

IAM prerequisites — the IAM principal that the CloudWatch data source uses, such as the Amazon Managed Grafana workspace IAM role, must have both cloudwatch:GetMetricData (required for instant and range queries) and cloudwatch:ListMetrics (required for metric, label key, and label value autocomplete). For details, see IAM permissions for PromQL.
https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-PromQL-Grafana.html#CloudWatch-PromQL-Querying-CloudWatch-datasource

Grafana のコンソールにログインして、data source を追加します。

スクリーンショット 2026-11-07 18.11.17.png

CloudWatch をクリックします。

スクリーンショット 2026-11-07 18.12.24.png

AMG なので、Authentication は Workspace IAM Role のままで問題ありません。
Additional Settings > Endpoint は何も入力せずにデフォルトの https://{service}.{region}.amazonaws.com とします。
Default Region は ap-northeast-1 (メトリクスが溜まっているリージョン) を指定します。

スクリーンショット 2026-11-07 18.25.15.png

「Save & Test」をクリックします。

スクリーンショット 2026-11-07 18.14.56.png

最初 Additional Settings > Endpoint に https://monitoring.{REGION_NAME}.amazonaws.com を入力する必要があるのかと思ったのですが、指定すると CloudWatch logs query 側で CloudWatch logs query failed: operation error CloudWatch Logs: DescribeLogGroups, https response error StatusCode: 404 というエラーがでました。

スクリーンショット 2026-11-07 18.16.25.png

デフォルトのままにしておけば、ログとメトリクスのそれぞれのエンドポイントに良い感じに振り分けてくれるようです。

スクリーンショット 2026-11-07 18.28.59.png

ダッシュボード追加

ダッシュボードを追加していきます。

スクリーンショット 2026-11-07 18.29.25.png

今回はあらかじめ JSON を用意しおいたのでインポートを行います。

スクリーンショット 2026-11-07 18.29.57.png

一部を抜粋すると下記のようになります。
cloudwatch datasource に対して、promqlExpression を指定してクエリします。

    {
      "datasource": {
        "type": "cloudwatch",
        "uid": "${datasource}"
      },
      "fieldConfig": {
        "defaults": {
          "unit": "reqps"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 0
      },
      "id": 1,
      "title": "HTTP requests / sec (CloudWatch PromQL)",
      "type": "timeseries",
      "targets": [
        {
          "datasource": {
            "type": "cloudwatch",
            "uid": "${datasource}"
          },
          "queryMode": "Metrics",
          "metricQueryType": 2,
          "metricEditorMode": 1,
          "promqlExpression": "sum(rate(demo_http_requests_total[5m]))",
          "range": true,
          "instant": false,
          "legendFormat": "requests",
          "region": "default",
          "refId": "A"
        }
      ]
    },

ログはこれまで通り、Logs Insights を利用します。

    {
      "datasource": {
        "type": "cloudwatch",
        "uid": "${datasource}"
      },
      "gridPos": {
        "h": 12,
        "w": 24,
        "x": 0,
        "y": 16
      },
      "id": 5,
      "title": "Application logs (filter by trace_id in Explore if needed)",
      "type": "logs",
      "targets": [
        {
          "datasource": {
            "type": "cloudwatch",
            "uid": "${datasource}"
          },
          "queryMode": "Logs",
          "expression": "fields @timestamp, @message | filter kubernetes.namespace_name = \"demo-app\" or @logStream like /demo-app/ | sort @timestamp desc | limit 50",
          "logGroupNames": ["/aws/containerinsights/$cluster/application"],
          "refId": "A",
          "region": "default"
        }
      ]
    }
  ],
利用したダッシュボード
{
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": {
          "type": "grafana",
          "uid": "-- Grafana --"
        },
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "fiscalYearStartMonth": 0,
  "graphTooltip": 1,
  "id": null,
  "links": [],
  "liveNow": false,
  "panels": [
    {
      "datasource": {
        "type": "cloudwatch",
        "uid": "${datasource}"
      },
      "fieldConfig": {
        "defaults": {
          "unit": "reqps"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 0
      },
      "id": 1,
      "title": "HTTP requests / sec (CloudWatch PromQL)",
      "type": "timeseries",
      "targets": [
        {
          "datasource": {
            "type": "cloudwatch",
            "uid": "${datasource}"
          },
          "queryMode": "Metrics",
          "metricQueryType": 2,
          "metricEditorMode": 1,
          "promqlExpression": "sum(rate(demo_http_requests_total[5m]))",
          "range": true,
          "instant": false,
          "legendFormat": "requests",
          "region": "default",
          "refId": "A"
        }
      ]
    },
    {
      "datasource": {
        "type": "cloudwatch",
        "uid": "${datasource}"
      },
      "fieldConfig": {
        "defaults": {
          "unit": "s"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 0
      },
      "id": 2,
      "title": "Request latency (CloudWatch PromQL)",
      "type": "timeseries",
      "targets": [
        {
          "datasource": {
            "type": "cloudwatch",
            "uid": "${datasource}"
          },
          "queryMode": "Metrics",
          "metricQueryType": 2,
          "metricEditorMode": 1,
          "promqlExpression": "histogram_quantile(0.95, {\"demo_http_request_duration_seconds\", \"@resource.service.name\"=\"demo-app\"})",
          "range": true,
          "instant": false,
          "legendFormat": "p95",
          "region": "default",
          "refId": "A"
        },
        {
          "datasource": {
            "type": "cloudwatch",
            "uid": "${datasource}"
          },
          "queryMode": "Metrics",
          "metricQueryType": 2,
          "metricEditorMode": 1,
          "promqlExpression": "histogram_avg({\"demo_http_request_duration_seconds\", \"@resource.service.name\"=\"demo-app\"})",
          "range": true,
          "instant": false,
          "legendFormat": "mean",
          "region": "default",
          "refId": "B"
        }
      ]
    },
    {
      "datasource": {
        "type": "cloudwatch",
        "uid": "${datasource}"
      },
      "fieldConfig": {
        "defaults": {
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 8
      },
      "id": 3,
      "title": "Container CPU (OTel Container Insights)",
      "type": "timeseries",
      "targets": [
        {
          "datasource": {
            "type": "cloudwatch",
            "uid": "${datasource}"
          },
          "queryMode": "Metrics",
          "metricQueryType": 2,
          "metricEditorMode": 1,
          "promqlExpression": "sum(rate(container_cpu_usage_seconds_total[5m]))",
          "range": true,
          "instant": false,
          "legendFormat": "cpu",
          "region": "default",
          "refId": "A"
        }
      ]
    },
    {
      "datasource": {
        "type": "grafana-x-ray-datasource",
        "uid": "${xray}"
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 8
      },
      "id": 4,
      "title": "X-Ray traces (demo-app)",
      "type": "table",
      "targets": [
        {
          "datasource": {
            "type": "grafana-x-ray-datasource",
            "uid": "${xray}"
          },
          "queryType": "getTraceSummaries",
          "query": "service(\"demo-app\")",
          "region": "default",
          "refId": "A"
        }
      ]
    },
    {
      "datasource": {
        "type": "cloudwatch",
        "uid": "${datasource}"
      },
      "gridPos": {
        "h": 12,
        "w": 24,
        "x": 0,
        "y": 16
      },
      "id": 5,
      "title": "Application logs (filter by trace_id in Explore if needed)",
      "type": "logs",
      "targets": [
        {
          "datasource": {
            "type": "cloudwatch",
            "uid": "${datasource}"
          },
          "queryMode": "Logs",
          "expression": "fields @timestamp, @message | filter kubernetes.namespace_name = \"demo-app\" or @logStream like /demo-app/ | sort @timestamp desc | limit 50",
          "logGroupNames": ["/aws/containerinsights/$cluster/application"],
          "refId": "A",
          "region": "default"
        }
      ]
    }
  ],
  "refresh": "30s",
  "schemaVersion": 41,
  "tags": ["eks", "demo-app", "cloudwatch", "otel", "promql", "xray"],
  "templating": {
    "list": [
      {
        "hide": 0,
        "includeAll": false,
        "label": "CloudWatch (PromQL / logs)",
        "name": "datasource",
        "options": [],
        "query": "cloudwatch",
        "refresh": 1,
        "regex": "",
        "type": "datasource"
      },
      {
        "hide": 0,
        "includeAll": false,
        "label": "X-Ray",
        "name": "xray",
        "options": [],
        "query": "grafana-x-ray-datasource",
        "refresh": 1,
        "regex": "",
        "type": "datasource"
      },
      {
        "current": {
          "text": "eks-obs-demo",
          "value": "eks-obs-demo"
        },
        "hide": 0,
        "label": "Cluster",
        "name": "cluster",
        "query": "eks-obs-demo",
        "type": "textbox"
      }
    ]
  },
  "time": {
    "from": "now-1h",
    "to": "now"
  },
  "timepicker": {},
  "timezone": "browser",
  "title": "EKS demo-app (OTel metrics / logs / traces)",
  "uid": "eks-demo-app-observability",
  "version": 3,
  "weekStart": ""
}

インポートします。

スクリーンショット 2026-11-07 18.30.18.png

良い感じにダッシュボードが表示されました。
トレースは Application Signals データソースをインストールしていないので表示されておらず、後ほど設定します。

スクリーンショット 2026-11-07 18.33.06.png

先に各パネルの見え方をもう少し深ぼってみます。

スクリーンショット 2026-11-07 18.32.06.png

PromQL で定義できていますね。

スクリーンショット 2026-11-07 18.32.24.png

CloudWatch データソースは PromQL 前提になったわけでは無く、旧来の Metrics Search/Metrics Insights を利用することも可能な上で PromQL を追加で選択できるようになった形です。

スクリーンショット 2026-11-07 18.32.44.png

Metrics Insights を選べば従来通りの SQL のサブセットを利用できます。

スクリーンショット 2026-11-07 18.51.09.png

Metrics Search を使えば、CloudWatch のコンソールと大分近い使い勝手になります。

スクリーンショット 2026-11-07 18.53.43.png

ただし、OTLP エンドポイントから取り込んだメトリクスに対しては PromQL でクエリする必要があることと、AWS 提供メトリクスに PromQL でクエリするには OTel エンリッチメントが必要な点は注意が必要です。

スクリーンショット 2026-11-07 19.02.44.png

Application Signals データソースの追加

正直な所あまり PromQL とは関係無いのですが、せっかくなので CloudWatch に溜まったトレースも可視化しておきます。
CloudWatch データソースを使えばメトリクスとログはクエリできるので、トレースだけ個別設定が必要になります。

スクリーンショット 2026-11-07 18.32.41.png

Application Signals データソースはコアデータプラグイン扱いでは無いので、プラグイン管理を「オン」に設定して、データソースのインストールが必要になります。

スクリーンショット 2026-11-07 18.36.26.png

Connection > Add new connection から AWS Application Signals を追加します。

スクリーンショット 2026-11-07 18.31.30.png

スクリーンショット 2026-11-07 18.31.38.png

インストールできたら、Datasource からクリックして追加します。

スクリーンショット 2026-11-07 18.33.58.png

データソース設定を行い、Save & test をクリックします。
CloudWatch データソース同様、権限は Workspace IAM Role で良く、Default Region だけ設定しておきます。

スクリーンショット 2026-11-07 18.34.17.png

Data source is working と表示されたら成功です。

スクリーンショット 2026-11-07 18.34.28.png

改めてダッシュボードを見にいくと、ログ/トレース/メトリクスの全てを CloudWatch から確認できるようになりました。

スクリーンショット 2026-11-07 18.34.35.png

Amazon Managed Prometheus と CloudWatch の使い分けについて

さて、こうなってくると Amazon Managed Prometheus (AMP) との使い分けが非常に難しいですね。
個人的に最も制約になりそうになのはクエリの最大レンジが 7 日であることです。
例えば offset などを利用して、週や月単位で傾向の差分を見ようとするとすぐレンジ制限に抵触します。

スクリーンショット 2026-11-07 23.07.31.png

AMP が 95 日間のクエリ期間をサポートしていることを考えると、長期的な傾向を分析する場合はかなり使い勝手に差がでます。

https://aws.amazon.com/jp/about-aws/whats-new/2025/05/amazon-managed-service-prometheus-95-day-queries/

とはいえ、週ごとの傾向を比較をしたいのであれば、Time shift でずらしてパネルを並べたりもできますし、長期の分析用に S3 + Athena などを併用しても良いので、新規構築だとクリティカルにはならない気もします。
メトリクス最大保持期間も CloudWatch が 15 ヶ月、AMP は 3 年と差がありますが、これもクリティカルになるかと言えば微妙な気はします。
また、AMP は Alert Manager を利用することでアラートのグルーピングや、ラベルを利用したルーティング、通知の一時停止などが可能であり、この点は CloudWatch より柔軟な設定が可能です。
一方で、CloudWatch が直近 1 年で大きく改善した部分でもあるので、この部分の差はすぐ縮まるかもしれません。

https://dev.classmethod.jp/articles/amazon-cloudwatch-tags-on-alarm-actions-payload/

https://dev.classmethod.jp/articles/amazon-cloudwatch-alarm-muting-rules/

細かい制約は下記公式ドキュメントにまとまっており、CloudWatch と AMP から選択する際は一読をおすすめします。

https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-PromQL.html#CloudWatch-PromQL-Limits

CloudWatch 側は、OTel エンリッチメントを有効化すれば AWS 提供メトリクスとカスタムメトリクスを全く同じように扱えるメリットが大きいです。
Grafana 側で突合すれば良いため、AMP と OTel エンリッチメントを併用することも可能ですが、アーキテクチャがシンプルになるメリットは大きいです。
ここは何とも言い辛い部分ですが、直近は CloudWatch 側のアップデートの方が目立つという話もあります。
AWS 側のモチベーションとして、AMP と CloudWatch という Prometheus 互換のデータストアを並列で展開するメリットはあまり大きく無いように感じます。
そうなった場合、どちらかに開発の重心が寄り、クエリの最大レンジや保持期間といった性能に関する部分の比較は意味が無くなる可能性はあります (積極的に投資されている方の性能が高くなる可能性)。
とはいえ、現時点で完璧な選択をすることは難しい部分もあるため、アプリケーションからカスタムメトリクスを OTel Collector 相当のコンポーネントに転送する部分だけでも OTLP を採用しておけば最低限 OK という考え方もできます。
コスト面はかなり価格体系が違うのでケースバイケースとなります。
1 データポイントあたりのラベル数が多い場合は AMP の方が有利になりやすいです。
また、クエリ料金も AMP が有利になりやすいですが、CloudWatch コンソールからクエリする分は無料な点が特徴的です。
EKS 基盤のメトリクスを取り込む際は EKS Container Insights(OTel)だと単価が変わる点も注意が必要ですね。

項目 CloudWatch(OTel) AMP
取り込み $0.50 / GB $0.90 / 1,000万サンプル(最初の20億サンプル、以降は段階的に割引)
保存 15か月分込み $0.03 / GB・月
クエリ(API 経由) $0.01 / 100万サンプル $0.10 / 10億サンプル
クエリ(コンソール) 無料 ー
備考 EKS Container Insights(OTel)は $0.08 / GB マネージドコレクター利用時は別途課金

https://aws.amazon.com/jp/cloudwatch/pricing/

https://aws.amazon.com/jp/prometheus/pricing/

最後に

CloudWatch が PromQL 対応したので、Amazon Managed Grafana から接続してみました。
CloudWatch と AMP の比較は難しいですが、まずは CloudWatch を検討して、気になる制約があれば AMP といった選び方が良いように感じました。
特に EKS では悩ましいですが、EKS Container Insights(OTel)の取り込み料金の安さやセットアップの楽さは中々に魅力的です。
既存の AMP を CloudWatch に移行するメリットはあまり無いが、新規構築だと CloudWatch を優先して良さそう、ただし、AWS がどちらに注力しているかはちゃんと見ておく必要がある、みたいな感じでしょうか (難しい立ち回り...!)。
Google Cloud のように CloudWatch に Grafana ダッシュボードをインポートできたりするとさらに面白くなると思うので、今後の開発にも期待したいと思います!

https://docs.cloud.google.com/monitoring/dashboards/import-grafana-dashboards?hl=ja

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事