mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-29 13:12:39 +08:00
AwsLambdaInstrumentor handles and re-raises handler function exception (#2245)
This commit is contained in:
@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#2136](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2136))
|
||||
- `opentelemetry-resource-detector-azure` Suppress instrumentation for `urllib` call
|
||||
([#2178](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2178))
|
||||
- AwsLambdaInstrumentor handles and re-raises function exception ([#2245](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2245))
|
||||
|
||||
## Version 1.22.0/0.43b0 (2023-12-14)
|
||||
|
||||
|
@ -97,6 +97,7 @@ from opentelemetry.trace import (
|
||||
get_tracer_provider,
|
||||
)
|
||||
from opentelemetry.trace.propagation import get_current_span
|
||||
from opentelemetry.trace.status import Status, StatusCode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -278,6 +279,7 @@ def _set_api_gateway_v2_proxy_attributes(
|
||||
return span
|
||||
|
||||
|
||||
# pylint: disable=too-many-statements
|
||||
def _instrument(
|
||||
wrapped_module_name,
|
||||
wrapped_function_name,
|
||||
@ -287,6 +289,8 @@ def _instrument(
|
||||
disable_aws_context_propagation: bool = False,
|
||||
meter_provider: MeterProvider = None,
|
||||
):
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
def _instrumented_lambda_handler_call( # noqa pylint: disable=too-many-branches
|
||||
call_wrapped, instance, args, kwargs
|
||||
):
|
||||
@ -350,7 +354,13 @@ def _instrument(
|
||||
lambda_context.aws_request_id,
|
||||
)
|
||||
|
||||
result = call_wrapped(*args, **kwargs)
|
||||
exception = None
|
||||
try:
|
||||
result = call_wrapped(*args, **kwargs)
|
||||
except Exception as exc: # pylint: disable=W0703
|
||||
exception = exc
|
||||
span.set_status(Status(StatusCode.ERROR))
|
||||
span.record_exception(exception)
|
||||
|
||||
# If the request came from an API Gateway, extract http attributes from the event
|
||||
# https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/instrumentation/aws-lambda.md#api-gateway
|
||||
@ -398,6 +408,9 @@ def _instrument(
|
||||
"MeterProvider was missing `force_flush` method. This is necessary in case of a Lambda freeze and would exist in the OTel SDK implementation."
|
||||
)
|
||||
|
||||
if exception is not None:
|
||||
raise exception.with_traceback(exception.__traceback__)
|
||||
|
||||
return result
|
||||
|
||||
wrap_function_wrapper(
|
||||
|
@ -19,3 +19,7 @@ def handler(event, context):
|
||||
|
||||
def rest_api_handler(event, context):
|
||||
return {"statusCode": 200, "body": "200 ok"}
|
||||
|
||||
|
||||
def handler_exc(event, context):
|
||||
raise Exception("500 internal server error")
|
||||
|
@ -40,7 +40,7 @@ from opentelemetry.propagators.aws.aws_xray_propagator import (
|
||||
from opentelemetry.semconv.resource import ResourceAttributes
|
||||
from opentelemetry.semconv.trace import SpanAttributes
|
||||
from opentelemetry.test.test_base import TestBase
|
||||
from opentelemetry.trace import NoOpTracerProvider, SpanKind
|
||||
from opentelemetry.trace import NoOpTracerProvider, SpanKind, StatusCode
|
||||
from opentelemetry.trace.propagation.tracecontext import (
|
||||
TraceContextTextMapPropagator,
|
||||
)
|
||||
@ -410,6 +410,27 @@ class TestAwsLambdaInstrumentor(TestBase):
|
||||
|
||||
assert spans
|
||||
|
||||
def test_lambda_handles_handler_exception(self):
|
||||
exc_env_patch = mock.patch.dict(
|
||||
"os.environ",
|
||||
{_HANDLER: "tests.mocks.lambda_function.handler_exc"},
|
||||
)
|
||||
exc_env_patch.start()
|
||||
AwsLambdaInstrumentor().instrument()
|
||||
# instrumentor re-raises the exception
|
||||
with self.assertRaises(Exception):
|
||||
mock_execute_lambda()
|
||||
|
||||
spans = self.memory_exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 1)
|
||||
span = spans[0]
|
||||
self.assertEqual(span.status.status_code, StatusCode.ERROR)
|
||||
self.assertEqual(len(span.events), 1)
|
||||
event = span.events[0]
|
||||
self.assertEqual(event.name, "exception")
|
||||
|
||||
exc_env_patch.stop()
|
||||
|
||||
def test_uninstrument(self):
|
||||
AwsLambdaInstrumentor().instrument()
|
||||
|
||||
|
Reference in New Issue
Block a user