Generated banner for Setting Up Cloudwatch Observability
Generated logo for Setting Up Cloudwatch Observability

Setting Up Cloudwatch Observability

AWSOfficialPublished by AWS

  • Skill
  • Tool integration
  • Cloud and DevOps
  • Apache-2.0
  • Medium risk

From the author

Sets up CloudWatch observability for the first time - Omni (CloudWatch Application Observability) and classic CloudWatch. Omni: creating a Space or Domain; access grants (who has access, at what level), access profiles bounding alerts, integrations, agents; instrumenting an app or AI agent with the plain ADOT SDK so traces reach Omni (Python/Node/Java/.NET on EC2/ECS/EKS/Lambda), incl. no-image-rebuild, CoreCLR vars; ingesting Azure or Google Cloud telemetry via the CloudWatch agent (VM/AKS, GCE/GKE); connecting Slack or the AWS DevOps Agent to a Space; whether GitHub or a custom MCP tool server (HTTP/stdio) can connect. CloudWatch: onboarding a service to Application Signals: ADOT auto-instrumentation, amazon-cloudwatch-observability add-on, monitored service, ServiceEvents, CI/CD metadata, Terraform. For using what is set up - queries, dashboards, alarms, Omni alerts, X-Ray, synthetics, Dynamic Instrumentation, AI agent evaluation, detecting Omni vs classic - use aws-observability.
— the description by AWS

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides the end-to-end setup procedures for two distinct CloudWatch observability products: CloudWatch Application Observability (Omni) and classic CloudWatch Application Signals. It acts as a central routing hub, helping users identify the correct product based on their requirements and guiding them through the specific onboarding, instrumentation, and configuration steps for each. It covers resource creation, access management, and telemetry ingestion, while clearly delineating the boundaries between the two products to ensure correct implementation.

What it does

  • Routes setup requests to the correct product path based on user intent and environment.
  • Guides users through CloudWatch Omni Domain and Space creation, access grants, and profile configuration.
  • Provides instructions for instrumenting applications and AI agents with the ADOT SDK for Omni.
  • Details the onboarding process for classic CloudWatch Application Signals, including auto-instrumentation and add-ons.
  • Supports telemetry ingestion configuration for Azure and Google Cloud environments.
  • Manages integration setups for Slack and the AWS DevOps Agent.

When to use it

  • When you need to set up CloudWatch Application Observability (Omni) for the first time.
  • When you need to onboard a service to classic CloudWatch Application Signals.
  • When you are unsure which CloudWatch observability product is appropriate for your workload.
  • When you need to configure access grants, profiles, or integrations for an existing Space.
  • When you need to instrument an application or AI agent to export telemetry to CloudWatch.

Advantages

  • Prevents configuration conflicts by enforcing mutually exclusive setup paths for Omni and Application Signals.
  • Provides a structured, step-by-step sequence for complex resource hierarchies like Domains and Spaces.
  • Clarifies the distinction between setup tasks and day-to-day operational tasks.
  • Ensures correct principal resolution and permission scoping for access grants and profiles.

Usage examples

“How do I start setting up CloudWatch Application Observability?”
The agent will explain the setup order (Domain, Space, grants, telemetry) and direct you to the app-basics reference to begin.
“I need to onboard my EKS service to Application Signals.”
The agent will route you to the Application Signals onboarding guide and the specific EKS-language instrumentation steps.
“How do I give a team access to my CloudWatch Omni Space?”
The agent will guide you through resolving the principal and using the access-grants reference to configure the appropriate permission level.
“Can I connect my GitHub repository to CloudWatch Omni?”
The agent will clarify that Omni does not support GitHub integration and stop the setup process.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/aws/setting-up-cloudwatch-observability/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip setting-up-cloudwatch-observability.zip -d .agents/skills

Documentation by AWS

Setting Up CloudWatch Observability

Scope: First-time CloudWatch observability setup, for both products — a CloudWatch Application Observability (Omni) Space from creation through first traces flowing, and onboarding a service to classic CloudWatch Application Signals. For using what is already set up (queries, dashboards, alarms, Omni alerts, evaluations, live debugging), route to aws-observability.

Two products, two reference folders

This skill owns setup for two products that share the CloudWatch name but are separate services. The folder a reference lives in is the signal for which product it belongs to — the same convention aws-observability uses:

FolderProductWhat setup means there
references/cloudwatch-omni/CloudWatch Omni (Application / Agent Observability)Domain → Space → grants → telemetry in → plain ADOT SDK instrumentation. No add-on, no CloudWatch Agent application_signals config, no port 4316.
references/cloudwatch/Classic CloudWatchOnboarding a service to Application Signals: ADOT auto-instrumentation, the amazon-cloudwatch-observability EKS add-on, the CloudWatch Agent, monitored service, ServiceEvents, CI/CD git/deployment metadata, port 4316.

The two instrumentation paths are mutually exclusive on a given workload — the Omni path explicitly forbids the Application Signals env vars and the add-on, and vice versa. Decide the product first (Routing Rules 1–4 below), then stay inside that folder. Enabling one does not replace the other; an account may run both, on different services.

Works best with the AWS MCP server — enables running AWS CLI commands directly. All guidance also works with standard AWS CLI access (aws cloudwatchomni ... on the Omni path; aws eks, aws iam, and aws application-signals on the Application Signals path).

