Skip to content

Commit a47810c

Browse files
ocelotlxrmxemdneto
authored
Enable global propagator for AWS instrumentation (#2599)
* Enable global propagator for AWS instrumentation Fixes #2598 * Add entry point test case * Update instrumentation/opentelemetry-instrumentation-aws-lambda/pyproject.toml Co-authored-by: Riccardo Magliocchetti <[email protected]> * Add test for propagator * Fix entry point name * Update instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py Co-authored-by: Emídio Neto <[email protected]> * Try with ubuntu latest * Try with 24.04 * Fix propagator key * Fix lint * Revert ununtuns --------- Co-authored-by: Riccardo Magliocchetti <[email protected]> Co-authored-by: Emídio Neto <[email protected]>
1 parent e799a74 commit a47810c

File tree

9 files changed

+66
-86
lines changed

9 files changed

+66
-86
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- `opentelemetry-instrumentation-flask` Add `http.route` and `http.target` to metric attributes
1313
([#2621](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2621))
14+
- `opentelemetry-instrumentation-aws-lambda` Enable global propagator for AWS instrumentation
15+
([#2708](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2708))
1416
- `opentelemetry-instrumentation-sklearn` Deprecated the sklearn instrumentation
1517
([#2708](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2708))
1618
- `opentelemetry-instrumentation-pyramid` Record exceptions raised when serving a request

instrumentation/opentelemetry-instrumentation-aws-lambda/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ dependencies = [
3333
[project.optional-dependencies]
3434
instruments = []
3535

36+
[project.entry-points.opentelemetry_instrumentor]
37+
aws-lambda = "opentelemetry.instrumentation.aws_lambda:AwsLambdaInstrumentor"
38+
3639
[project.urls]
3740
Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-aws-lambda"
3841

instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py

Lines changed: 5 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,6 @@ def custom_event_context_extractor(lambda_event):
8383
from opentelemetry.instrumentation.utils import unwrap
8484
from opentelemetry.metrics import MeterProvider, get_meter_provider
8585
from opentelemetry.propagate import get_global_textmap
86-
from opentelemetry.propagators.aws.aws_xray_propagator import (
87-
TRACE_HEADER_KEY,
88-
AwsXRayPropagator,
89-
)
9086
from opentelemetry.semconv.resource import ResourceAttributes
9187
from opentelemetry.semconv.trace import SpanAttributes
9288
from opentelemetry.trace import (
@@ -96,7 +92,6 @@ def custom_event_context_extractor(lambda_event):
9692
get_tracer,
9793
get_tracer_provider,
9894
)
99-
from opentelemetry.trace.propagation import get_current_span
10095
from opentelemetry.trace.status import Status, StatusCode
10196

10297
logger = logging.getLogger(__name__)
@@ -107,9 +102,6 @@ def custom_event_context_extractor(lambda_event):
107102
OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT = (
108103
"OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT"
109104
)
110-
OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION = (
111-
"OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION"
112-
)
113105

114106

115107
def _default_event_context_extractor(lambda_event: Any) -> Context:
@@ -145,7 +137,6 @@ def _default_event_context_extractor(lambda_event: Any) -> Context:
145137
def _determine_parent_context(
146138
lambda_event: Any,
147139
event_context_extractor: Callable[[Any], Context],
148-
disable_aws_context_propagation: bool = False,
149140
) -> Context:
150141
"""Determine the parent context for the current Lambda invocation.
151142
@@ -159,36 +150,14 @@ def _determine_parent_context(
159150
Event as input and extracts an OTel Context from it. By default,
160151
the context is extracted from the HTTP headers of an API Gateway
161152
request.
162-
disable_aws_context_propagation: By default, this instrumentation
163-
will try to read the context from the `_X_AMZN_TRACE_ID` environment
164-
variable set by Lambda, set this to `True` to disable this behavior.
165153
Returns:
166154
A Context with configuration found in the carrier.
167155
"""
168-
parent_context = None
169-
170-
if not disable_aws_context_propagation:
171-
xray_env_var = os.environ.get(_X_AMZN_TRACE_ID)
172156

173-
if xray_env_var:
174-
parent_context = AwsXRayPropagator().extract(
175-
{TRACE_HEADER_KEY: xray_env_var}
176-
)
177-
178-
if (
179-
parent_context
180-
and get_current_span(parent_context)
181-
.get_span_context()
182-
.trace_flags.sampled
183-
):
184-
return parent_context
157+
if event_context_extractor is None:
158+
return _default_event_context_extractor(lambda_event)
185159

186-
if event_context_extractor:
187-
parent_context = event_context_extractor(lambda_event)
188-
else:
189-
parent_context = _default_event_context_extractor(lambda_event)
190-
191-
return parent_context
160+
return event_context_extractor(lambda_event)
192161

193162

194163
def _set_api_gateway_v1_proxy_attributes(
@@ -286,14 +255,15 @@ def _instrument(
286255
flush_timeout,
287256
event_context_extractor: Callable[[Any], Context],
288257
tracer_provider: TracerProvider = None,
289-
disable_aws_context_propagation: bool = False,
290258
meter_provider: MeterProvider = None,
291259
):
260+
292261
# pylint: disable=too-many-locals
293262
# pylint: disable=too-many-statements
294263
def _instrumented_lambda_handler_call( # noqa pylint: disable=too-many-branches
295264
call_wrapped, instance, args, kwargs
296265
):
266+
297267
orig_handler_name = ".".join(
298268
[wrapped_module_name, wrapped_function_name]
299269
)
@@ -303,7 +273,6 @@ def _instrumented_lambda_handler_call( # noqa pylint: disable=too-many-branches
303273
parent_context = _determine_parent_context(
304274
lambda_event,
305275
event_context_extractor,
306-
disable_aws_context_propagation,
307276
)
308277

309278
try:
@@ -451,9 +420,6 @@ def _instrument(self, **kwargs):
451420
Event as input and extracts an OTel Context from it. By default,
452421
the context is extracted from the HTTP headers of an API Gateway
453422
request.
454-
``disable_aws_context_propagation``: By default, this instrumentation
455-
will try to read the context from the `_X_AMZN_TRACE_ID` environment
456-
variable set by Lambda, set this to `True` to disable this behavior.
457423
"""
458424
lambda_handler = os.environ.get(ORIG_HANDLER, os.environ.get(_HANDLER))
459425
# pylint: disable=attribute-defined-outside-init
@@ -475,16 +441,6 @@ def _instrument(self, **kwargs):
475441
flush_timeout_env,
476442
)
477443

478-
disable_aws_context_propagation = kwargs.get(
479-
"disable_aws_context_propagation", False
480-
) or os.getenv(
481-
OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION, "False"
482-
).strip().lower() in (
483-
"true",
484-
"1",
485-
"t",
486-
)
487-
488444
_instrument(
489445
self._wrapped_module_name,
490446
self._wrapped_function_name,
@@ -493,7 +449,6 @@ def _instrument(self, **kwargs):
493449
"event_context_extractor", _default_event_context_extractor
494450
),
495451
tracer_provider=kwargs.get("tracer_provider"),
496-
disable_aws_context_propagation=disable_aws_context_propagation,
497452
meter_provider=kwargs.get("meter_provider"),
498453
)
499454

instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,19 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
1415
import os
1516
from dataclasses import dataclass
16-
from importlib import import_module
17+
from importlib import import_module, reload
1718
from typing import Any, Callable, Dict
1819
from unittest import mock
1920

21+
from opentelemetry import propagate
2022
from opentelemetry.environment_variables import OTEL_PROPAGATORS
2123
from opentelemetry.instrumentation.aws_lambda import (
2224
_HANDLER,
2325
_X_AMZN_TRACE_ID,
2426
OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT,
25-
OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION,
2627
AwsLambdaInstrumentor,
2728
)
2829
from opentelemetry.propagate import get_global_textmap
@@ -37,6 +38,7 @@
3738
from opentelemetry.trace.propagation.tracecontext import (
3839
TraceContextTextMapPropagator,
3940
)
41+
from opentelemetry.util._importlib_metadata import entry_points
4042

4143
from .mocks.api_gateway_http_api_event import (
4244
MOCK_LAMBDA_API_GATEWAY_HTTP_API_EVENT,
@@ -56,6 +58,7 @@ def __init__(self, aws_request_id, invoked_function_arn):
5658
)
5759

5860
MOCK_XRAY_TRACE_ID = 0x5FB7331105E8BB83207FA31D4D9CDB4C
61+
5962
MOCK_XRAY_TRACE_ID_STR = f"{MOCK_XRAY_TRACE_ID:x}"
6063
MOCK_XRAY_PARENT_SPAN_ID = 0x3328B8445A6DBAD2
6164
MOCK_XRAY_TRACE_CONTEXT_COMMON = f"Root={TRACE_ID_VERSION}-{MOCK_XRAY_TRACE_ID_STR[:TRACE_ID_FIRST_PART_LENGTH]}-{MOCK_XRAY_TRACE_ID_STR[TRACE_ID_FIRST_PART_LENGTH:]};Parent={MOCK_XRAY_PARENT_SPAN_ID:x}"
@@ -81,6 +84,7 @@ def mock_execute_lambda(event=None):
8184
"""Mocks the AWS Lambda execution.
8285
8386
NOTE: We don't use `moto`'s `mock_lambda` because we are not instrumenting
87+
8488
calls to AWS Lambda using the AWS SDK. Instead, we are instrumenting AWS
8589
Lambda itself.
8690
@@ -122,10 +126,13 @@ def test_active_tracing(self):
122126
{
123127
**os.environ,
124128
# Using Active tracing
129+
OTEL_PROPAGATORS: "xray-lambda",
125130
_X_AMZN_TRACE_ID: MOCK_XRAY_TRACE_CONTEXT_SAMPLED,
126131
},
127132
)
133+
128134
test_env_patch.start()
135+
reload(propagate)
129136

130137
AwsLambdaInstrumentor().instrument()
131138

@@ -173,8 +180,7 @@ class TestCase:
173180
xray_traceid: str
174181
expected_state_value: str = None
175182
expected_trace_state_len: int = 0
176-
disable_aws_context_propagation: bool = False
177-
disable_aws_context_propagation_envvar: str = ""
183+
propagators: str = "tracecontext"
178184

179185
def custom_event_context_extractor(lambda_event):
180186
return get_global_textmap().extract(lambda_event["foo"]["headers"])
@@ -226,9 +232,10 @@ def custom_event_context_extractor(lambda_event):
226232
expected_traceid=MOCK_XRAY_TRACE_ID,
227233
expected_parentid=MOCK_XRAY_PARENT_SPAN_ID,
228234
xray_traceid=MOCK_XRAY_TRACE_CONTEXT_SAMPLED,
235+
propagators="xray-lambda",
229236
),
230237
TestCase(
231-
name="custom_extractor_sampled_xray_disable_aws_propagation",
238+
name="custom_extractor_sampled_xray",
232239
custom_extractor=custom_event_context_extractor,
233240
context={
234241
"foo": {
@@ -238,24 +245,21 @@ def custom_event_context_extractor(lambda_event):
238245
}
239246
}
240247
},
241-
disable_aws_context_propagation=True,
242248
expected_traceid=MOCK_W3C_TRACE_ID,
243249
expected_parentid=MOCK_W3C_PARENT_SPAN_ID,
244250
expected_trace_state_len=3,
245251
expected_state_value=MOCK_W3C_TRACE_STATE_VALUE,
246252
xray_traceid=MOCK_XRAY_TRACE_CONTEXT_SAMPLED,
247253
),
248254
TestCase(
249-
name="no_custom_extractor_xray_disable_aws_propagation_via_env_var",
255+
name="no_custom_extractor_xray",
250256
custom_extractor=None,
251257
context={
252258
"headers": {
253259
TraceContextTextMapPropagator._TRACEPARENT_HEADER_NAME: MOCK_W3C_TRACE_CONTEXT_SAMPLED,
254260
TraceContextTextMapPropagator._TRACESTATE_HEADER_NAME: f"{MOCK_W3C_TRACE_STATE_KEY}={MOCK_W3C_TRACE_STATE_VALUE},foo=1,bar=2",
255261
}
256262
},
257-
disable_aws_context_propagation=False,
258-
disable_aws_context_propagation_envvar="true",
259263
expected_traceid=MOCK_W3C_TRACE_ID,
260264
expected_parentid=MOCK_W3C_PARENT_SPAN_ID,
261265
expected_trace_state_len=3,
@@ -264,21 +268,21 @@ def custom_event_context_extractor(lambda_event):
264268
),
265269
]
266270
for test in tests:
271+
267272
test_env_patch = mock.patch.dict(
268273
"os.environ",
269274
{
270275
**os.environ,
271276
# NOT Active Tracing
272277
_X_AMZN_TRACE_ID: test.xray_traceid,
273-
OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION: test.disable_aws_context_propagation_envvar,
274-
# NOT using the X-Ray Propagator
275-
OTEL_PROPAGATORS: "tracecontext",
278+
OTEL_PROPAGATORS: test.propagators,
276279
},
277280
)
278281
test_env_patch.start()
282+
reload(propagate)
283+
279284
AwsLambdaInstrumentor().instrument(
280285
event_context_extractor=test.custom_extractor,
281-
disable_aws_context_propagation=test.disable_aws_context_propagation,
282286
)
283287
mock_execute_lambda(test.context)
284288
spans = self.memory_exporter.get_finished_spans()
@@ -374,6 +378,7 @@ def test_lambda_handles_invalid_event_source(self):
374378
},
375379
)
376380
test_env_patch.start()
381+
reload(propagate)
377382

378383
AwsLambdaInstrumentor().instrument()
379384

@@ -513,3 +518,15 @@ def test_no_op_tracer_provider(self):
513518
spans = self.memory_exporter.get_finished_spans()
514519
assert spans is not None
515520
self.assertEqual(len(spans), 0)
521+
522+
def test_load_entry_point(self):
523+
self.assertIs(
524+
next(
525+
iter(
526+
entry_points(
527+
group="opentelemetry_instrumentor", name="aws-lambda"
528+
)
529+
)
530+
).load(),
531+
AwsLambdaInstrumentor,
532+
)

propagator/opentelemetry-propagator-aws-xray/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ dependencies = [
3030

3131
[project.entry-points.opentelemetry_propagator]
3232
xray = "opentelemetry.propagators.aws:AwsXRayPropagator"
33-
xray_lambda = "opentelemetry.propagators.aws:AwsXRayLambdaPropagator"
33+
xray-lambda = "opentelemetry.propagators.aws:AwsXRayLambdaPropagator"
3434

3535
[project.urls]
3636
Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/propagator/opentelemetry-propagator-aws-xray"

propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/__init__.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from opentelemetry.propagators.aws.aws_xray_propagator import AwsXRayPropagator
15+
from opentelemetry.propagators.aws.aws_xray_propagator import (
16+
AwsXRayLambdaPropagator,
17+
AwsXRayPropagator,
18+
)
1619

17-
__all__ = ["AwsXRayPropagator"]
20+
__all__ = ["AwsXRayPropagator", "AwsXRayLambdaPropagator"]

propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,9 @@ def fields(self):
328328
return {TRACE_HEADER_KEY}
329329

330330

331-
class AwsXrayLambdaPropagator(AwsXRayPropagator):
331+
class AwsXRayLambdaPropagator(AwsXRayPropagator):
332332
"""Implementation of the AWS X-Ray Trace Header propagation protocol but
333-
with special handling for Lambda's ``_X_AMZN_TRACE_ID` environment
333+
with special handling for Lambda's ``_X_AMZN_TRACE_ID`` environment
334334
variable.
335335
"""
336336

0 commit comments

Comments
 (0)