diff --git a/packages/opentelemetry-instrumentation-cohere/opentelemetry/instrumentation/cohere/__init__.py b/packages/opentelemetry-instrumentation-cohere/opentelemetry/instrumentation/cohere/__init__.py index 5430ec9414..beffc4dd02 100644 --- a/packages/opentelemetry-instrumentation-cohere/opentelemetry/instrumentation/cohere/__init__.py +++ b/packages/opentelemetry-instrumentation-cohere/opentelemetry/instrumentation/cohere/__init__.py @@ -287,7 +287,6 @@ async def _awrap( if span.is_recording(): span.set_status(Status(StatusCode.ERROR, str(e))) span.record_exception(e) - span.end() raise set_span_response_attributes(span, response) diff --git a/packages/opentelemetry-instrumentation-cohere/tests/test_async_error_handling.py b/packages/opentelemetry-instrumentation-cohere/tests/test_async_error_handling.py new file mode 100644 index 0000000000..73484ca2a6 --- /dev/null +++ b/packages/opentelemetry-instrumentation-cohere/tests/test_async_error_handling.py @@ -0,0 +1,42 @@ +import logging + +import cohere +import pytest +from opentelemetry.instrumentation.cohere import CohereInstrumentor +from opentelemetry.trace import StatusCode + + +@pytest.mark.asyncio +async def test_async_cohere_exception_records_error_once( + caplog, monkeypatch, span_exporter, tracer_provider +): + async def failing_chat(self, *args, **kwargs): + raise RuntimeError("cohere async failure") + + monkeypatch.setattr(cohere.AsyncClient, "chat", failing_chat) + instrumentor = CohereInstrumentor() + instrumentor.instrument(tracer_provider=tracer_provider) + + try: + with caplog.at_level(logging.WARNING, logger="opentelemetry.sdk.trace"): + with pytest.raises(RuntimeError, match="cohere async failure"): + await cohere.AsyncClient("test_api_key").chat( + model="command", message="Tell me a joke, pirate style" + ) + finally: + instrumentor.uninstrument() + + spans = span_exporter.get_finished_spans() + assert len(spans) == 1 + span = spans[0] + assert span.name == "cohere.chat" + assert span.status.status_code == StatusCode.ERROR + assert "cohere async failure" in span.status.description + assert any( + event.name == "exception" + and "cohere async failure" in event.attributes.get("exception.message", "") + for event in span.events + ) + assert not any( + "Calling end() on an ended span" in record.message for record in caplog.records + )