Send application telemetry
Deploy the CloudWatch agent where your application runs: Amazon EC2, Amazon ECS, Amazon EKS, an Azure VM, Azure Kubernetes Service, a Google Compute Engine instance, or Google Kubernetes Engine. Then point your application's OpenTelemetry exporter at the agent, and confirm that data arrives in your space. If your application is not instrumented yet, add OpenTelemetry for Python, Node.js, Java, .NET, or Go in the last step. The agent receives OpenTelemetry Protocol (OTLP) data from your application and forwards metrics, traces, and logs to CloudWatch.
If you are monitoring an AI agent, see Send AI agent telemetry. If your application runs on Amazon Lambda, see Send application telemetry from Amazon Lambda; Lambda has no collector to deploy.
Steps 1 and 2 show one environment at a time: expand the section for where your application runs in each step. Sections are collapsed so you can see the whole page; open only yours.
If your application already uses OpenTelemetry, do Steps 1 to 3 and stop; Step 4 is only for applications that are not instrumented yet. If you already run your own OpenTelemetry collector or the ADOT SDK, you need only an endpoint: see "Choose an endpoint" in Send telemetry to CloudWatch Omni.
Note
Assisted setup. The Add source wizard in the Omni web UI (Settings › Ingestion) generates these commands for your selections. From your coding agent, the Omni skills in the Agent Toolkit for Amazon do the same; see Use Omni skills. The rest of this page is the manual path.
Prerequisites
-
Transaction Search is enabled in the account and Region that receive traces. Traces sent before it is enabled are not searchable. See Transaction Search.
-
You can attach IAM policies to the role your compute uses: an instance role, a task role, the agent's service account role, or the federated role on Azure or Google Cloud.
-
For Step 4, your application's language is one of Python, Node.js, Java, .NET, or Go. For more information about the frameworks with documented notes, see Supported environments, languages, and frameworks. Other frameworks still work with the custom-instrumentation snippets.
Step 1: Deploy the CloudWatch agent (platform team or administrator)
Expand the environment your application runs on. Each section gives the install commands and the same resources as infrastructure as code, as tabs.
On Amazon EC2, you attach a managed policy to the instance role, install the agent with the OTLP preset (per instance, or fleet-wide with a State Manager association), then continue to Step 2.
Grant permissions
The instance role needs CloudWatchAgentServerPolicy,
which covers metrics, logs, and traces, bound to the instance
through an instance profile.
Install the agent and enable OTLP
For the full agent configuration reference, see Amazon CloudWatch agent in the Amazon CloudWatch User Guide.
On Amazon ECS (Fargate), you attach a managed policy to the task role, add
the agent as a second container in the same task with the application
depending on it, then continue to Step 2. Your application sends OTLP to
localhost; the task shares one network
namespace.
Grant permissions and egress
The task role needs CloudWatchAgentServerPolicy; the
execution role needs AmazonECSTaskExecutionRolePolicy.
The task needs egress to pull the agent image and reach the OTLP
endpoints: a public IP in a public subnet, a NAT gateway, or VPC
endpoints.
Important
The application container must depend on the agent container
with condition START. The agent image has no health
check, so condition HEALTHY hangs startup.
Add the sidecar to the task definition
For the agent configuration reference, see Amazon CloudWatch agent.
On Amazon EKS, you install the CloudWatch Observability add-on with OTLP enabled
and give its agent credentials, then continue to Step 2. The add-on runs
the agent as a DaemonSet and exposes a cloudwatch-agent
Service in the amazon-cloudwatch namespace; your pods send
OTLP to that Service over cluster DNS, not to localhost.
The add-on is installed with the Amazon CLI regardless of how you deploy
your application, so there is one installation path here.
curl -fsSL https://raw.githubusercontent.com/aws/amazon-cloudwatch-agent/main/scripts/aws/setup.sh | \ CWAGENT_PLATFORM=aws_eks \ CWAGENT_K8S_CLUSTER_NAME=<my-cluster> \ CWAGENT_AWS_REGION=<region> \ CWAGENT_AWS_ENABLE_TRANSACTION_SEARCH=true \ sh
-
The script installs the EKS Pod Identity Agent, creates the agent role with a Pod Identity association, and installs the add-on with OTLP enabled. Pod Identity supplies the agent's credentials, so you do not annotate the service account for IAM roles for service accounts (IRSA).
Three settings must be right or telemetry never arrives, with no error in the agent log:
-
The OTLP receiver must be bound to
0.0.0.0, not the defaultlocalhost, or it refuses cross-pod traffic. If application OTLP is refused after the script runs, apply the override and restart the DaemonSet:
aws eks update-addon --cluster-name <my-cluster> --addon-name amazon-cloudwatch-observability \ --configuration-values '{"agent":{"config":{"opentelemetry":{"collect":{"otlp":{"grpc_endpoint":"0.0.0.0:4317","http_endpoint":"0.0.0.0:4318"}}}}}}' kubectl -n amazon-cloudwatch rollout restart daemonset/cloudwatch-agent
-
The agent must have credentials through Pod Identity (the script) or an IRSA-annotated service account. The add-on's
--service-account-role-arnflag does not annotate the service account; without the annotation the agent falls back to the node role and its exports are rejected. -
Application logs are in the cluster-scoped log group
/aws/cwagent/<my-cluster>/otlp, not in/aws/cwagent/otlp.
For a manual install with IRSA and the add-on configuration reference, see Install the CloudWatch Observability add-on in the Amazon CloudWatch User Guide.
On an Azure VM, you federate the VM's managed identity to an IAM role
and install the CloudWatch agent on the VM, then continue to Step 2. The agent
sends telemetry with temporary Amazon credentials instead of a stored
key; your application sends OTLP to localhost.
The complete procedure, including the OpenID Connect (OIDC) federation, the IAM role trust policy, and the onboarding script, is in Install the CloudWatch agent on Azure in the Amazon CloudWatch User Guide. Follow the VM section there, then return to Step 2.
On Azure Kubernetes Service, you federate workload identity for the
cloudwatch-agent service account to an IAM role and
install the CloudWatch Observability Helm chart, then continue to Step 2. Pods
send OTLP to the cloudwatch-agent Service over cluster
DNS.
The complete procedure, including the OIDC federation and the Helm values, is in Install the CloudWatch agent on Azure in the Amazon CloudWatch User Guide. Follow the AKS section there, then return to Step 2.
Note
Unlike the EKS add-on, the AKS Helm chart's OTLP receiver accepts
cross-pod traffic by default; no 0.0.0.0 override is
needed.
On a Google Compute Engine instance, you federate the instance's
service account to an IAM role and install the CloudWatch agent on the
instance, then continue to Step 2. The agent sends telemetry with
temporary Amazon credentials instead of a stored key; your application
sends OTLP to localhost.
The complete procedure, including the service account federation, the IAM role trust policy, and the onboarding scripts, is in Install the CloudWatch agent on Google Cloud in the Amazon CloudWatch User Guide. Follow the Google Compute Engine (GCE) section there, then return to Step 2.
On Google Kubernetes Engine, you federate the cluster's OIDC issuer
for the cloudwatch-agent service account to an IAM role and
install the CloudWatch Observability Helm chart, then continue to Step 2. Pods
send OTLP to the cloudwatch-agent Service over cluster
DNS.
The complete procedure, including the OIDC federation and the Helm values, is in Install the CloudWatch agent on Google Cloud in the Amazon CloudWatch User Guide. Follow the Google Kubernetes Engine (GKE) section there, then return to Step 2.
Step 2: Point your application at the agent (developer)
Set these environment variables on the application, never on the agent: one agent serves many services and already enriches telemetry with infrastructure attributes. The endpoint and the place the variables live depend on your environment, and the port and protocol depend on your language; expand the same section you chose in Step 1, then choose your language.
On Amazon EC2, set these in the application's service unit or start script,
for example Environment= lines in a systemd unit:
On Amazon ECS, set these in the application container's
environment block:
On Amazon EKS, set these in the container's env block in the
pod spec:
On an Azure VM, set these in the application's service unit or start script:
On Azure Kubernetes Service, set these in the container's
env block in the pod spec:
On a Google Compute Engine instance, set these in the application's service unit or start script:
On Google Kubernetes Engine, set these in the container's
env block in the pod spec:
Step 3: Verify
Use the automated verification in the Omni web UI. In your space, open Settings › Ingestion and choose your source: the Add source flow's verification step confirms the agent is reporting and your application's telemetry is arriving, and points at the failing setting when it is not. Run it after every deployment change.
If verification fails, see the "Troubleshoot missing telemetry" section of this page.
The agent is reporting
Your application appears
If you run your own OpenTelemetry Collector instead of the CloudWatch
agent, this is your check. If your application is not instrumented
yet, do Step 4 first, then return to this check. Restart the
application, then open your space. In Application map, the service appears under the
service.name you set. In Trace Explorer, a trace for a recent request shows
the entry span for your service with the resource attributes you
set. Application logs are in /aws/cwagent/otlp on EC2,
ECS, Azure VMs, and Compute Engine instances, or
/aws/cwagent/<cluster>/otlp on EKS, AKS, and
GKE. A custom metric is queryable with PromQL by its OpenTelemetry
name, for example
sum({__name__="orders.placed"}).
Step 4 (optional): Instrument your application with OpenTelemetry (developer)
Choose your language. The choice applies to every code sample in this step and is remembered on the other pages in this guide. For Python, Node.js, Java, and .NET, most HTTP frameworks, database clients, and messaging libraries are traced without code changes. Go has no auto-instrumentation agent, so initialize the SDK in code and wrap your handlers with the library instrumentation for your framework. The table in each tab lists the frameworks with documented notes, and the OpenTelemetry registry lists the rest. For a framework not covered, the custom-instrumentation snippet still works.
Install the OpenTelemetry SDK
Add the CloudWatch plugin for OpenTelemetry with the SDK. The plugin generates the request, error, and duration span metrics that power the service views (including the Errors metric), and it meters every span before sampling, so those metrics reflect all requests rather than the sampled subset. It is available for Python, Node.js, Java, .NET, and Go. The following table lists the package names and links. The plugin needs a metrics pipeline to emit into. If your application exports traces but no metrics, the plugin stays inert and Errors remains unpopulated. Configure a metrics exporter alongside your trace exporter.
If you instrument with the ADOT SDK instead and sample, your span metrics are computed from the sampled spans only.
| Language | Package | Documentation |
|---|---|---|
| Java | software.amazon.opentelemetry:cloudwatch-plugin-otel |
Java plugin README |
| Python | cloudwatch-plugin-otel |
Python plugin README |
| Node.js | @aws/cloudwatch-plugin-otel |
Node.js plugin README |
| .NET | Amazon.OpenTelemetry.CloudWatchPluginOtel |
.NET plugin README |
| Go | github.com/aws-observability/cloudwatch-plugin-otel-go |
Go plugin README |
Enable auto-instrumentation
Run your application under the auto-instrumentation agent for its language. Framework, HTTP, and database calls are traced without code changes. Go has no auto-instrumentation agent. For Go, initialize the SDK once at startup instead.
Add custom instrumentation
Set business attributes on the active span, mark your entry span as a server span so it counts in request metrics, and record a custom metric. These snippets assume the SDK is initialized by the step above.
Query custom metrics with PromQL by their OpenTelemetry name, for example
sum({__name__="orders.placed"}). Restart the application
and repeat Step 3.
Troubleshoot missing telemetry
| Symptom | Cause and fix |
|---|---|
| Logs and spans arrive, metrics do not | A metric attribute value is longer than 1024 characters;
the CloudWatch OTLP metrics endpoint rejects the whole batch with
HTTP 400. Trim the attribute. For Java, the usual cause is
process.command_args on a long classpath:
set
OTEL_JAVA_DISABLED_RESOURCE_PROVIDERS=io.opentelemetry.instrumentation.resources.ProcessResourceProvider. |
| Nothing arrives; the SDK logs connection errors | Port and protocol do not match: 4317 is gRPC
and 4318 is HTTP. Set
OTEL_EXPORTER_OTLP_PROTOCOL to match the
port. For Go, the exporter package sets the protocol, so use
port 4318 with the OTLP/HTTP exporters. |
| Nothing arrives on ECS; the task hangs at startup | The application container depends on the agent with
condition HEALTHY. Use
START. |
Nothing arrives on ECS; the agent logs
AccessDenied or times out |
The task role lacks
CloudWatchAgentServerPolicy, or the task
has no egress to the OTLP endpoints. Attach the policy; add
a public IP, NAT gateway, or VPC endpoints. |
| Nothing arrives on EKS; no agent errors | The receiver is bound to localhost, or the
agent service account has no credentials. Apply the
0.0.0.0 override; use Pod Identity or
annotate the service account for IRSA, then restart the
DaemonSet. |
| Nothing arrives from a new EC2 instance | The agent started before the instance profile reached the
instance metadata service. Wait for the role in user data
before fetch-config, or restart the
agent. |
| Nothing arrives from an Azure VM or AKS | The federation is not complete: the IAM role trust policy does not match the identity, or the service account is not annotated. Recheck the federation steps in Install the CloudWatch agent on Azure. |
| Nothing arrives from a Compute Engine instance or GKE | The federation is not complete: the IAM role trust policy does not match the instance's service account unique ID or the cluster's OIDC issuer, or the instance has no service account attached. Recheck the federation steps in Install the CloudWatch agent on Google Cloud. |
| The service appears under the agent's name | OTEL_SERVICE_NAME is set on the agent, not
the application. Move it to the application. |
| A Python service shows one process span and no route spans | opentelemetry-instrument wrapped
python instead of the server. Wrap
uvicorn or gunicorn. |
| Traces exist but are not searchable | Transaction Search was enabled after the traces were sent. Enable it, then send new traces. |
| Only some requests appear in the trace list | Transaction Search indexes 1 percent of spans by default for the trace list; the spans themselves are all stored. Raise the indexing percentage in Transaction Search settings. |