Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions lib/cli/src/crewai_cli/crew_run_tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import time
from typing import Any, ClassVar, cast

from crewai_core.telemetry import Telemetry
from rich.text import Text
from textual import work
from textual.app import App, ComposeResult
Expand Down Expand Up @@ -571,6 +572,7 @@ def __init__(
self._want_deploy: bool = False
self._trace_url: str | None = None
self._consent_screen: TraceConsentScreen | None = None
self._telemetry: Telemetry | None = None

# ── Layout ──────────────────────────────────────────────

Expand Down Expand Up @@ -1042,10 +1044,21 @@ def action_deploy_crew(self) -> None:
self._unsubscribe()
self.exit(self._crew_result)

def _record_tui_button_click(self, button_name: str) -> None:
try:
if self._telemetry is None:
self._telemetry = Telemetry()
self._telemetry.set_tracer()
Comment thread
lorenzejay marked this conversation as resolved.
self._telemetry.feature_usage_span(f"cli_usage:{button_name}")
except Exception: # noqa: S110
pass

def on_button_pressed(self, event: Button.Pressed) -> None:
if event.button.id in ("btn-traces", "btn-traces-done"):
self._record_tui_button_click("view_traces")
self.action_view_traces()
elif event.button.id == "btn-deploy":
self._record_tui_button_click("deploy")
self.action_deploy_crew()

def _scroll_to_result(self) -> None:
Expand Down
33 changes: 33 additions & 0 deletions lib/cli/tests/test_crew_run_tui.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from datetime import datetime
import time
from types import SimpleNamespace
from unittest.mock import Mock

import pytest

Expand Down Expand Up @@ -126,6 +128,37 @@ def login(self) -> None:
assert "Deploy failed with exit code 42" in capsys.readouterr().out


def test_view_traces_button_click_records_telemetry(monkeypatch) -> None:
app = CrewRunApp()
app._status = "completed"
app._trace_url = "https://app.crewai.com/traces/test"
app._telemetry = Mock()
opened_urls: list[str] = []

monkeypatch.setattr("webbrowser.open", lambda url: opened_urls.append(url))

app.on_button_pressed(SimpleNamespace(button=SimpleNamespace(id="btn-traces")))

app._telemetry.feature_usage_span.assert_called_once_with("cli_usage:view_traces")
assert opened_urls == ["https://app.crewai.com/traces/test"]


def test_deploy_button_click_records_telemetry() -> None:
app = CrewRunApp()
app._status = "completed"
app._crew_result = object()
app._telemetry = Mock()
app._unsubscribe = lambda: None # type: ignore[method-assign]
exits: list[object] = []
app.exit = lambda result: exits.append(result) # type: ignore[method-assign]

app.on_button_pressed(SimpleNamespace(button=SimpleNamespace(id="btn-deploy")))

app._telemetry.feature_usage_span.assert_called_once_with("cli_usage:deploy")
assert app._want_deploy is True
assert exits == [app._crew_result]


def test_conversation_turn_done_records_assistant_message() -> None:
class RawResult:
raw = "hello from the flow"
Expand Down
13 changes: 13 additions & 0 deletions lib/crewai-core/src/crewai_core/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,19 @@ def _operation() -> None:

self._safe_telemetry_procedure(_operation)

def feature_usage_span(self, feature: str) -> None:
"""Records that a feature was used. One span = one count."""
from crewai_core.version import get_crewai_version

def _operation() -> None:
Comment thread
joaomdmoura marked this conversation as resolved.
tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Feature Usage")
self._add_attribute(span, "crewai_version", get_crewai_version())
self._add_attribute(span, "feature", feature)
close_span(span)

self._safe_telemetry_procedure(_operation)

def flow_creation_span(self, flow_name: str) -> None:
"""Records the creation of a new flow."""

Expand Down
27 changes: 27 additions & 0 deletions lib/crewai-core/tests/test_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import os
from pathlib import Path
from unittest.mock import Mock

from crewai_core import (
constants,
Expand Down Expand Up @@ -206,3 +207,29 @@ def fail_if_called(provider: object) -> None:

assert called is False
assert telemetry.trace_set is True


def test_core_telemetry_records_feature_usage(
monkeypatch: pytest.MonkeyPatch,
) -> None:
from crewai_core.telemetry import Telemetry

Telemetry._instance = None
monkeypatch.delenv("OTEL_SDK_DISABLED", raising=False)
monkeypatch.delenv("CREWAI_DISABLE_TELEMETRY", raising=False)
monkeypatch.delenv("CREWAI_DISABLE_TRACKING", raising=False)

tracer = Mock()
span = Mock()
tracer.start_span.return_value = span
monkeypatch.setattr(
"crewai_core.telemetry.trace.get_tracer",
lambda _name: tracer,
)

telemetry = Telemetry()
telemetry.feature_usage_span("cli_usage:view_traces")

tracer.start_span.assert_called_once_with("Feature Usage")
span.set_attribute.assert_any_call("feature", "cli_usage:view_traces")
span.end.assert_called_once()
Loading