From 673e4aadb4836ff406e0ece9d90e9282e277d7be Mon Sep 17 00:00:00 2001 From: Tom de Bruijn Date: Fri, 3 Feb 2023 05:30:57 +0100 Subject: [PATCH] Record exception in Celery instrumentation (#1573) * Add tests for errors in Celery tasks I noticed there were no tests for the error scenario in the Celery package. This commit adds a basic test, based on the previous test and how I see other packages test the error status on the span. Part of #987 * Record exception in Celery instrumentation In addition to setting the status on the span, also record the exception on the span. This adds an event to the span with more details about the error, following the format other instrumentations also use. * Update CHANGELOG with Celery record exception * Fix lint code formatting issues * Move Celery error tests to the functional tests The celery tests failed on Python 3.11. This is most likely due to this issue in billiard, a celery dependency, about it not working on Python 3.11 because of the error reported in the CI: https://github.com/celery/billiard/issues/377 It's been fixed in billiard 4.1.0, but celery is locked on billiard version lower than 4, so it cannot use this version with the fix. This issue does not arise on the Docker tests, because they use Python 3.9.16. I've moved the error test span event assertions to the error test that is available in the functional tests, and removed the unit test. That way, the build will run successfully. * Remove duplicate entry in changelog This was added in a recent merge commit on this PR branch. * Remove unused test code With the move of the tests for tasks with errors to the functional tests, remove the unit test's error task and unused imports. --------- Co-authored-by: Srikanth Chekuri --- CHANGELOG.md | 2 ++ .../src/opentelemetry/instrumentation/celery/__init__.py | 1 + .../tests/celery/test_celery_functional.py | 6 ++++++ 3 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9120929b..3fd85a7f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `opentelemetry-instrumentation-celery` Record exceptions as events on the span. + ([#1573](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1573)) - Add metric instrumentation for urllib ([#1553](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1553)) - `opentelemetry/sdk/extension/aws` Implement [`aws.ecs.*`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/cloud_provider/aws/ecs.md) and [`aws.logs.*`](https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/cloud_provider/aws/logs/) resource attributes in the `AwsEcsResourceDetector` detector when the ECS Metadata v4 is available diff --git a/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/__init__.py b/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/__init__.py index 6d79f4511..c6a7540cc 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/__init__.py @@ -250,6 +250,7 @@ class CeleryInstrumentor(BaseInstrumentor): if ex is not None: status_kwargs["description"] = str(ex) + span.record_exception(ex) span.set_status(Status(**status_kwargs)) @staticmethod diff --git a/tests/opentelemetry-docker-tests/tests/celery/test_celery_functional.py b/tests/opentelemetry-docker-tests/tests/celery/test_celery_functional.py index 4cdf3718f..1a86154ff 100644 --- a/tests/opentelemetry-docker-tests/tests/celery/test_celery_functional.py +++ b/tests/opentelemetry-docker-tests/tests/celery/test_celery_functional.py @@ -249,6 +249,7 @@ def test_fn_task_delay(celery_app, memory_exporter): run_span.attributes.get("celery.task_name") == "test_celery_functional.fn_task_parameters" ) + assert len(run_span.events) == 0 def test_fn_exception(celery_app, memory_exporter): @@ -275,6 +276,11 @@ def test_fn_exception(celery_app, memory_exporter): == "test_celery_functional.fn_exception" ) assert span.status.status_code == StatusCode.ERROR + assert len(span.events) == 1 + event = span.events[0] + assert event.name == "exception" + assert event.attributes[SpanAttributes.EXCEPTION_TYPE] == "ExceptionInfo" + assert SpanAttributes.EXCEPTION_MESSAGE in event.attributes assert ( span.attributes.get(SpanAttributes.MESSAGING_MESSAGE_ID) == result.task_id