diff --git a/src/langtrace_python_sdk/instrumentation/__init__.py b/src/langtrace_python_sdk/instrumentation/__init__.py index bef3fa4f..1966eb68 100644 --- a/src/langtrace_python_sdk/instrumentation/__init__.py +++ b/src/langtrace_python_sdk/instrumentation/__init__.py @@ -1,30 +1,31 @@ from .anthropic import AnthropicInstrumentation +from .autogen import AutogenInstrumentation +from .aws_bedrock import AWSBedrockInstrumentation +from .cerebras import CerebrasInstrumentation from .chroma import ChromaInstrumentation from .cohere import CohereInstrumentation from .crewai import CrewAIInstrumentation +from .crewai_tools import CrewaiToolsInstrumentation +from .dspy import DspyInstrumentation +from .embedchain import EmbedchainInstrumentation +from .gemini import GeminiInstrumentation +from .google_genai import GoogleGenaiInstrumentation from .groq import GroqInstrumentation from .langchain import LangchainInstrumentation from .langchain_community import LangchainCommunityInstrumentation from .langchain_core import LangchainCoreInstrumentation from .langgraph import LanggraphInstrumentation +from .litellm import LiteLLMInstrumentation from .llamaindex import LlamaindexInstrumentation +from .milvus import MilvusInstrumentation +from .mistral import MistralInstrumentation +from .ollama import OllamaInstrumentor from .openai import OpenAIInstrumentation from .pinecone import PineconeInstrumentation +from .pymongo import PyMongoInstrumentation from .qdrant import QdrantInstrumentation -from .weaviate import WeaviateInstrumentation -from .ollama import OllamaInstrumentor -from .dspy import DspyInstrumentation -from .autogen import AutogenInstrumentation from .vertexai import VertexAIInstrumentation -from .gemini import GeminiInstrumentation -from .mistral import MistralInstrumentation -from .aws_bedrock import AWSBedrockInstrumentation -from .embedchain import EmbedchainInstrumentation -from .litellm import LiteLLMInstrumentation -from .pymongo import PyMongoInstrumentation -from .cerebras import CerebrasInstrumentation -from .milvus import MilvusInstrumentation -from .google_genai import GoogleGenaiInstrumentation +from .weaviate import WeaviateInstrumentation __all__ = [ "AnthropicInstrumentation", @@ -54,4 +55,5 @@ "CerebrasInstrumentation", "MilvusInstrumentation", "GoogleGenaiInstrumentation", + "CrewaiToolsInstrumentation", ] diff --git a/src/langtrace_python_sdk/instrumentation/crewai_tools/__init__.py b/src/langtrace_python_sdk/instrumentation/crewai_tools/__init__.py new file mode 100644 index 00000000..e6457033 --- /dev/null +++ b/src/langtrace_python_sdk/instrumentation/crewai_tools/__init__.py @@ -0,0 +1,3 @@ +from .instrumentation import CrewaiToolsInstrumentation + +__all__ = ["CrewaiToolsInstrumentation"] diff --git a/src/langtrace_python_sdk/instrumentation/crewai_tools/instrumentation.py b/src/langtrace_python_sdk/instrumentation/crewai_tools/instrumentation.py new file mode 100644 index 00000000..b0a6d5ec --- /dev/null +++ b/src/langtrace_python_sdk/instrumentation/crewai_tools/instrumentation.py @@ -0,0 +1,49 @@ +""" +Copyright (c) 2025 Scale3 Labs + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from typing import Collection + +from importlib_metadata import version as v +from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.trace import get_tracer +from wrapt import wrap_function_wrapper as _W + +from .patch import patch_run + + +class CrewaiToolsInstrumentation(BaseInstrumentor): + """ + The CrewAIInstrumentation class represents the CrewAI instrumentation""" + + def instrumentation_dependencies(self) -> Collection[str]: + return ["crewai-tools >= 0.32.0"] + + def _instrument(self, **kwargs): + tracer_provider = kwargs.get("tracer_provider") + tracer = get_tracer(__name__, "", tracer_provider) + version = v("crewai-tools") + try: + _W( + "crewai_tools.tools.serper_dev_tool.serper_dev_tool", + "SerperDevTool._run", + patch_run("SerperDevTool._run", version, tracer), + ) + # pylint: disable=broad-except + except Exception: + pass + + def _uninstrument(self, **kwargs): + pass diff --git a/src/langtrace_python_sdk/instrumentation/crewai_tools/patch.py b/src/langtrace_python_sdk/instrumentation/crewai_tools/patch.py new file mode 100644 index 00000000..50c1d14d --- /dev/null +++ b/src/langtrace_python_sdk/instrumentation/crewai_tools/patch.py @@ -0,0 +1,64 @@ +import json + +from importlib_metadata import version as v +from langtrace.trace_attributes import FrameworkSpanAttributes +from opentelemetry import baggage +from opentelemetry.trace import SpanKind, Tracer +from opentelemetry.trace.status import Status, StatusCode + +from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME +from langtrace_python_sdk.constants.instrumentation.common import ( + LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY, SERVICE_PROVIDERS) +from langtrace_python_sdk.utils import set_span_attribute +from langtrace_python_sdk.utils.llm import get_span_name, set_span_attributes +from langtrace_python_sdk.utils.misc import serialize_args, serialize_kwargs + + +def patch_run(operation_name, version, tracer: Tracer): + def traced_method(wrapped, instance, args, kwargs): + service_provider = SERVICE_PROVIDERS["CREWAI"] + extra_attributes = baggage.get_baggage(LANGTRACE_ADDITIONAL_SPAN_ATTRIBUTES_KEY) + span_attributes = { + "langtrace.sdk.name": "langtrace-python-sdk", + "langtrace.service.name": service_provider, + "langtrace.service.type": "framework", + "langtrace.service.version": version, + "langtrace.version": v(LANGTRACE_SDK_NAME), + **(extra_attributes if extra_attributes is not None else {}), + } + + inputs = {} + if len(args) > 0: + inputs["args"] = serialize_args(*args) + if len(kwargs) > 0: + inputs["kwargs"] = serialize_kwargs(**kwargs) + span_attributes["crewai_tools.tools.serper_dev_tool.inputs"] = json.dumps(inputs) + + attributes = FrameworkSpanAttributes(**span_attributes) + + with tracer.start_as_current_span( + get_span_name(operation_name), kind=SpanKind.CLIENT + ) as span: + + try: + set_span_attributes(span, attributes) + result = wrapped(*args, **kwargs) + if result is not None and len(result) > 0: + set_span_attribute( + span, "crewai_tools.tools.serper_dev_tool.outputs", str(result) + ) + if result: + span.set_status(Status(StatusCode.OK)) + return result + + except Exception as err: + # Record the exception in the span + span.record_exception(err) + + # Set the span status to indicate an error + span.set_status(Status(StatusCode.ERROR, str(err))) + + # Reraise the exception to ensure it's not swallowed + raise + + return traced_method diff --git a/src/langtrace_python_sdk/langtrace.py b/src/langtrace_python_sdk/langtrace.py index 8077e605..321faabf 100644 --- a/src/langtrace_python_sdk/langtrace.py +++ b/src/langtrace_python_sdk/langtrace.py @@ -14,74 +14,50 @@ limitations under the License. """ +import logging import os import sys +from typing import Any, Dict, Optional + import sentry_sdk -import logging -from typing import Dict, Optional, Any from colorama import Fore -from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME, SENTRY_DSN from opentelemetry import trace +from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import \ + OTLPSpanExporter as GRPCExporter +from opentelemetry.exporter.otlp.proto.http.trace_exporter import \ + OTLPSpanExporter as HTTPExporter from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor from opentelemetry.sdk.resources import SERVICE_NAME, Resource from opentelemetry.sdk.trace import TracerProvider -from opentelemetry.sdk.trace.export import ( - BatchSpanProcessor, - ConsoleSpanExporter, - SimpleSpanProcessor, -) - -from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( - OTLPSpanExporter as GRPCExporter, -) -from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( - OTLPSpanExporter as HTTPExporter, -) -from langtrace_python_sdk.constants.exporter.langtrace_exporter import ( - LANGTRACE_REMOTE_URL, - LANGTRACE_SESSION_ID_HEADER, -) -from langtrace_python_sdk.instrumentation import ( - AnthropicInstrumentation, - ChromaInstrumentation, - CohereInstrumentation, - CrewAIInstrumentation, - DspyInstrumentation, - EmbedchainInstrumentation, - GeminiInstrumentation, - GroqInstrumentation, - LangchainCommunityInstrumentation, - LangchainCoreInstrumentation, - LangchainInstrumentation, - LanggraphInstrumentation, - LiteLLMInstrumentation, - LlamaindexInstrumentation, - MistralInstrumentation, - AWSBedrockInstrumentation, - OllamaInstrumentor, - OpenAIInstrumentation, - PineconeInstrumentation, - QdrantInstrumentation, - AutogenInstrumentation, - VertexAIInstrumentation, - WeaviateInstrumentation, - PyMongoInstrumentation, - CerebrasInstrumentation, - MilvusInstrumentation, - GoogleGenaiInstrumentation, -) +from opentelemetry.sdk.trace.export import (BatchSpanProcessor, + ConsoleSpanExporter, + SimpleSpanProcessor) from opentelemetry.util.re import parse_env_headers +from sentry_sdk.types import Event, Hint -from langtrace_python_sdk.types import DisableInstrumentations, InstrumentationMethods -from langtrace_python_sdk.utils import ( - check_if_sdk_is_outdated, - get_sdk_version, - is_package_installed, - validate_instrumentations, -) +from langtrace_python_sdk.constants import LANGTRACE_SDK_NAME, SENTRY_DSN +from langtrace_python_sdk.constants.exporter.langtrace_exporter import ( + LANGTRACE_REMOTE_URL, LANGTRACE_SESSION_ID_HEADER) +from langtrace_python_sdk.extensions.langtrace_exporter import \ + LangTraceExporter +from langtrace_python_sdk.instrumentation import ( + AnthropicInstrumentation, AutogenInstrumentation, + AWSBedrockInstrumentation, CerebrasInstrumentation, ChromaInstrumentation, + CohereInstrumentation, CrewAIInstrumentation, CrewaiToolsInstrumentation, + DspyInstrumentation, EmbedchainInstrumentation, GeminiInstrumentation, + GoogleGenaiInstrumentation, GroqInstrumentation, + LangchainCommunityInstrumentation, LangchainCoreInstrumentation, + LangchainInstrumentation, LanggraphInstrumentation, LiteLLMInstrumentation, + LlamaindexInstrumentation, MilvusInstrumentation, MistralInstrumentation, + OllamaInstrumentor, OpenAIInstrumentation, PineconeInstrumentation, + PyMongoInstrumentation, QdrantInstrumentation, VertexAIInstrumentation, + WeaviateInstrumentation) +from langtrace_python_sdk.types import (DisableInstrumentations, + InstrumentationMethods) +from langtrace_python_sdk.utils import (check_if_sdk_is_outdated, + get_sdk_version, is_package_installed, + validate_instrumentations) from langtrace_python_sdk.utils.langtrace_sampler import LangtraceSampler -from langtrace_python_sdk.extensions.langtrace_exporter import LangTraceExporter -from sentry_sdk.types import Event, Hint class LangtraceConfig: @@ -309,6 +285,7 @@ def init( "pymongo": PyMongoInstrumentation(), "cerebras-cloud-sdk": CerebrasInstrumentation(), "pymilvus": MilvusInstrumentation(), + "crewai-tools": CrewaiToolsInstrumentation(), } init_instrumentations(config.disable_instrumentations, all_instrumentations) diff --git a/src/langtrace_python_sdk/version.py b/src/langtrace_python_sdk/version.py index c78f55c4..903a158a 100644 --- a/src/langtrace_python_sdk/version.py +++ b/src/langtrace_python_sdk/version.py @@ -1 +1 @@ -__version__ = "3.3.31" +__version__ = "3.4.0"