Concepts — Omni (references/cloudwatch-omni/)

These are Omni's resources. None of them exist on the Application Signals path — that one has no Domain, Space, grant, or Dataset; its unit is a monitored service, and access is plain IAM. Do not ask an Application Signals onboarding customer for a spaceId.

TermWhat it is
DomainThe identity boundary. Carries the authorization provider (IAM or Identity Center) and owns the endpoint URL customers reach Omni through. One per account, or one shared across an AWS Organization.
SpaceA workspace holding telemetry, in exactly one account and one Region. Created under a Domain. At most one per account per Region. Region rule: under an IAM-only Domain a Space may sit in a Region other than the Domain's; under an account-scoped Identity Center Domain the Space must be in the Domain's own Region; under an org-scoped Identity Center Domain it must be in a Region the instance is replicated to.
Access grantAttaches a principal — person, group, IAM identity, or async workload — to one Space at a permission level. The only way anyone reaches data through a Space — it does not restrict the source CloudWatch log groups, which stay readable under their own IAM.
Access ProfileA named boundary for async workloads (alerts, integrations, agents) that act without a person in the loop. It is only a named container: create-access-profile takes a Space, a name, and a description and nothing else — no permission, action, or scope input. It does something only once two separate sets of grants exist (what the profile may do; which workloads may assume it) and a workload names it.
DatasetWhat queries run against. Telemetry arrives through the CloudWatch OTLP endpoints, or by forwarding what is already in CloudWatch log groups.

