Subchapter 37.38
references/cloudwatch/tracing.mdMarkdown9 KBView on GitHub
X-Ray SDK is in maintenance mode. Use ADOT (OpenTelemetry) for all new projects.
| Criteria | X-Ray SDK | ADOT (OpenTelemetry) |
|---|---|---|
| Status | Maintenance mode | Actively developed |
| Multi-backend | X-Ray only | CloudWatch, X-Ray, Prometheus, OpenSearch |
| Auto-instrumentation | Limited | Java, Python (compute); Node.js (Lambda layer only) |
| Vendor lock-in | AWS-specific | Vendor-neutral (OTel standard) |
| Lambda support | Built-in daemon | Lambda layer (auto-instrumentation) |
| Recommendation | Legacy apps only | All new projects |
Migration path: AWS provides migration guides from X-Ray SDK to OpenTelemetry SDK. The CloudWatch agent now also supports sending traces to X-Ray — no separate daemon needed.
X-Amzn-Trace-Id: Root=1-58406520-a006649127e371903a2de979;Parent=53995c3f42cd8ad8;Sampled=1Format: 1-{8 hex epoch}-{24 hex unique}. W3C trace IDs are supported (reformatted).
| Feature | Annotations | Metadata |
|---|---|---|
| Indexed | Yes — Searchable with filter expressions | No — Not indexed |
| Value types | String, Number, Boolean only | Any type (objects, arrays) |
| Limit | 50 indexed per trace (API accepts more, but only 50 are searchable) | No limit (within segment size) |
| Key format | Alphanumeric + underscore only | Any key (AWS. prefix reserved) |
| Use case | Filtering/grouping traces | Storing debug data |
Rule of thumb: If you need to search for it → annotation. If you just need to store it → metadata.
WARNING: 50 annotations per trace is a hard limit. Plan your annotation schema carefully.
| Parameter | Description |
|---|---|
| Priority | 1–9999 (lower = higher priority) |
| Reservoir | Fixed traces/second before applying rate |
| Rate | Percentage of additional requests (0–100 in console, 0.0–1.0 in API/JSON) |
| Service name | Wildcards * and ? supported |
| Service type | e.g., AWS::EC2::Instance, AWS::Lambda::Function |
| HTTP method | GET, POST, etc. |
| URL path | Path portion of URL |
Sampling decision is made once by the root service. Downstream services honor the upstream decision regardless of their own rules. Custom rules only apply where no sampling decision exists yet.
SamplingRateBoost — auto-increases rate during anomaliesMaxRate — ceiling for boosted rateCooldownWindowMinutes — prevents continuous boosts (recommended when SamplingRateBoost is configured)[Receivers] → [Processors] → [Exporters]The
0.0.0.0receivers below listen on every interface with no TLS and no authentication. Bind them to127.0.0.1when the senders are on the same host; otherwise it is recommended to restrict the OTLP4317/4318ports via security groups or host firewall and to avoid co-locating untrusted workloads. This guide does not apply those controls, so assess and configure them for your environment.
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 30s
send_batch_size: 8192
exporters:
awsxray:
region: us-east-1
awsemf:
namespace: MyApplication
region: us-east-1
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [awsxray]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [awsemf]resources:
limits:
memory: 200Mi
requests:
cpu: 250m
memory: 100Midimension_rollup_option + metric_declarations; Prometheus: metric_relabel_configs)Filter as early as possible in the pipeline to reduce cost and cardinality.
import { Tracing } from 'aws-cdk-lib/aws-lambda';
const fn = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
tracing: Tracing.ACTIVE,
});const api = new apigateway.RestApi(this, 'MyApi', {
deployOptions: {
tracingEnabled: true,
},
});Or via CLI: aws apigateway update-stage --rest-api-id <id> --stage-name prod --patch-operations op=replace,path=/tracingEnabled,value=true
Inject trace ID into application logs for cross-pillar correlation:
import logging
from opentelemetry import trace
ctx = trace.get_current_span().get_span_context()
trace_id = format(ctx.trace_id, '032x')
logging.info("Processing request", extra={"trace_id": trace_id})In OTel, all span attributes become X-Ray metadata by default. To make an attribute a searchable X-Ray annotation, add its key to the aws.xray.annotations list:
span.set_attribute("aws.xray.annotations", ["order_id", "customer_tier"])
span.set_attribute("order_id", "12345")Without this, you lose all annotation-based filtering after migration.
The ADOT collector config must include the awsproxy extension (or use the CloudWatch agent as a proxy) for X-Ray centralized sampling rules to work. Without a proxy, the SDK falls back to a default local rule (1 req/sec + 5%):
extensions:
awsproxy:
endpoint: 127.0.0.1:2000
service:
extensions: [awsproxy]SDK env vars: OTEL_TRACES_SAMPLER=xray and OTEL_TRACES_SAMPLER_ARG=endpoint=http://localhost:2000
Centralized sampling language support: Java, .NET, Python, Node.js (ADOT). Vanilla OTel SDK: Java, .NET, Go.
OTel defaults to W3C Trace Context; X-Ray SDK uses X-Ray trace header. During migration, configure both:
OTEL_PROPAGATORS=xray,tracecontextWithout this, traces break at service boundaries between old and new instrumentation.
Both use port 2000. Running both simultaneously causes silent data loss.
ADOT Lambda layers increase memory usage and cold start time. For latency-sensitive functions where you don’t need OTel’s multi-backend capabilities, X-Ray SDK may still be preferable.
ADOT Collector 0.34.0+ (X-Ray Exporter 0.86.0+) is required to accept W3C-format trace IDs. Older versions silently reject them.
Using X-Ray SDK for new projects — Maintenance mode. Use ADOT/OpenTelemetry.
Storing searchable data as metadata — Metadata is NOT indexed. Use annotations for data you need to filter by.
Exceeding 50 annotations per trace — Hard limit. Plan your annotation schema.
Not stripping X-Amzn-Trace-Id from untrusted requests — Users can inject trace IDs or sampling decisions.
Default sampling for all services — 1 req/sec + 5% is too conservative for low-traffic services (may miss issues) and too aggressive for high-traffic (unnecessary cost). Tune per service.
StepFunctions tracing overrides Lambda — When StepFunction tracing is enabled, downstream Lambda tracing is always enabled regardless of Lambda’s own config.
Cross-account tracing — Trace IDs propagate naturally across accounts, but unified cross-account viewing requires CloudWatch Observability Access Manager (OAM) setup with monitoring/source account links.