fix(core): scope span export to our own tracer provider (#6954)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Check Documentation Broken Links / Check broken links (push) Has been cancelled
Vulnerability Scan / Detect changes (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled

* fix(telemetry): stop exporting third-party spans to the collector

set_tracer() installed CrewAI's TracerProvider as the global one, so every
OTel-instrumented library in the host process - HTTP servers, Redis clients,
ORMs - resolved trace.get_tracer() to our provider and exported to CrewAI's
endpoint. A 20M-row sample of the telemetry table found 18,866 distinct
operation names under our serviceName; CrewAI emits 21.

The same wiring lost data in the other direction: when an application had
already installed its own provider, our spans were created by theirs and went
to their collector, so CrewAI received nothing from instrumented processes.

Spans are now created from the private provider in both packages. Deletes
_attach_common_attributes and its WeakSet/lock, whose multi-provider dedupe
guarded a state that can no longer occur.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH

* fix(telemetry): keep process context on crewai-core spans

Isolating each package to its own TracerProvider removed an accident the CLI
spans depended on: crewai_core.telemetry had no CommonAttributesSpanProcessor,
so its spans only ever carried coding_agent/runtime_context/project_id by
riding the global provider that crewai installed at import.

A differential capture of every span reaching the exporter showed 8 of 54 spans
losing those attributes - Feature Usage (cli_usage:*), Start Deployment,
Template Installed, Create Crew Deployment, Get Crew Logs, Remove Crew,
Deploy Signup Error and Flow Creation.

Moves the marker tables and the detect_* helpers to crewai_core.runtime_env and
the processor plus common_span_attributes() to crewai_core.telemetry, so both
implementations share one source of truth. crewai.telemetry.utils and
crewai.utilities.constants re-export the moved names, so their import paths are
unchanged.

Also fixes a gap that predates the isolation change: a CLI-only process never
imports crewai, so it never reported either attribute. It does now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH

* fix(core): type test helpers and stop tests reaching the collector

mypy runs over lib/crewai-core/tests (the one test tree not excluded), so the
new test file needed full annotations and a narrowed span.attributes.

Also patches SafeOTLPSpanExporter before Telemetry is constructed and shuts the
provider down afterwards: __init__ wires a BatchSpanProcessor around the real
OTLP exporter, so each test was attempting a live export and leaving its batch
worker thread running.

Corrects the marker-precedence docstring, which named Cursor third when the
table checks it last so that assistants running inside its terminal are not
masked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH

* style(core): use one import form per module in telemetry tests

Both test modules imported their telemetry module twice - once aliased for the
monkeypatch target and once via from-import for the names. Dropping the alias
in favour of monkeypatch's dotted-string target leaves a single import form and
removes the need to qualify every reference.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH

* docs(core): drop comments that restate the code

The TRACER_NAME constants were annotated with what their name and
set_tracer()'s docstring already say, and the test fixtures narrated
provider.shutdown() and the exporter patch at more length than either needed.

Keeps the ones carrying something the code cannot: the resource-attribute
ingestion quirk, why the marker tables moved packages, and the two ordering
traps the fixtures exist to avoid.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASfWmW3RGy4qAQm6s8U9jH

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
João Moura
2026-08-10 21:16:27 -03:00
committed by GitHub
parent 17f107c197
commit 094b94e8d0
17 changed files with 970 additions and 583 deletions

View File

@@ -34,6 +34,20 @@ os.environ['CREWAI_DISABLE_TELEMETRY'] = 'true'
os.environ['OTEL_SDK_DISABLED'] = 'true'
```
### العزل عن إعداد OpenTelemetry الخاص بك
يعمل القياس عن بُعد الخاص بـ CrewAI على `TracerProvider` خاص به ولا يسجل نفسه
أبدًا كمزوّد عام. هذا يفصل الاتجاهين:
- لا تُرسَل أبدًا إلى CrewAI الامتدادات (spans) الصادرة عن المكتبات الأخرى
المزوّدة بأدوات القياس في عمليتك — أطر الويب، وعملاء قواعد البيانات،
وعملاء HTTP.
- لا تُرسَل امتدادات القياس عن بُعد الخاصة بـ CrewAI إلى نظام المراقبة لديك، لذا
لن تظهر في Langfuse أو Braintrust أو Phoenix أو أي مُجمِّع آخر تقوم بإعداده.
لا تتأثر تكاملات المراقبة: فهي تقيس CrewAI عبر مزوّد التتبع الخاص بها، وهو
مستقل عن المزوّد الموصوف هنا.
### شرح البيانات:
| افتراضي | البيانات | السبب والتفاصيل |
|:----------|:------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------|

View File

@@ -34,6 +34,20 @@ os.environ['CREWAI_DISABLE_TELEMETRY'] = 'true'
os.environ['OTEL_SDK_DISABLED'] = 'true'
```
### Isolation from your own OpenTelemetry setup
CrewAI's telemetry runs on its own private `TracerProvider` and never registers
itself as the global one. This keeps the two directions separate:
- Spans from other instrumented libraries in your process — web frameworks,
database clients, HTTP clients — are never sent to CrewAI.
- CrewAI's telemetry spans are never sent to your observability backend, so they
will not appear in Langfuse, Braintrust, Phoenix, or any other collector you
configure.
Observability integrations are unaffected: they instrument CrewAI through their
own tracer provider, which is independent of the one described here.
### Data Explanation:
| Defaulted | Data | Reason and Specifics |
|:----------|:------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------|

View File

@@ -33,6 +33,19 @@ os.environ['CREWAI_DISABLE_TELEMETRY'] = 'true'
os.environ['OTEL_SDK_DISABLED'] = 'true'
```
### 사용자 OpenTelemetry 설정과의 격리
CrewAI의 telemetry는 자체 전용 `TracerProvider`에서 실행되며 자신을 전역
provider로 등록하지 않습니다. 이를 통해 양방향이 분리됩니다:
- 프로세스 내 다른 계측된 라이브러리(웹 프레임워크, 데이터베이스 클라이언트,
HTTP 클라이언트)의 span은 CrewAI로 전송되지 않습니다.
- CrewAI의 telemetry span은 사용자의 관측 가능성 백엔드로 전송되지 않으므로
Langfuse, Braintrust, Phoenix 또는 구성한 다른 수집기에 나타나지 않습니다.
관측 가능성 통합은 영향을 받지 않습니다: 해당 통합은 여기서 설명한 provider와
독립적인 자체 tracer provider를 통해 CrewAI를 계측합니다.
### 데이터 설명:
| 기본값 | 데이터 | 사유 및 세부 사항 |
|:--------|:-------------------------------------------|:----------------------------------------------------------------------------------------------------------------------|

View File

@@ -34,6 +34,20 @@ os.environ['CREWAI_DISABLE_TELEMETRY'] = 'true'
os.environ['OTEL_SDK_DISABLED'] = 'true'
```
### Isolamento da sua própria configuração do OpenTelemetry
A telemetria do CrewAI roda em seu próprio `TracerProvider` privado e nunca se
registra como o provider global. Isso mantém as duas direções separadas:
- Spans de outras bibliotecas instrumentadas no seu processo — frameworks web,
clientes de banco de dados, clientes HTTP — nunca são enviados ao CrewAI.
- Os spans de telemetria do CrewAI nunca são enviados ao seu backend de
observabilidade, portanto não aparecerão no Langfuse, Braintrust, Phoenix ou
em qualquer outro coletor que você configurar.
As integrações de observabilidade não são afetadas: elas instrumentam o CrewAI
por meio do próprio tracer provider, que é independente do descrito aqui.
### Explicação dos Dados:
| Padrão | Dados | Razão e Especificidades |
|--------|--------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|