File size: 4,657 Bytes
94ea28c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import json
import os
import platform
import socket

import pkg_resources
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.trace import Status, StatusCode


class Telemetry:
    """A class to handle anonymous telemetry for the crewai package.

    The data being collected is for development purpose, all data is anonymous.

    There is NO data being collected on the prompts, tasks descriptions
    agents backstories or goals nor responses or any data that is being
    processed by the agents, nor any secrets and env vars.

    Data collected includes:
    - Version of crewAI
    - Version of Python
    - General OS (e.g. number of CPUs, macOS/Windows/Linux)
    - Number of agents and tasks in a crew
    - Crew Process being used
    - If Agents are using memory or allowing delegation
    - If Tasks are being executed in parallel or sequentially
    - Language model being used
    - Roles of agents in a crew
    - Tools names available
    """

    def __init__(self):
        telemetry_endpoint = "http://telemetry.crewai.com:4318"
        self.resource = Resource(attributes={SERVICE_NAME: "crewAI-telemetry"})
        provider = TracerProvider(resource=self.resource)
        processor = BatchSpanProcessor(
            OTLPSpanExporter(endpoint=f"{telemetry_endpoint}/v1/traces")
        )
        provider.add_span_processor(processor)
        trace.set_tracer_provider(provider)

    def crew_creation(self, crew):
        """Records the creation of a crew."""
        try:
            tracer = trace.get_tracer("crewai.telemetry")
            span = tracer.start_span("Crew Created")
            self.add_attribute(
                span, "crewai_version", pkg_resources.get_distribution("crewai").version
            )
            self.add_attribute(span, "python_version", platform.python_version())
            self.add_attribute(span, "hostname", socket.gethostname())
            self.add_attribute(span, "crewid", str(crew.id))
            self.add_attribute(span, "crew_process", crew.process)
            self.add_attribute(span, "crew_language", crew.language)
            self.add_attribute(span, "crew_number_of_tasks", len(crew.tasks))
            self.add_attribute(span, "crew_number_of_agents", len(crew.agents))
            self.add_attribute(
                span,
                "crew_agents",
                json.dumps(
                    [
                        {
                            "id": str(agent.id),
                            "role": agent.role,
                            "memory_enabled?": agent.memory,
                            "llm": json.dumps(self._safe_llm_attributes(agent.llm)),
                            "delegation_enabled?": agent.allow_delegation,
                            "tools_names": [tool.name for tool in agent.tools],
                        }
                        for agent in crew.agents
                    ]
                ),
            )
            self.add_attribute(
                span,
                "crew_tasks",
                json.dumps(
                    [
                        {
                            "id": str(task.id),
                            "async_execution?": task.async_execution,
                            "tools_names": [tool.name for tool in task.tools],
                        }
                        for task in crew.tasks
                    ]
                ),
            )
            self.add_attribute(span, "platform", platform.platform())
            self.add_attribute(span, "platform_release", platform.release())
            self.add_attribute(span, "platform_system", platform.system())
            self.add_attribute(span, "platform_version", platform.version())
            self.add_attribute(span, "cpus", os.cpu_count())
            span.set_status(Status(StatusCode.OK))
            span.end()
        except Exception:
            pass

    def add_attribute(self, span, key, value):
        """Add an attribute to a span."""
        try:
            return span.set_attribute(key, value)
        except Exception:
            pass

    def _safe_llm_attributes(self, llm):
        attributes = ["name", "model_name", "base_url", "model", "top_k", "temperature"]
        safe_attributes = {k: v for k, v in vars(llm).items() if k in attributes}
        safe_attributes["class"] = llm.__class__.__name__
        return safe_attributes