Add OpenTelemetry instrumentation for CrewAI#87
Add OpenTelemetry instrumentation for CrewAI#87whoIam0987 wants to merge 5 commits intoalibaba:mainfrom
Conversation
2 change unit test to adapt code.
13a39ef to
aa5f9e1
Compare
|
Thanks for the contribution! Please fix the CI failure. |
There was a problem hiding this comment.
Pull request overview
This pull request adds OpenTelemetry instrumentation for the CrewAI framework, enabling automatic tracing of Crew, Agent, Task, and Tool executions with GenAI semantic conventions.
Changes:
- Implements OpenTelemetry instrumentation wrappers for CrewAI's core components (Crew, Flow, Agent, Task, and Tool)
- Adds utility functions for JSON serialization and message conversion to GenAI format
- Includes comprehensive test suite covering synchronous/streaming LLM calls, tool usage, error scenarios, and agent workflows
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
src/opentelemetry/instrumentation/crewai/__init__.py |
Main instrumentation module with wrapper classes for Crew.kickoff, Flow.kickoff_async, Agent.execute_task, Task.execute_sync, and ToolUsage._use |
src/opentelemetry/instrumentation/crewai/utils.py |
Utility functions for JSON serialization, message conversion, and GenAI hook helpers |
src/opentelemetry/instrumentation/crewai/package.py |
Package metadata defining instrumentation dependencies |
src/opentelemetry/instrumentation/crewai/version.py |
Version information (0.1.0) |
pyproject.toml |
Project configuration with dependencies and build settings |
README.md |
Documentation with installation instructions and usage examples |
test-requirements.txt |
Test dependencies including CrewAI >=0.80.0 and LiteLLM |
tests/*.py |
Comprehensive test suite covering various CrewAI execution scenarios |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "Programming Language :: Python :: 3.8", | ||
| "Programming Language :: Python :: 3.9", |
There was a problem hiding this comment.
Python version classifiers list Python 3.8 and 3.9, but the requires-python field specifies ">=3.10,<4". These are inconsistent. Either update the classifiers to only include 3.10, 3.11, and 3.12, or change the requires-python constraint to match the classifiers.
| "Programming Language :: Python :: 3.8", | |
| "Programming Language :: Python :: 3.9", |
There was a problem hiding this comment.
I have updated the classifiers to only include 3.10, 3.11, and 3.12.
| # "opentelemetry-api ~=1.37", | ||
| # "opentelemetry-instrumentation >=0.58b0, <2", | ||
| # "opentelemetry-semantic-conventions >=0.58b0, <2", |
There was a problem hiding this comment.
These commented-out dependency lines should either be removed or have a comment explaining why they're kept. Leaving commented code in production can cause confusion and maintenance issues.
| # "opentelemetry-api ~=1.37", | |
| # "opentelemetry-instrumentation >=0.58b0, <2", | |
| # "opentelemetry-semantic-conventions >=0.58b0, <2", |
There was a problem hiding this comment.
These commented-out dependency has been removed.
| def __call__(self, wrapped, instance, args, kwargs): | ||
| """Wrap Flow.kickoff_async to create CHAIN span.""" | ||
| inputs = kwargs.get("inputs", {}) | ||
| flow_name = getattr(instance, "name", None) or "flow.kickoff" | ||
|
|
||
| genai_inputs = to_input_message("user", inputs) | ||
|
|
||
| with self._tracer.start_as_current_span( | ||
| name=flow_name, | ||
| kind=SpanKind.INTERNAL, | ||
| attributes={ | ||
| gen_ai_attributes.GEN_AI_OPERATION_NAME: OP_NAME_CREW, | ||
| gen_ai_attributes.GEN_AI_SYSTEM: "crewai", | ||
| }, | ||
| ) as span: | ||
| try: | ||
| result = wrapped(*args, **kwargs) | ||
| genai_outputs = to_output_message("assistant", result) | ||
| self._helper.on_completion(span, genai_inputs, genai_outputs) | ||
| span.set_status(Status(StatusCode.OK)) | ||
| return result | ||
| except Exception as e: | ||
| span.record_exception(e) | ||
| self._helper.on_completion(span, genai_inputs, []) | ||
| raise |
There was a problem hiding this comment.
The _FlowKickoffAsyncWrapper wraps Flow.kickoff_async which appears to be an asynchronous method, but the wrapper's __call__ method is not declared as async. If wrapped(*args, **kwargs) returns a coroutine, this will fail. The wrapper should either be made async with async def __call__ and use await wrapped(*args, **kwargs), or handle the coroutine appropriately if the method is expected to be synchronous.
There was a problem hiding this comment.
The "async def call" and "await wrapped(*args,**kwargs)" has been added.
...suite/loongsuite-instrumentation-crewai/src/opentelemetry/instrumentation/crewai/__init__.py
Show resolved
Hide resolved
...suite/loongsuite-instrumentation-crewai/src/opentelemetry/instrumentation/crewai/__init__.py
Show resolved
Hide resolved
...suite/loongsuite-instrumentation-crewai/src/opentelemetry/instrumentation/crewai/__init__.py
Show resolved
Hide resolved
|
|
||
| [project.optional-dependencies] | ||
| instruments = [ | ||
| "crewai >= 0.1.0", |
There was a problem hiding this comment.
The minimum CrewAI version differs between package.py (>=0.70.0) and pyproject.toml optional dependencies (>=0.1.0). This inconsistency could lead to compatibility issues. The version constraint in package.py should match the one in pyproject.toml optional dependencies, or vice versa. Given that the test-requirements.txt specifies >=0.80.0, consider aligning all version specifications to use a consistent minimum version.
| "crewai >= 0.1.0", | |
| "crewai >= 0.80.0", |
There was a problem hiding this comment.
The pyproject.toml has changed to "crewai >= 0.70.0"
There was a problem hiding this comment.
I didn't see it changed. It is still "crewai >= 0.1.0".
| # Context keys for tracking | ||
| _CREWAI_SPAN_KEY = context_api.create_key("crewai_span") | ||
| _CREWAI_START_TIME_KEY = context_api.create_key("crewai_start_time") | ||
| _CREWAI_LITELLM_RESPONSE_KEY = context_api.create_key( | ||
| "crewai_litellm_response" | ||
| ) | ||
|
|
||
|
|
There was a problem hiding this comment.
These context keys are defined but never used in the codebase. They should either be removed if not needed, or implemented if they were intended to be used for tracking state across the instrumentation.
| # Context keys for tracking | |
| _CREWAI_SPAN_KEY = context_api.create_key("crewai_span") | |
| _CREWAI_START_TIME_KEY = context_api.create_key("crewai_start_time") | |
| _CREWAI_LITELLM_RESPONSE_KEY = context_api.create_key( | |
| "crewai_litellm_response" | |
| ) |
...suite/loongsuite-instrumentation-crewai/src/opentelemetry/instrumentation/crewai/__init__.py
Show resolved
Hide resolved
| def __init__( | ||
| self, completion_hook: CompletionHook, capture_content: bool = True | ||
| ): | ||
| self.completion_hook = completion_hook |
There was a problem hiding this comment.
The completion_hook parameter is stored in the GenAIHookHelper class but is never used. It should either be integrated into the on_completion method to provide extensibility, or removed if it's not needed. If it's intended for future use, add a comment explaining the intended purpose.
There was a problem hiding this comment.
The completion_hook has been removed.
Description
Instrument CrewAI with genai util.
Fixes # (issue)
Type of change
Please delete options that are not relevant.
How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
Does This PR Require a Core Repo Change?
Checklist:
See contributing.md for styleguide, changelog guidelines, and more.