Skip to content

How to drop specific endpoints from CloudWatch Application Signals?

0

Question

How can I configure CloudWatch Application Signals to drop metrics and traces for specific endpoints like health checks?

Context

I'm running a Java application on Amazon ECS Fargate with Application Signals enabled. The application has health check endpoints (/actuator/health/readiness, /actuator/health/liveness) that are generating high-cardinality metrics and traces that I don't need to monitor.

What I Want to Achieve

  • Drop traces and metrics for health check endpoints
  • Reduce CloudWatch costs by filtering unnecessary telemetry
  • Keep monitoring for business-critical endpoints

Current Setup

  • Platform: Amazon ECS Fargate
  • Application: Java with Spring Boot Actuator
  • Region: sa-east-1
  • OpenTelemetry: Auto-instrumentation enabled I'm using aws-otel-java-instrumentation for sending metrics/traces and cloudwatch-agent as the sidecar that receives them.

What I've Tried

I added drop rules to my CloudWatch Agent configuration:

{
    "traces": {
        "traces_collected": {
            "application_signals": {
                "rules": [
                    {
                        "selectors": [
                            {
                                "dimension": "Operation",
                                "match": "GET /actuator/health/readiness"
                            }
                        ],
                        "action": "drop"
                    }
                ]
            }
        }
    }
}

I've also tried adding retention/sampling rules to X-Ray

