diff --git a/sentry_sdk/integrations/langchain.py b/sentry_sdk/integrations/langchain.py index 431fc46bec..d6e310607b 100644 --- a/sentry_sdk/integrations/langchain.py +++ b/sentry_sdk/integrations/langchain.py @@ -87,12 +87,9 @@ def __init__(self, span): class SentryLangchainCallback(BaseCallbackHandler): # type: ignore[misc] """Base callback handler that can be used to handle callbacks from langchain.""" - span_map = OrderedDict() # type: OrderedDict[UUID, WatchedSpan] - - max_span_map_size = 0 - def __init__(self, max_span_map_size, include_prompts, tiktoken_encoding_name=None): # type: (int, bool, Optional[str]) -> None + self.span_map = OrderedDict() # type: OrderedDict[UUID, WatchedSpan] self.max_span_map_size = max_span_map_size self.include_prompts = include_prompts diff --git a/tests/integrations/langchain/test_langchain.py b/tests/integrations/langchain/test_langchain.py index 3f1b3b1da5..ef43eb0f43 100644 --- a/tests/integrations/langchain/test_langchain.py +++ b/tests/integrations/langchain/test_langchain.py @@ -17,7 +17,10 @@ from langchain_core.outputs import ChatGenerationChunk from sentry_sdk import start_transaction -from sentry_sdk.integrations.langchain import LangchainIntegration +from sentry_sdk.integrations.langchain import ( + LangchainIntegration, + SentryLangchainCallback, +) from langchain.agents import tool, AgentExecutor, create_openai_tools_agent from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder @@ -342,3 +345,22 @@ def test_span_origin(sentry_init, capture_events): assert event["contexts"]["trace"]["origin"] == "manual" for span in event["spans"]: assert span["origin"] == "auto.ai.langchain" + + +def test_span_map_is_instance_variable(): + """Test that each SentryLangchainCallback instance has its own span_map.""" + # Create two separate callback instances + callback1 = SentryLangchainCallback(max_span_map_size=100, include_prompts=True) + callback2 = SentryLangchainCallback(max_span_map_size=100, include_prompts=True) + + # Verify they have different span_map instances + assert ( + callback1.span_map is not callback2.span_map + ), "span_map should be an instance variable, not shared between instances" + + +def test_span_map_not_class_attribute(): + """Test that span_map is not accessible as a class attribute.""" + # This should raise AttributeError if span_map is properly an instance variable + with pytest.raises(AttributeError): + SentryLangchainCallback.span_map