Omni setup order from nothing: Domain → Space → grants → telemetry in → instrumentation. (The Application Signals equivalent is much shorter and has no prerequisite resources — add-on/agent, IAM, then the per-platform enablement change; see references/cloudwatch/application-signals-onboarding.md.) "Telemetry in" (a collector exporting to CloudWatch's OTLP endpoints, plus dataset forwarding for what is already in CloudWatch) is its own step, separate from instrumenting the workloads. Access Profiles are conditional, not a step in the sequence — only when async workloads (alerts, integrations, agents) are involved. Whenever you give this sequence, also say that instrumentation or forwarding started before a Space exists appears to succeed while delivering telemetry nowhere the customer can see — a customer who checks Omni first reads a working, empty Space as a failure. For the concept relationships and the full arc, see references/cloudwatch-omni/app-basics.md.

This is a routing skill. Classify the user's setup request and delegate to the correct reference. Omni references live under references/cloudwatch-omni/; classic-CloudWatch (Application Signals) references live under references/cloudwatch/.

User intentReference
Onboard a service to Application Signals (auto-instrumentation, the amazon-cloudwatch-observability EKS add-on, CloudWatch Agent IAM for Application Signals, monitored service, reporting telemetry to Application Signals, ServiceEvents, the two onboarding tiers)references/cloudwatch/application-signals-onboarding.md
Propagate ServiceEvents git/deployment metadata through CI/CD (the 5 OTEL_AWS_SERVICE_EVENTS_* vars, per-provider patterns)references/cloudwatch/application-signals-cicd-metadata.md
Per-platform × per-language Application Signals enablement steps once platform and language are knownThe matching references/cloudwatch/appsignals-guides/<platform>-<language>.md (e.g. references/cloudwatch/appsignals-guides/eks-python.md)
Turn on Dynamic Instrumentation for a service at onboarding time (the OTEL_AWS_DYNAMIC_INSTRUMENTATION_* vars and their IAM)references/cloudwatch/application-signals-onboarding.md (Step 5d). Using it to debug is aws-observability
Understand what Omni is, its concepts, or where to startreferences/cloudwatch-omni/app-basics.md
Instrument an AI agent (ADOT, OpenInference, framework detection, trace verification), or deploy an agent to production and get traces flowing to CloudWatch — env vars per platform (AgentCore, Lambda, or other platforms such as ECS/EC2/EKS), routing spans to a custom trace log group, IAM permissions needed, how the export authenticates (AWS credentials, no API token), ADOT version requirementsreferences/cloudwatch-omni/omni-agents-instrumentation/omni-agents-instrumentation.md (§ Production deployment for the deploy case)
Per-framework OpenInference guide (LangChain, LangGraph, Strands, CrewAI, OpenAI Agents, Vercel AI) once the agent framework is knownreferences/cloudwatch-omni/omni-agents-instrumentation/openinference-framework-guide.md, then the matching references/cloudwatch-omni/omni-agents-instrumentation/instrument-<framework>.md
Instrument an application (ADOT SDK on EC2/ECS/EKS/Lambda — Python, Node.js, Java, .NET)references/cloudwatch-omni/instrumentation/instrumentation.md
Emit a custom application or agent metric so it is queryable in Omni (why OTLP and not PutMetricData/EMF)references/cloudwatch-omni/instrumentation/instrumentation.md (§ Custom metrics)
Create an account-scoped Space or Domainreferences/cloudwatch-omni/spaces-and-domains.md
Whether a Space can be in a different Region from its Domainreferences/cloudwatch-omni/spaces-and-domains.md (Prerequisites → Region rules)
The AgentCore evaluation role that create-space asks for — what it is, whether to create onereferences/cloudwatch-omni/spaces-and-domains.md (Step 3 → Also resolve the AgentCore evaluation role)
Let Omni run Bedrock models for a Space (Agent Playground, evaluations run from Omni), or a Bedrock AccessDeniedException from those featuresreferences/cloudwatch-omni/spaces-and-domains.md (Step 3 → Optional: let Omni invoke Bedrock models)
A Space that was created successfully but returns an authorization error when usedreferences/cloudwatch-omni/spaces-and-domains.md (Troubleshooting → If the Space was created but cannot be used) — a space access role trust-policy problem, not a grant problem
Create a Domain shared across an AWS Organizationreferences/cloudwatch-omni/org-domains.md
Configure access grants for people or IAM identities or alertsreferences/cloudwatch-omni/access-grants.md
An aws cloudwatchomni command reporting that the service is not supported, or a request to repair the customer's CLI or SDK so Omni commands workNot a setup task — a local client-version problem. STOP and route to aws-observability
A programmatic caller denied on a Space it already had working — a CI role, SDK client, CloudFormation role, coding agent, or a workload under an Access Profilereferences/cloudwatch-omni/access-grants.md (Grants, IAM, and Access Profiles), and aws-observability for the API-side view
Bound an alert, integration, or agent with an Access Profilereferences/cloudwatch-omni/access-profiles.md
Deploy an OTel Collector so an instrumented app has somewhere to export to (EC2/ECS/EKS) — it exports to CloudWatch's own per-signal OTLP endpointsreferences/cloudwatch-omni/instrumentation/collector.md
An OTLP collector already running (a CloudWatch Agent with an opentelemetry section or OTLP on 4317/4318, or otelcol-contrib) whose telemetry does not arrive, in whole or for one signal such as tracesreferences/cloudwatch-omni/instrumentation/collector.md (Verify), then the platform collector guide it links for the troubleshooting table
Enable Transaction Search so traces reach a Space (spans land in aws/spans only once it is on — per account, per Region)references/cloudwatch-omni/instrumentation/collector.md (Step 1)
Forward telemetry already in CloudWatch into the Datasetreferences/cloudwatch-omni/data-forwarding-and-centralization.md
Send your application's own telemetry from Azure (the logs/metrics/traces your service emits, via the CloudWatch agent on an Azure VM/AKS)references/cloudwatch-omni/azure-ingestion/azure-ingestion.md (intent triage), then references/cloudwatch-omni/azure-ingestion/custom-telemetry.md (the CloudWatch-agent-on-VM/AKS procedure)
Send your application's own telemetry from Google Cloud (the logs/metrics/traces your service emits, via the CloudWatch agent on a GCE instance/GKE cluster)references/cloudwatch-omni/gcp-ingestion/gcp-ingestion.md (intent triage), then references/cloudwatch-omni/gcp-ingestion/custom-telemetry.md (the CloudWatch-agent-on-GCE/GKE procedure)
Connect Slack to a Space for the first timereferences/cloudwatch-omni/slack-integration.md
Connect the AWS DevOps Agent to a Space (Settings → Integrations → AWS DevOps Agent), an empty agent-space picker, or Investigations reporting the AWS DevOps Agent is not connectedreferences/cloudwatch-omni/devops-agent-integration.md. Creating the DevOps Agent space itself and running or chatting with investigations belong to the aws-agents-for-devsecops plugin
Whether a custom MCP tool server can be registered (Omni has none)references/cloudwatch-omni/custom-mcp-integration.md
Enable or configure CloudWatch Omni Intelligence for a Space — attach an optional customer-managed KMS key (put-intelligence-configuration), connect an intelligence integration (AWS_INTEGRATION, AWS_CONFIG_SLREC, EXTERNAL_AGENT), check current config, or troubleshoot enablement (404, AccessDenied, empty graph)references/cloudwatch-omni/intelligence-setup.md

Routing Rules

  1. If the user is asking what Omni is, what a Domain or Space or grant means, where to start, or the end-to-end order of steps from nothing — rather than asking to perform one setup step — route to references/cloudwatch-omni/app-basics.md and answer the sequence from its "Setup order" section (not from a single procedure file such as collector.md, which covers one step). It also carries the boundary against aws-observability. A question about one concept's rules — a Space's Region relative to its Domain, the roles create-space needs — belongs to the procedure file for that concept (spaces-and-domains.md), which the routing table names.

  2. If the request is about instrumenting an AI agent project (adding OTel to a framework such as LangChain, LangGraph, Strands, CrewAI, OpenAI Agents, or Vercel AI), it is Omni — route to references/cloudwatch-omni/omni-agents-instrumentation/omni-agents-instrumentation.md. There is no Application Signals path for an agent framework.

  3. If the request is about instrumenting a general application (a service on EC2, ECS, EKS, or Lambda in Python, Node.js, Java, or .NET — not an AI-agent framework), decide the product before opening any procedure file — the two paths are mutually exclusive on a workload:

    • Names Application Signals, ServiceEvents, a "monitored service", the service map, the amazon-cloudwatch-observability add-on, the CloudWatch Agent's application_signals configuration, or port 4316 → the CloudWatch path: references/cloudwatch/application-signals-onboarding.md, then the matching references/cloudwatch/appsignals-guides/<platform>-<language>.md.

    • Names Omni, Application Observability, a Space, a Domain, or a Dataset — or explicitly rules Application Signals out ("plain OTel", "no add-on", "no agent sidecar") → the Omni path: references/cloudwatch-omni/instrumentation/instrumentation.md.

    • Naming the CloudWatch Agent alone decides nothing: it is also the Omni path's default collector. An agent with an opentelemetry section or OTLP receivers on 4317/4318 is the Omni collector, and its delivery problems belong to rule 6.

    • Names neither → rule 4.

  4. If an instrumentation, ADOT, or collector request names neither product (neither Omni or a Space, nor Application Signals, ServiceEvents, or the amazon-cloudwatch-observability add-on), probe for a Space in the target Region before choosing. list-spaces is account-global: the --region flag only selects the endpoint, and the response lists every Space in the account, each with its own region, so filter to the target Region rather than trusting a non-empty list: aws cloudwatchomni list-spaces --region <region> --query "items[?region=='<region>']". A Space in that Region → the Omni path, references/cloudwatch-omni/instrumentation/instrumentation.md. An empty filtered list → the customer has not adopted Omni in that Region, so Application Signals is the live product for them: references/cloudwatch/application-signals-onboarding.md. Either way the request stays in this skill — the probe picks the folder, not the skill. If the probe errors with an unknown service, that is the CLI model, not evidence Omni is absent — fall back to the customer's wording and ask only if still inconclusive.

  5. If the request is about Space/Domain creation or configuration, route to the matching setup reference. An authorization error that appears the moment a just-created Space is used is part of this — it is a space access role trust-policy problem (create-space never verifies the role can be assumed), so route to references/cloudwatch-omni/spaces-and-domains.md → "If the Space was created but cannot be used", not to the access-grants reference.

  6. If the user asks about getting telemetry to a destination — telemetry not yet reaching CloudWatch — deploy an OTel Collector on EC2/ECS/EKS so an instrumented workload has somewhere to send OTLP, and wire the app's OTEL_EXPORTER_OTLP_ENDPOINT to it: references/cloudwatch-omni/instrumentation/collector.md. The same file covers an OTLP collector that is already deployed but whose telemetry does not arrive, in whole or for one signal (its Verify section and the platform guide's troubleshooting table). The collector exports straight to CloudWatch's own per-signal OTLP endpoints. If instead the telemetry is already in CloudWatch log groups and needs forwarding into the Dataset, route to references/cloudwatch-omni/data-forwarding-and-centralization.md. Both the collector's OTLP export and CloudWatch's OTLP endpoints authenticate with SigV4 (AWS credentials), including OIDC-federated credentials for a workload outside AWS (see references/cloudwatch-omni/azure-ingestion/custom-telemetry.md or references/cloudwatch-omni/gcp-ingestion/custom-telemetry.md). A purely token-based ingestion path for a sender that cannot obtain AWS credentials at all is not covered by these skills; do not improvise one, and say so plainly.

  7. If the request is about getting Azure or Google Cloud telemetry into CloudWatch, route by cloud — references/cloudwatch-omni/azure-ingestion/azure-ingestion.md for Azure, references/cloudwatch-omni/gcp-ingestion/gcp-ingestion.md for Google Cloud — and decide by intent. If the customer wants the telemetry their own application produces (the logs/metrics/traces from their code), that is supported via the CloudWatch agent on an Azure VM or AKS cluster, or on a GCE instance or GKE cluster — follow the reference. If they want telemetry their cloud's resources emit on their own (the equivalent of AWS VPC flow logs / Route 53 logs: Azure resource and platform logs, or Google Cloud Audit Logs), that is not supported — say so and do not attempt a setup. If the request names no cloud, ask which one before giving any steps.

  8. If the user asks to connect, enable, or authorize Slack for a Space for the first time (including granting the operator permission to use it), route to references/cloudwatch-omni/slack-integration.md. Using Slack after it is connected (posting findings to a channel, mentioning the assistant, or searching Slack) happens in Slack and the console and is not covered by these skills; Slack as an alert notification target is covered by aws-observability's Omni alerts reference.

  9. Application Signals, ServiceEvents, and Dynamic Instrumentation are CloudWatch features, and they split by setup versus use — not by skill. Enabling them on a service that does not have them yet is setup and belongs here, under references/cloudwatch/: Application Signals onboarding and ServiceEvents in references/cloudwatch/application-signals-onboarding.md (with the CI/CD metadata chain in references/cloudwatch/application-signals-cicd-metadata.md), and switching Dynamic Instrumentation on at instrumentation time in that same file's Step 5d. They must never appear in an Omni instrumentation change — for that they remain out of scope, and rule 3 is how you tell the two paths apart. Using them once the service reports — reading the service map, alarming on Application Signals metrics, or placing breakpoints and reading snapshots with Dynamic Instrumentation — is day-to-day work: STOP and route to aws-observability.

  10. If the user already has a working Space, or a service already reporting to Application Signals, and is asking about queries/dashboards/alarms/alerts/investigation, STOP and route to aws-observability.

  11. If the user asks to register their own MCP tool server, connect a custom MCP server, or set up MCP authentication: CloudWatch Omni does not let customers add a custom MCP server. There is no console screen for it and the integration type is not enabled for customer use, so the attempt is refused. Say so plainly and stop; do not describe a setup flow, and do not offer a substitute. See references/cloudwatch-omni/custom-mcp-integration.md.

  12. If the user asks to connect GitHub, link a GitHub organization or repositories, or enrich the application map from source code: CloudWatch Omni has no GitHub integration. Say so plainly and stop — do not walk through a setup. Do not offer a substitute: the Application Signals GitHub Action and the CloudWatch Logs GitHub audit-log source are separate CloudWatch features, not a way to connect GitHub to Omni, and a custom MCP server is not a GitHub integration. A GitHub-related feature found in public documentation is not evidence of an Omni GitHub integration.

  13. If the user asks to enable or configure CloudWatch Omni Intelligence — attach or remove a customer-managed KMS key for intelligence data, add an intelligence integration (AWS_INTEGRATION, AWS_CONFIG_SLREC, or EXTERNAL_AGENT), read the current intelligence configuration, or troubleshoot why it will not turn on (a 404 UnknownOperationException, an AccessDeniedException, or an empty context graph) — route to references/cloudwatch-omni/intelligence-setup.md. That reference is the source of truth for the KMS ARN rules (full key ARN only, kms:Decrypt/kms:GenerateDataKey, exactly one of --kms-key-arn/--remove-kms-key, and that revoking the key makes intelligence data unrecoverable), the per-integration extra IAM, the two AccessDenied causes, and why "not enabled" is a 404 rather than an AccessDenied. Reading or interpreting the intelligence data once it is on is day-to-day use: STOP and route to the aws-observability skill — triaging insights, observations, or anomalies goes to its intelligence.md reference, which covers the ListInsights / ListObservations / GetContextGraph operations and the 404-vs-403-vs-local error rule; a pure topology or blast-radius question goes to its context-graph.md reference. For Slack specifically, route to references/cloudwatch-omni/slack-integration.md; for a custom MCP server, route to references/cloudwatch-omni/custom-mcp-integration.md (not supported). Do not offer GitHub, PagerDuty, Teams, MODEL_PROVIDER, or CUSTOM_MCP as intelligence integration types.

  14. If the request names neither product — "add observability to my API", "how should I begin monitoring my workload", with no mention of Omni, a Space, a Domain, or of a CloudWatch feature — do not assume either one. Which product a customer wants to set up is their intent, not something the account's current state tells you, so ask, framed product versus product: CloudWatch Omni (Application/Agent Observability — Domains, Spaces, grants, a Dataset) or CloudWatch (log groups, alarms, Log Insights, Application Signals). Both answers are served here, from different reference folders, so this is a question about which product to set up — not about which skill to use, and not a reason to hand the request to aws-observability. In the same message, explain the boundary so they can choose — it is setup versus use: creating or configuring a Domain, Space, grant, or Access Profile, getting telemetry flowing for the first time, instrumenting an application or agent for Omni, and onboarding a service to Application Signals are all first-time setup and belong here; querying telemetry, building dashboards, configuring alarms or Omni alerts, investigating a live problem, and debugging with Dynamic Instrumentation are day-to-day use and belong to aws-observability. Do not start walking through Domain/Space creation or Application Signals onboarding until they confirm which product; having asked, stop and wait.

  15. If the user asks to connect the AWS DevOps Agent to a Space, or the connect card or Investigations shows it is not connected, route to references/cloudwatch-omni/devops-agent-integration.md. These skills cover only that Omni-side connection. Creating or configuring the DevOps Agent space, and running, following, or chatting with its investigations from a coding agent, belong to the agent's dedicated aws-agents-for-devsecops plugin; point the customer there rather than reconstructing that workflow.

