From 9685686cd52765fbbc26fb2f6e00c763fde9a501 Mon Sep 17 00:00:00 2001 From: karthik Date: Tue, 20 Jan 2026 12:05:01 -0500 Subject: [PATCH] fix(bedrock): add error logging to instrumented functions Adds try/except blocks to record exceptions in spans for all four instrumented functions: - _instrumented_model_invoke - _instrumented_model_invoke_with_response_stream - _instrumented_converse - _instrumented_converse_stream When an exception occurs, the span now: - Sets ERROR_TYPE attribute with the exception class name - Records the exception details via span.record_exception() - Sets span status to ERROR with the exception message - Increments the exception counter metric This follows the OTel error recording pattern per: https://opentelemetry.io/docs/languages/python/instrumentation/#record-exceptions-in-spans Partial fix for #412 --- .../instrumentation/bedrock/__init__.py | 57 +++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/packages/opentelemetry-instrumentation-bedrock/opentelemetry/instrumentation/bedrock/__init__.py b/packages/opentelemetry-instrumentation-bedrock/opentelemetry/instrumentation/bedrock/__init__.py index 885dd92150..8a6c151519 100644 --- a/packages/opentelemetry-instrumentation-bedrock/opentelemetry/instrumentation/bedrock/__init__.py +++ b/packages/opentelemetry-instrumentation-bedrock/opentelemetry/instrumentation/bedrock/__init__.py @@ -53,6 +53,8 @@ Meters, ) from opentelemetry.trace import Span, SpanKind, get_tracer +from opentelemetry.trace.status import Status, StatusCode +from opentelemetry.semconv.attributes.error_attributes import ERROR_TYPE from wrapt import wrap_function_wrapper @@ -203,7 +205,18 @@ def with_instrumentation(*args, **kwargs): with tracer.start_as_current_span( _BEDROCK_INVOKE_SPAN_NAME, kind=SpanKind.CLIENT ) as span: - response = fn(*args, **kwargs) + try: + response = fn(*args, **kwargs) + except Exception as e: + span.set_attribute(ERROR_TYPE, e.__class__.__name__) + span.record_exception(e) + span.set_status(Status(StatusCode.ERROR, str(e))) + if metric_params.exception_counter: + metric_params.exception_counter.add( + 1, attributes={"error.type": e.__class__.__name__} + ) + raise + _handle_call(span, kwargs, response, metric_params, event_logger) return response @@ -220,7 +233,19 @@ def with_instrumentation(*args, **kwargs): span = tracer.start_span(_BEDROCK_INVOKE_SPAN_NAME, kind=SpanKind.CLIENT) - response = fn(*args, **kwargs) + try: + response = fn(*args, **kwargs) + except Exception as e: + span.set_attribute(ERROR_TYPE, e.__class__.__name__) + span.record_exception(e) + span.set_status(Status(StatusCode.ERROR, str(e))) + span.end() + if metric_params.exception_counter: + metric_params.exception_counter.add( + 1, attributes={"error.type": e.__class__.__name__} + ) + raise + _handle_stream_call(span, kwargs, response, metric_params, event_logger) return response @@ -240,7 +265,18 @@ def with_instrumentation(*args, **kwargs): with tracer.start_as_current_span( _BEDROCK_CONVERSE_SPAN_NAME, kind=SpanKind.CLIENT ) as span: - response = fn(*args, **kwargs) + try: + response = fn(*args, **kwargs) + except Exception as e: + span.set_attribute(ERROR_TYPE, e.__class__.__name__) + span.record_exception(e) + span.set_status(Status(StatusCode.ERROR, str(e))) + if metric_params.exception_counter: + metric_params.exception_counter.add( + 1, attributes={"error.type": e.__class__.__name__} + ) + raise + _handle_converse(span, kwargs, response, metric_params, event_logger) return response @@ -255,7 +291,20 @@ def with_instrumentation(*args, **kwargs): return fn(*args, **kwargs) span = tracer.start_span(_BEDROCK_CONVERSE_SPAN_NAME, kind=SpanKind.CLIENT) - response = fn(*args, **kwargs) + + try: + response = fn(*args, **kwargs) + except Exception as e: + span.set_attribute(ERROR_TYPE, e.__class__.__name__) + span.record_exception(e) + span.set_status(Status(StatusCode.ERROR, str(e))) + span.end() + if metric_params.exception_counter: + metric_params.exception_counter.add( + 1, attributes={"error.type": e.__class__.__name__} + ) + raise + if span.is_recording(): _handle_converse_stream(span, kwargs, response, metric_params, event_logger)