Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ If your change does not need a CHANGELOG entry, add the "skip changelog" label t

## Unreleased

- fix(agent-observability): fall back to OTEL_EXPORTER_OTLP_ENDPOINT for unsampled spans; also export unsampled spans to non-AWS endpoints
([#738](https://github.com/aws-observability/aws-otel-python-instrumentation/pull/738))
- feat: auto-detect and mutually exclude AWS native vs third-party agentic instrumentors; add `AWS_AGENTIC_INSTRUMENTATION_OPT_IN` env var to override auto-detection
([#729](https://github.com/aws-observability/aws-otel-python-instrumentation/pull/729))
- fix(lambda-layer): align context propagation with JS — delegate to global propagator so W3C traceparent is no longer ignored when X-Ray active tracing is enabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogRecordExporter, LogRecordExporter
from opentelemetry.sdk.environment_variables import (
_OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED,
OTEL_EXPORTER_OTLP_ENDPOINT,
OTEL_EXPORTER_OTLP_METRICS_PROTOCOL,
OTEL_EXPORTER_OTLP_PROTOCOL,
OTEL_TRACES_SAMPLER_ARG,
Expand Down Expand Up @@ -331,11 +332,20 @@ def _export_unsampled_span_for_agent_observability(trace_provider: TracerProvide
return

traces_endpoint = os.environ.get(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT)
if traces_endpoint and _is_aws_otlp_endpoint(traces_endpoint, XRAY_SERVICE):
if not traces_endpoint:
base_endpoint = os.environ.get(OTEL_EXPORTER_OTLP_ENDPOINT)
if base_endpoint:
Comment thread
liustve marked this conversation as resolved.
traces_endpoint = base_endpoint.rstrip("/") + "/v1/traces"
if not traces_endpoint:
return

Comment thread
liustve marked this conversation as resolved.
if _is_aws_otlp_endpoint(traces_endpoint, XRAY_SERVICE):
endpoint, region = _extract_endpoint_and_region_from_otlp_endpoint(traces_endpoint)
span_exporter = _create_aws_otlp_exporter(endpoint=endpoint, service=XRAY_SERVICE, region=region)
else:
span_exporter = OTLPSpanExporter(endpoint=traces_endpoint)

trace_provider.add_span_processor(BatchUnsampledSpanProcessor(span_exporter=span_exporter))
trace_provider.add_span_processor(BatchUnsampledSpanProcessor(span_exporter=span_exporter))


def _is_defer_to_workers_enabled():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,43 @@ def test_export_unsampled_span_for_agent_observability(self):
os.environ.pop("AGENT_OBSERVABILITY_ENABLED", None)
os.environ.pop("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", None)

mock_tracer_provider.reset_mock()

os.environ["AGENT_OBSERVABILITY_ENABLED"] = "true"
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "http://localhost:4318"
_export_unsampled_span_for_agent_observability(mock_tracer_provider, Resource.get_empty())
self.assertEqual(mock_tracer_provider.add_span_processor.call_count, 1)
processor = mock_tracer_provider.add_span_processor.call_args_list[0].args[0]
self.assertIsInstance(processor, BatchUnsampledSpanProcessor)
self.assertEqual(processor.span_exporter._endpoint, "http://localhost:4318/v1/traces")
Comment thread
liustve marked this conversation as resolved.

os.environ.pop("AGENT_OBSERVABILITY_ENABLED", None)
os.environ.pop("OTEL_EXPORTER_OTLP_ENDPOINT", None)

Comment thread
liustve marked this conversation as resolved.
mock_tracer_provider.reset_mock()

os.environ["AGENT_OBSERVABILITY_ENABLED"] = "true"
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://xray.us-west-2.amazonaws.com"
_export_unsampled_span_for_agent_observability(mock_tracer_provider, Resource.get_empty())
self.assertEqual(mock_tracer_provider.add_span_processor.call_count, 1)

os.environ.pop("AGENT_OBSERVABILITY_ENABLED", None)
os.environ.pop("OTEL_EXPORTER_OTLP_ENDPOINT", None)

mock_tracer_provider.reset_mock()

os.environ["AGENT_OBSERVABILITY_ENABLED"] = "true"
os.environ["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"] = "https://xray.us-east-1.amazonaws.com/v1/traces"
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "http://localhost:4318"
_export_unsampled_span_for_agent_observability(mock_tracer_provider, Resource.get_empty())
self.assertEqual(mock_tracer_provider.add_span_processor.call_count, 1)
processor = mock_tracer_provider.add_span_processor.call_args_list[0].args[0]
self.assertIsInstance(processor, BatchUnsampledSpanProcessor)

os.environ.pop("AGENT_OBSERVABILITY_ENABLED", None)
os.environ.pop("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", None)
os.environ.pop("OTEL_EXPORTER_OTLP_ENDPOINT", None)

# pylint: disable=no-self-use
def test_export_unsampled_span_for_agent_observability_uses_aws_exporter(self):
"""Test that OTLPAwsSpanExporter is used for AWS endpoints"""
Expand Down
Loading