Files

references/cloudwatch-omni/data-forwarding-and-centralization.md

Forwarding telemetry into a Space

Gets an account's CloudWatch logs and traces into the CloudWatch Dataset, so CloudWatch Omni can query and correlate them. Logs and traces do not enter the Dataset directly — they are copied from CloudWatch Logs (including the aws/spans trace records), so getting them into Omni always means getting them into CloudWatch first, then forwarding. OTel metrics are the exception: they land in the Dataset natively via the CloudWatch metrics OTLP endpoint and need no forwarding.

Always state these, in any answer drawn from this file:

  • Which of the two paths applies, and why the other exists. OTLP ingestion — the standard CloudWatch OTLP endpoints — is for telemetry not yet in CloudWatch; dataset forwarding is for telemetry already there. They compose: OTLP lands data in CloudWatch, and the dataset integration brings it into the Dataset. A customer starting from nothing needs both.

  • Forwarding with nothing arriving in CloudWatch yields a working integration with no data flowing through it, which reads as a failure even though every call succeeded.

  • Logs and traces forward; metrics do not. Customer OTel metrics land in the Dataset natively; AWS-vended CloudWatch metrics arrive through OTel enrichment (aws observabilityadmin start-telemetry-enrichment, then aws cloudwatch start-otel-enrichment) instead. Enrichment is opt-in per account and per Region: enabling it in one Region leaves every other Region's vended metrics out of Omni, so name each Region it must be repeated in. A custom metric published with EMF or PutMetricData takes neither route; it reaches Omni only when emitted over OTLP (references/cloudwatch-omni/instrumentation/instrumentation.md, Custom metrics).

  • Enabling Omni from the console already creates the integration and its execution role, which is why you check before creating.

  • The first-ever integration in an account and Region triggers a one-time import of the previous week; it never repeats, and log groups encrypted with a customer managed key are excluded from it.