## Questions
Is this the correct way to configure drop rules for Application Signals?
Should I use wildcards like GET /actuator/health/* or exact matches?
Do I need to configure both traces and logs sections?
How long does it take for drop rules to take effect?
Are there any best practices for filtering health check endpoints?
Any examples or guidance would be helpful!
asked 19 days ago56 views
3 Answers
1

To effectively drop specific endpoints and reduce costs in CloudWatch Application Signals, you need to use the specific Sampling Rules syntax designed for the AWS Distro for OpenTelemetry (ADOT) collector. The generic "drop" action is often not recognized in the application_signals block; instead, the service relies on sampling logic to filter telemetry.

1. Updated CloudWatch Agent Configuration

Update your sidecar configuration to use sampling_rules. This tells the ADOT collector to ignore these paths before they are processed by the Application Signals managed service:

{
  "traces": {
    "traces_collected": {
      "application_signals": {
        "sampling_rules": [
          {
            "rule_name": "ExcludeHealthChecks",
            "selectors": [
              {
                "dimension": "Operation",
                "match": "GET /actuator/health/*"
              }
            ],
            "should_sample": false
          }
        ]
      }
    }
  }
}
  • Wildcards: The * wildcard is fully supported for the Operation dimension.
  • Cost Impact: By setting should_sample: false, these requests are not counted towards your Application Signals managed service charges because the telemetry is discarded at the agent level.

2. Application-Level Exclusion (Java Agent)

For optimal performance on ECS Fargate, you should also prevent the Java instrumentation from generating these spans in the first place. This reduces CPU overhead in your application container. Add this environment variable to your ECS Task Definition:

  • Key: OTEL_JAVAAGENT_EXCLUDED_URLS
  • Value: /actuator/health/*

Answers to your specific questions:

  • Is this the correct way? Yes, using sampling_rules within the application_signals block is the standard approach for ADOT-based monitoring.
  • Traces vs. Logs? Focus on Traces. Application Signals dashboards and metrics are primarily derived from trace data. Filtering traces is the key to cost control.
  • How long does it take? Changes take effect immediately upon restarting your ECS Tasks.
  • Best Practice: Always use the OTEL_JAVAAGENT_EXCLUDED_URLS variable alongside the Agent's sampling rules for a "defense-in-depth" approach to telemetry filtering.
EXPERT
answered 19 days ago
  • Thanks for your answer. Unfortunately, this did not work for me. Here are some findings: I noticed should_sample config flag is used in the python's library (aws-observability/aws-otel-python-instrumentation) but not on the java one. Also could not find any use of it on the sidecar I'm using here https://github.com/aws/amazon-cloudwatch-agent Similar to the above, found use of OTEL_PYTHON_EXCLUDED_URLS in the opentelemetry python's config (open-telemetry/opentelemetry-python-contrib) but nothing equivalent for java.

0
Accepted Answer

After investigating, I wasn't able to get Application Signals drop rules to reliably filter health check traces. I ended up switching to X-Ray centralized sampling rules with an ADOT Collector sidecar inside the task definition. This approach gave me full control over what gets sampled before traces are even sent.

Architecture

I replaced aws-otel-java-instrumentation + cloudwatch-agent with: ADOT Java agent (public.ecr.aws/aws-observability/adot-autoinstrumentation-java) — init container that copies the agent to a shared volume ADOT Collector sidecar — runs inside the same task, receives traces via OTLP and forwards to X-Ray. Also runs the awsproxy extension which is key for sampling rules to work.

Collector config

extensions:
  awsproxy:
    endpoint: 0.0.0.0:2000
    region: us-east-1

receivers:
  otlp:
    protocols:
      http:
        endpoint: 0.0.0.0:4316

processors:
  batch:

exporters:
  awsxray:
    region: us-east-1

service:
  extensions: [awsproxy]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [awsxray]

Application container environment variables

{"name": "JAVA_TOOL_OPTIONS", "value": "-javaagent:/otel-auto-instrumentation/javaagent.jar"},
{"name": "OTEL_TRACES_SAMPLER",     "value": "xray"},
{"name": "OTEL_TRACES_SAMPLER_ARG", "value": "endpoint=http://localhost:2000"},
{"name": "OTEL_TRACES_IDGENERATOR", "value": "xray"},
{"name": "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "value": "http://localhost:4316/v1/traces"},
{"name": "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL", "value": "http/protobuf"},
{"name": "OTEL_PROPAGATORS", "value": "tracecontext,baggage,b3,xray"},
{"name": "OTEL_METRICS_EXPORTER", "value": "none"},
{"name": "OTEL_LOGS_EXPORTER",  "value": "none"}

Why awsproxy is essential

The ADOT Java agent's XraySamplerClient (activated by OTEL_TRACES_SAMPLER=xray) polls GetSamplingRules and GetSamplingTargets via unsigned plain HTTP. It cannot sign requests with SigV4 itself. The awsproxy extension acts as a local proxy on port 2000 that forwards those calls to the X-Ray API with proper SigV4 signing using the ECS task role credentials.

Without this proxy, the sampler silently fails to load rules. You'll see adaptive_sampling_configured=false on startup spans, and everything falls through to the Default rule (100% sample rate), including health checks.

X-Ray sampling rule to drop health checks

In X-Ray console → Sampling rules, create a rule with priority higher than Default (lower number = higher priority):

Field Value Rule name DropHealthChecks Priority 1 Reservoir size 0 Fixed rate 0% Service name * URL path /actuator/health/* Unsure if wildcard works, I've actually created both rules with wildcards and specific endpoints. Health check traces are dropped before recording. Rules take effect within ~10 seconds of the sampler's next polling cycle.

Critical gotcha: port 2000 must be TCP

The awsproxy extension uses HTTP (TCP). If your ECS security group has port 2000 open as UDP (which is the default for the legacy X-Ray daemon), the sampler will silently fail to contact the proxy and you'll never see sampling rules applied. Change the inbound rule for port 2000 to TCP.

IAM permissions for the task role

{
  "Effect": "Allow",
  "Action": [
    "xray:GetSamplingRules",
    "xray:GetSamplingTargets",
    "xray:PutTraceSegments",
    "xray:PutTelemetryRecords"
  ],
  "Resource": "*"
}

The AWSXRayDaemonWriteAccess managed policy covers all of these.

answered 11 days ago
AWS
EXPERT
reviewed 6 days ago
0

Based on the available documentation for CloudWatch Application Signals, I can provide guidance on filtering telemetry data, though the specific drop rules configuration you're attempting may not be the standard approach.

Recommended Approaches for Filtering Endpoints

1. Disable Metrics Exporters Selectively

You can control what telemetry is sent by configuring environment variables in your application container. For your Java application on ECS Fargate, you're already using these key variables:

  • OTEL_AWS_APPLICATION_SIGNALS_ENABLED - Controls whether Application Signals telemetry is sent
  • OTEL_METRICS_EXPORTER - Set to none to disable other metrics exporters
  • OTEL_LOGS_EXPORTER - Set to none to disable other logs exporters

2. Application-Level Filtering

The most effective approach for filtering health check endpoints is typically at the application or OpenTelemetry instrumentation level, rather than at the CloudWatch agent level. You can:

  • Configure the OpenTelemetry Java agent to exclude specific endpoints from instrumentation
  • Use OpenTelemetry's sampling configuration to drop traces for specific patterns
  • Implement custom span processors that filter out health check endpoints before they're exported

3. Endpoint Configuration

Ensure your metrics and traces are being sent to the correct endpoints:

  • OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT should be set to http://localhost:4316/v1/metrics for the sidecar configuration
  • OTEL_EXPORTER_OTLP_TRACES_ENDPOINT should be set to http://localhost:4316/v1/traces

Important Considerations

Protocol Setting: Make sure you have OTEL_EXPORTER_OTLP_PROTOCOL set to http/protobuf to properly send metrics and traces to Application Signals.

Version Requirements: Ensure you're using version 1.32.2 or later of the AWS Distro for OpenTelemetry auto-instrumentation agent for Java, as this is required for proper Application Signals functionality.

Alternative Approach

Since the drop rules in the CloudWatch agent configuration may not be the standard method for Application Signals, consider using OpenTelemetry's native filtering capabilities through environment variables or configuration files specific to the Java auto-instrumentation agent. This would allow you to filter traces before they even reach the CloudWatch agent, reducing both network overhead and costs more effectively.

Unfortunately, the specific syntax for drop rules within the Application Signals configuration isn't clearly documented in the standard setup guides, which suggests this may not be the intended filtering mechanism for this service.
Sources
Deploy using the daemon strategy - Amazon CloudWatch
Deploy using the sidecar strategy - Amazon CloudWatch

answered 19 days ago
EXPERT
reviewed 19 days ago
  • Thanks for your answer, here's some comments on the above:

    1. Disable Metrics Exporters Selectively I think this is how I want it to be today, I do want to have signals enabled.
    2. Application-Level Filtering I was hoping to get away without touching application's code When I used native's OpenTelemetry's sampling configuration to drop the traces (using file config), some of the specific config I was using for AWS got ignored, such as OTEL_AWS_APP_SIGNALS_ENABLED=true, or service name. So I ended up with no traces being tied and displayed next to their corresponding agents.
    3. Endpoint Configuration I think this is fine today, not representing a problem. Alternative Approach Somehow, using the native library was causing some of the features I wanted in signals to be ignored, for instance I was not able to browse traces by ECS service.

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.