Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a897a95
Update celery instrumentation to follow semantic conventions
Aug 25, 2025
0bb7870
Update changelog
Aug 25, 2025
8dc6ea7
Update celery instrumentation to follow semantic conventions
Aug 27, 2025
90666fc
Update celery instrumention tests to follow semantic conventions
Aug 27, 2025
73d3310
Update celery instrumentation to use latest semantic conventions sche…
Aug 27, 2025
9a33772
Update changelog
Aug 27, 2025
16e04ef
Merge branch 'main' of github.com:open-telemetry/opentelemetry-python…
Sep 1, 2025
2a2750e
Merge branch 'main' into semconv-celery
mriamah Sep 7, 2025
717f584
Merge branch 'main' into semconv-celery
mriamah Sep 9, 2025
1a116f9
Merge branch 'main' into semconv-celery
mriamah Sep 16, 2025
ceba850
Merge branch 'main' into semconv-celery
mriamah Sep 21, 2025
97f7109
Merge branch 'main' into semconv-celery
mriamah Oct 4, 2025
11250a8
Merge branch 'main' into semconv-celery
mriamah Oct 19, 2025
c344be7
Add messaging signal type and mode to instrumentations' semantic conv…
Oct 19, 2025
ce120b8
Update CeleryInstrumentor to use opt-in mode for semantic conventions
Oct 19, 2025
aef2872
Update celery instrumentation utils to use opt-in mode for new semant…
Oct 19, 2025
91ebd51
Add test_task_new_sem_conv for testing when opt-in option is messaging
Oct 19, 2025
a5a51f7
Refactor code
Oct 19, 2025
93499b1
Merge branch 'main' into semconv-celery
mriamah Nov 1, 2025
d7a3444
Add test for when OTEL_SEMCONV_STABILITY_OPT_IN="messaging/dup" to ha…
Nov 1, 2025
17a9f5c
Merge branch 'semconv-celery' of github.com:mriamah/opentelemetry-pyt…
Nov 1, 2025
dd8ebdd
Add back MESSAGING_DESTINATION_KIND use in celery instrumentation for…
Nov 1, 2025
2c93115
Refactor code
Nov 1, 2025
cba8dfa
Add back attribute MESSAGING_DESTINATION_KIND to celery instrumentati…
Nov 1, 2025
da6abc9
Add test for raised exception in celery instrumentation using new sem…
Nov 1, 2025
06dba64
Update changelog
Nov 1, 2025
ec1d951
Merge branch 'main' into semconv-celery
mriamah Nov 7, 2025
d15607d
Merge branch 'main' into semconv-celery
mriamah Nov 8, 2025
8f8642e
Merge branch 'main' into semconv-celery
mriamah Nov 12, 2025
8003429
Merge branch 'main' into semconv-celery
mriamah Nov 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#3610](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3610))
- infra(ci): Fix git pull failures in core contrib test
([#3357](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3357))
- `opentelemetry-instrumentation-celery`: Implement new messaging semantic convention opt-in in celery instrumentation and add corresponding tests ([#3712](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3712))

### Added

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,22 @@ def add(x, y):

from opentelemetry import context as context_api
from opentelemetry import trace
from opentelemetry.instrumentation._semconv import (
_get_schema_url,
_OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType,
_report_new,
_report_old,
_StabilityMode,
)
from opentelemetry.instrumentation.celery import utils
from opentelemetry.instrumentation.celery.package import _instruments
from opentelemetry.instrumentation.celery.version import __version__
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.metrics import get_meter
from opentelemetry.propagate import extract, inject
from opentelemetry.propagators.textmap import Getter
from opentelemetry.semconv._incubating.attributes import messaging_attributes
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.trace.status import Status, StatusCode

Expand Down Expand Up @@ -116,27 +125,32 @@ def keys(self, carrier):
class CeleryInstrumentor(BaseInstrumentor):
metrics = None
task_id_to_start_time = {}
_sem_conv_opt_in_mode = _StabilityMode.DEFAULT

def instrumentation_dependencies(self) -> Collection[str]:
return _instruments

def _instrument(self, **kwargs):
tracer_provider = kwargs.get("tracer_provider")

self._sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.MESSAGING
)

# pylint: disable=attribute-defined-outside-init
self._tracer = trace.get_tracer(
__name__,
__version__,
tracer_provider,
schema_url="https://opentelemetry.io/schemas/1.11.0",
schema_url=_get_schema_url(self._sem_conv_opt_in_mode),
)

meter_provider = kwargs.get("meter_provider")
meter = get_meter(
__name__,
__version__,
meter_provider,
schema_url="https://opentelemetry.io/schemas/1.11.0",
schema_url=_get_schema_url(self._sem_conv_opt_in_mode),
)

self.create_celery_metrics(meter)
Expand Down Expand Up @@ -204,8 +218,12 @@ def _trace_postrun(self, *args, **kwargs):
# request context tags
if span.is_recording():
span.set_attribute(_TASK_TAG_KEY, _TASK_RUN)
utils.set_attributes_from_context(span, kwargs)
utils.set_attributes_from_context(span, task.request)
utils.set_attributes_from_context(
span, kwargs, self._sem_conv_opt_in_mode
)
utils.set_attributes_from_context(
span, task.request, self._sem_conv_opt_in_mode
)
span.set_attribute(_TASK_NAME_KEY, task.name)

activation.__exit__(None, None, None)
Expand Down Expand Up @@ -240,9 +258,18 @@ def _trace_before_publish(self, *args, **kwargs):
# apply some attributes here because most of the data is not available
if span.is_recording():
span.set_attribute(_TASK_TAG_KEY, _TASK_APPLY_ASYNC)
span.set_attribute(SpanAttributes.MESSAGING_MESSAGE_ID, task_id)
if _report_new(self._sem_conv_opt_in_mode):
span.set_attribute(
messaging_attributes.MESSAGING_MESSAGE_ID, task_id
) # Not necessary since it has the same name as the old attribute but just in case it changes in the future
if _report_old(self._sem_conv_opt_in_mode):
span.set_attribute(
SpanAttributes.MESSAGING_MESSAGE_ID, task_id
)
span.set_attribute(_TASK_NAME_KEY, task_name)
utils.set_attributes_from_context(span, kwargs)
utils.set_attributes_from_context(
span, kwargs, self._sem_conv_opt_in_mode
)

activation = trace.use_span(span, end_on_exit=True)
activation.__enter__() # pylint: disable=E1101
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
from celery import registry # pylint: disable=no-name-in-module
from celery.app.task import Task

from opentelemetry.instrumentation._semconv import (
_report_new,
_report_old,
_StabilityMode,
)
from opentelemetry.semconv._incubating.attributes import messaging_attributes
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.trace import Span

Expand Down Expand Up @@ -56,7 +62,11 @@


# pylint:disable=too-many-branches
def set_attributes_from_context(span, context):
def set_attributes_from_context(
span,
context,
sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
):
"""Helper to extract meta values from a Celery Context"""
if not span.is_recording():
return
Expand All @@ -80,7 +90,7 @@ def set_attributes_from_context(span, context):
continue

attribute_name = None

new_attribute_name = None
# Celery 4.0 uses `origin` instead of `hostname`; this change preserves
# the same name for the tag despite Celery version
if key == "origin":
Expand All @@ -91,20 +101,39 @@ def set_attributes_from_context(span, context):
routing_key = value.get("routing_key")

if routing_key is not None:
span.set_attribute(
SpanAttributes.MESSAGING_DESTINATION, routing_key
)
if _report_new(sem_conv_opt_in_mode):
span.set_attribute(
messaging_attributes.MESSAGING_DESTINATION_NAME,
routing_key,
)
if _report_old(sem_conv_opt_in_mode):
span.set_attribute(
SpanAttributes.MESSAGING_DESTINATION, routing_key
)

value = str(value)

elif key == "id":
attribute_name = SpanAttributes.MESSAGING_MESSAGE_ID
if _report_new(sem_conv_opt_in_mode):
new_attribute_name = messaging_attributes.MESSAGING_MESSAGE_ID
if _report_old(sem_conv_opt_in_mode):
attribute_name = SpanAttributes.MESSAGING_MESSAGE_ID

elif key == "correlation_id":
attribute_name = SpanAttributes.MESSAGING_CONVERSATION_ID
if _report_new(sem_conv_opt_in_mode):
new_attribute_name = (
messaging_attributes.MESSAGING_MESSAGE_CONVERSATION_ID
)
if _report_old(sem_conv_opt_in_mode):
attribute_name = SpanAttributes.MESSAGING_CONVERSATION_ID

elif key == "routing_key":
attribute_name = SpanAttributes.MESSAGING_DESTINATION
if _report_new(sem_conv_opt_in_mode):
new_attribute_name = (
messaging_attributes.MESSAGING_DESTINATION_NAME
)
if _report_old(sem_conv_opt_in_mode):
attribute_name = SpanAttributes.MESSAGING_DESTINATION

# according to https://docs.celeryproject.org/en/stable/userguide/routing.html#exchange-types
elif key == "declare":
Expand All @@ -117,11 +146,13 @@ def set_attributes_from_context(span, context):
value = "topic"
break

if attribute_name:
span.set_attribute(attribute_name, value)
if new_attribute_name:
span.set_attribute(new_attribute_name, value)
# set attribute name if not set specially for a key
if attribute_name is None:
attribute_name = f"celery.{key}"

span.set_attribute(attribute_name, value)
if attribute_name is None and new_attribute_name is None:
span.set_attribute(f"celery.{key}", value)


def attach_context(
Expand Down
Loading