Contents

  • Which path

  • What arrives when forwarding starts

  • Prerequisites

  • Step 1 — Check whether forwarding already exists

  • Step 2 — Create the execution role

  • Step 3 — Create the dataset integration

  • Changing what is forwarded

  • Forwarding in more than one account

  • Cleanup

  • Troubleshooting

  • Security considerations

  • Additional resources

Which path

Two different things are described as sending data to Omni. Identify which the customer needs before making any change:

The customer hasPath
Applications or AWS services already ingesting into CloudWatch log groupsDataset forwarding — this file
An agent or application not sending to CloudWatchStandard CloudWatch OTLP endpoints — the per-signal OTLP entry points that deliver into CloudWatch. Deploy a collector that exports to them: see references/cloudwatch-omni/instrumentation/collector.md

The two paths solve different problems. The standard CloudWatch OTLP endpoints are OTLP entry points: they exist so an application or agent that is not currently sending anything to CloudWatch has somewhere to send it. Dataset forwarding does not accept telemetry at all — it collects what is already in CloudWatch log groups and brings it into the Dataset.

So the two compose. An application sends over OTLP to the CloudWatch OTLP endpoints, which lands telemetry in CloudWatch, and the dataset integration brings it into the Dataset. A customer starting from nothing needs both; a customer who already has logs in CloudWatch needs only forwarding.

Forwarding set up for a customer whose application is not yet sending to CloudWatch produces a working integration with nothing flowing through it, which reads as a failure even though every call succeeded.

Constraints:

  • You MUST establish which path applies rather than assuming. Setting up forwarding for a customer whose application is not sending to CloudWatch produces a working integration with nothing flowing through it, which reads as a failure.

What arrives when forwarding starts

Forwarding moves logs and traces as they are ingested. Metrics do not flow through the dataset integration — they become available through metric enrichment.

When the dataset integration is created for the first time in an account and Region, CloudWatch performs a one-time import of the previous week of existing log data. After that:

  • The import runs once. Deleting and recreating the integration does not repeat it.

  • Log groups encrypted with a customer managed AWS KMS key are not included in the import. Their forwarding still begins normally from creation onward.

  • Adding a log group to the integration's scope later forwards its records from that point on, not its existing contents.

Constraints:

  • You MUST set this expectation before creating the integration. A customer who expects all of their history, or none of it, will misread a correctly working integration.

  • You MUST tell a customer with customer managed key encryption that their encrypted log groups are excluded from the initial import, because the result otherwise looks like a partial failure.

  • You MUST tell the customer that metrics do not arrive through this integration. Expecting metrics because forwarding is on is a reasonable and common misunderstanding.

Prerequisites

  • The AWS Region, confirmed with the customer rather than inferred. Forwarding is same-account and same-Region, and a Region mismatch produces an integration that forwards nothing.

  • iam:PassRole on the execution role, for whoever runs Step 3. Without it the create call fails after the role already exists.

A Space is not a technical prerequisite — forwarding can be set up without one, but nothing in Omni reads the forwarded data until a Space exists. Within onboarding it effectively is one, since the Space is the Omni experience being set up, so sequence it first. See references/cloudwatch-omni/spaces-and-domains.md.

Report the caller identity before starting:

aws sts get-caller-identity
Operations you will call

Every operation is an aws <service> <operation> CLI command — the service (observabilityadmin, iam, or sts), the kebab-case operation, and a flag for each input parameter. Run it through the aws___call_aws tool when that tool is available; otherwise run the same command in a shell. Policy documents are shown below as standalone JSON blocks — pass each one as the value of the corresponding flag (--assume-role-policy-document, --policy-document).

aws observabilityadmin:

IntentOperation
Check for existing forwardingget-dataset-integration
Start forwardingcreate-dataset-integration
Change which role the integration usesupdate-dataset-integration
Stop forwardingdelete-dataset-integration

aws iam:

IntentOperation
Create the execution rolecreate-role
Attach forwarding permissionsput-role-policy
Remove an inline policydelete-role-policy
Delete the execution roledelete-role

aws sts:

IntentOperation
Confirm the calling identityget-caller-identity

Step 1 — Check whether forwarding already exists

When CloudWatch Omni is enabled from the console, forwarding is set up automatically — the console creates the dataset integration and its execution role as part of enablement. Check before creating anything.

There is one dataset integration per account per Region and it is named default, so its ARN is deterministic. Construct it and read it directly:

aws observabilityadmin get-dataset-integration \
  --arn arn:aws:observabilityadmin:<region>:<account-id>:dataset-integration/default

A successful response means forwarding already exists. A not-found error means it does not.

Constraints:

  • You MUST run this check before creating an integration. There is one per account per Region, so a second create conflicts.

  • If one exists, you MUST report what the call returns and stop. The remaining work is scoping (see Changing what is forwarded), not creation.

  • If you cannot determine whether an integration exists — access is denied, or the response is ambiguous — you MUST treat the result as inconclusive, not negative. Report that the check could not be completed and stop. You MUST NOT create an integration on that basis.

Step 2 — Create the execution role

Only if Step 1 found no integration. This is the role CloudWatch Logs assumes to bring logs and traces into the Dataset.

Ask the customer whether the CloudWatch Dataset is encrypted with a customer managed KMS key. If it is, the execution role needs kms:Decrypt on that key, or forwarded telemetry cannot be written.

Constraints:

  • You MUST ask before creating the role. A missing kms:Decrypt produces an integration that reports success and silently writes nothing.

  • You MUST ask about the Dataset's key specifically. Log group encryption is a separate matter and has no bearing on this role's permissions.

Create the role

Call aws iam create-role with --role-name set to the customer's chosen role name and --assume-role-policy-document set to this trust policy. The aws:SourceAccount and aws:SourceArn conditions are confused-deputy protection — keep both. A condition that does not match — the wrong account, or an aws:SourceArn that is not the dataset-integration/default resource — blocks logs.amazonaws.com from assuming the role, and that failure is silent: nothing surfaces on the create call, so forwarding ends up set up yet never delivers.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": "logs.amazonaws.com" },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": { "aws:SourceAccount": "<account-id>" },
        "ArnLike": {
          "aws:SourceArn": "arn:aws:observabilityadmin:<region>:<account-id>:dataset-integration/default"
        }
      }
    }
  ]
}
aws iam create-role \
  --role-name <role-name> --assume-role-policy-document <trust-policy-json>
Attach the forwarding permissions

Forward all log groups in the account. This is the onboarding default: it gives Omni the fullest picture to correlate across, and log groups created later are picked up without a permission change. cloudwatch:PutRecords does not support resource-level scoping.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "logs:IntegrateWithDataset",
      "Resource": ["arn:aws:logs:<region>:<account-id>:log-group:*"]
    },
    {
      "Effect": "Allow",
      "Action": "cloudwatch:PutRecords",
      "Resource": "*"
    }
  ]
}
aws iam put-role-policy \
  --role-name <role-name> --policy-name DatasetIntegrationAccess --policy-document <policy-json>

Constraints:

  • You SHOULD use the account-wide log-group:* resource shown above.

  • If the customer asks to forward only specific log groups, replace log-group:* with their ARNs, and tell them log groups created later will not forward until the policy is updated.

  • You MUST NOT add actions beyond these two. This role exists solely to move telemetry into the Dataset.

Attach KMS decrypt, only if the Dataset uses a customer managed key
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "arn:aws:kms:<region>:<account-id>:key/<key-id>"
    }
  ]
}
aws iam put-role-policy \
  --role-name <role-name> --policy-name DatasetKeyDecrypt --policy-document <policy-json>

Constraints:

  • You MUST scope this to the Dataset's key ARN. Do not use "Resource": "*".

  • You MUST NOT author or modify the KMS key policy. This grants the role permission to use the key; it does not change who the key trusts. If the key policy needs changing, direct the customer to their key administrator.

Step 3 — Create the dataset integration

aws observabilityadmin create-dataset-integration \
  --role-arn arn:aws:iam::<account-id>:role/<role-name>

Constraints:

  • Creating the integration starts forwarding logs and traces together. There is no per-signal switch at create time; scope is controlled by the role's permissions.

  • If the call fails on iam:PassRole, you MUST report which principal lacks it and stop. Do not attach permissions to your own caller to get past it.

Forwarding begins on creation. Allow a few minutes before telemetry appears in the Space — permission changes take effect within a few minutes, and there is delivery latency on top of that. If telemetry does not appear, see Troubleshooting.

Changing what is forwarded

Scope is the execution role's logs:IntegrateWithDataset permissions, not a setting on the integration.

  • Narrowing or widening the role's log group ARNs takes effect within a few minutes.

  • Scope changes are forward-only in both directions. Adding a log group forwards its records from that point on, not its existing contents. Removing one stops future records, while records already in the Dataset remain until they pass their retention period.

  • To change which role the integration uses, or to stop forwarding entirely, use update-dataset-integration or delete-dataset-integration.

Retention in the Dataset mirrors each record's source retention, so records with different retention periods coexist. It is not configured on the Dataset.

Constraints:

  • You MUST state which direction applies. A customer who widens scope expecting the new log group's history, or narrows it expecting forwarded records to disappear, will be wrong in both cases.

Forwarding in more than one account

Forwarding is same-account and same-Region. One account's integration does not collect telemetry from other accounts, and one Region's integration does not collect from other Regions.

To cover several accounts, each account forwards its own telemetry in the Region where its Space lives, and each account gets its own execution role and integration.

A Region mismatch fails silently: the integration is created, forwards nothing, and produces no error anywhere. And do not reason by analogy from how other AWS services centralize into a monitoring account — that pattern does not exist here, and proposing it recommends an architecture that cannot work.

Constraints:

  • You MUST NOT compose a cross-account or monitoring-account forwarding pattern from how other AWS services centralize. Doing so recommends a plausible architecture that does not work here.

Cleanup

  1. Stop forwarding:

    aws observabilityadmin delete-dataset-integration \
      --arn arn:aws:observabilityadmin:<region>:<account-id>:dataset-integration/default
  2. Detach the inline policies, then delete the execution role. A role with inline policies attached cannot be deleted:

    aws iam delete-role-policy \
      --role-name <role-name> --policy-name DatasetIntegrationAccess
    
    aws iam delete-role-policy \
      --role-name <role-name> --policy-name DatasetKeyDecrypt
    
    aws iam delete-role --role-name <role-name>

    Skip DatasetKeyDecrypt if it was never attached.

Deleting the integration stops future forwarding. It does not remove records already in the Dataset — those age out under their source retention.

Constraints:

  • You MUST warn the customer that deleting the integration is not reversible in effect: recreating it restores forwarding, but the one-time import does not run again.

  • You MUST NOT delete and recreate the integration to try to obtain missing history. The import runs only on first creation, so recreating gains nothing and interrupts working forwarding.

Troubleshooting

Rule: When an AWS call returns an error, surface the error code and message verbatim to the customer, then map to the mitigation below. Do NOT invent error text, do NOT paraphrase what the service returned, and do NOT synthesize a plausible-sounding mitigation for an error that is not listed.

Establish which kind of failure this is before investigating. They have different causes and different fixes, and treating one as the other wastes the whole diagnosis:

  • The API call was rejected — creating, reading, or deleting the integration failed. The cause is the caller's own permissions or a bad argument.

  • The API call succeeded but telemetry is not appearing — the integration exists. The cause is almost always the execution role's contents, or a Region mismatch.

The API call was rejected
Error signalCauseMitigation to surface
AccessDenied on createCaller lacks observabilityadmin:CreateDatasetIntegrationAsk the customer to add the action to their calling role
AccessDenied naming iam:PassRoleCaller may create the integration but cannot pass the execution role to logs.amazonaws.com. This is a permission on the caller, not on the execution role — a common misdiagnosisAsk the customer to add iam:PassRole on the specific role ARN to their calling role
Execution role not foundRole ARN typo, or role in a different accountAsk the customer to verify the exact role ARN and confirm it is in the same account. The role must exist before the integration can reference it
Conflict on createAn integration already exists for this account and RegionRead it instead — see Step 1. Do NOT retry the create

Constraints:

  • You MUST report the principal and the action, and direct the customer to whoever administers their IAM permissions. You cannot widen your own access.

The integration exists but telemetry is not appearing

Work through these in order. Each is cheap to check and rules out the ones below it.

  • Is anything reaching CloudWatch at all? Confirm the source log group is receiving records. If it is empty, the problem is upstream of forwarding — see references/cloudwatch-omni/instrumentation/collector.md.

  • Is everything in the same Region? Forwarding is same-Region. A mismatch fails silently, with no error anywhere.

  • Can logs.amazonaws.com assume the execution role? Check the trust policy's principal, and that aws:SourceAccount and aws:SourceArn match this account and the dataset-integration/default ARN. A condition that does not match blocks the assume, and nothing surfaces on the create call.

  • Does the role cover the log groups in question? logs:IntegrateWithDataset must include their ARNs. A role scoped to specific log groups forwards only those.

  • Does the role have cloudwatch:PutRecords? Without it there is nowhere to write.

  • Does the Dataset use a customer managed key? If so the role needs kms:Decrypt on that key. Without it the integration reports healthy and silently writes nothing.

Constraints:

  • You MUST change one thing at a time and recheck. Stacked fixes hide which one worked, and some conflict.

Expectations that look like faults
  • Metrics are missing. Metrics do not flow through this integration; they become available through metric enrichment.

  • Only part of the expected history appeared. The one-time import covers the previous week and excludes log groups encrypted with a customer managed key.

  • Recent records appear but older ones do not. Scope changes are forward-only. Adding a log group forwards its records from that point on, not its existing contents.

Security considerations

  • The logs:IntegrateWithDataset resource controls what enters the Dataset. Account-wide forwarding is the onboarding default; restrict it to specific log group ARNs only when a customer needs particular log groups kept out.

  • Keep both aws:SourceAccount and aws:SourceArn conditions in the trust policy. They are the confused-deputy protection.

  • Do not attach *FullAccess managed policies to the execution role. It needs the dataset-integration actions and nothing else.

  • Forwarded telemetry is encrypted at rest in the Dataset. When a customer managed key is in use, the execution role needs kms:Decrypt on it.

  • Access to query the Dataset is controlled separately from ingestion, so read access can be granted without granting the ability to change forwarding.

Additional resources

  • references/cloudwatch-omni/instrumentation/collector.md — deploying a collector that exports to CloudWatch's OTLP endpoints, for telemetry not already reaching CloudWatch

  • references/cloudwatch-omni/spaces-and-domains.md — creating a Space and configuring access

  • CloudWatch Dataset — forwarding setup, policies, retention, encryption

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs an MCP server, Needs Python

Security

What our scanner noticed· Medium risk

  • References to credential files
  • Instructions that use the network

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
AWS
Publisher
AWS (Official)
Source
aws/agent-toolkit-for-aws · skills/specialized-skills/operations-skills/setting-up-cloudwatch-observability · commit 0a218f8
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • NOTICE (added by AutoGineer from NOTICE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by AWS or AWS.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download setting-up-cloudwatch-observability.zip