diff --git a/haystack/tracing/logging_tracer.py b/haystack/tracing/logging_tracer.py index 166c484a9..b9807ecd4 100644 --- a/haystack/tracing/logging_tracer.py +++ b/haystack/tracing/logging_tracer.py @@ -8,6 +8,7 @@ from typing import Any, Dict, Iterator, Optional from haystack import logging from haystack.tracing import Span, Tracer +from haystack.tracing.utils import coerce_tag_value logger = logging.getLogger(__name__) @@ -75,8 +76,9 @@ class LoggingTracer(Tracer): logger.debug("Operation: {operation_name}", operation_name=operation_name) for tag_name, tag_value in tags.items(): color_string = self.tags_color_strings.get(tag_name, "") + coerced_value = coerce_tag_value(tag_value) logger.debug( - color_string + "{tag_name}={tag_value}" + RESET_COLOR, tag_name=tag_name, tag_value=tag_value + color_string + "{tag_name}={tag_value}" + RESET_COLOR, tag_name=tag_name, tag_value=coerced_value ) def current_span(self) -> Optional[Span]: diff --git a/releasenotes/notes/coerce-tag-value-serialization-1192e532889be4a3.yaml b/releasenotes/notes/coerce-tag-value-serialization-1192e532889be4a3.yaml new file mode 100644 index 000000000..c56088168 --- /dev/null +++ b/releasenotes/notes/coerce-tag-value-serialization-1192e532889be4a3.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + use coerce_tag_value in LoggingTracer to serialize tag values diff --git a/test/components/agents/test_agent.py b/test/components/agents/test_agent.py index 7484c1831..abdb62d2e 100644 --- a/test/components/agents/test_agent.py +++ b/test/components/agents/test_agent.py @@ -817,59 +817,18 @@ class TestAgentTracing: expected_tag_values = [ "chat_generator", "MockChatGeneratorWithoutRunAsync", - {"messages": "list", "tools": "list"}, - {}, - {}, - { - "messages": [ChatMessage.from_user(text="What's the weather in Paris?")], - "tools": [ - Tool( - name="weather_tool", - description="Provides weather information for a given location.", - parameters={ - "type": "object", - "properties": {"location": {"type": "string"}}, - "required": ["location"], - }, - function=weather_function, - outputs_to_string=None, - inputs_from_state=None, - outputs_to_state=None, - ) - ], - }, + '{"messages": "list", "tools": "list"}', + "{}", + "{}", + '{"messages": [{"role": "user", "meta": {}, "name": null, "content": [{"text": "What\'s the weather in Paris?"}]}], "tools": [{"type": "haystack.tools.tool.Tool", "data": {"name": "weather_tool", "description": "Provides weather information for a given location.", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}, "function": "test_agent.weather_function", "outputs_to_string": null, "inputs_from_state": null, "outputs_to_state": null}}]}', 1, - {"replies": [ChatMessage.from_assistant(text="Hello")]}, + '{"replies": [{"role": "assistant", "meta": {}, "name": null, "content": [{"text": "Hello"}]}]}', 100, - [ - Tool( - name="weather_tool", - description="Provides weather information for a given location.", - parameters={ - "type": "object", - "properties": {"location": {"type": "string"}}, - "required": ["location"], - }, - function=weather_function, - outputs_to_string=None, - inputs_from_state=None, - outputs_to_state=None, - ) - ], - ["text"], - { - "messages": { - "type": "typing.List[haystack.dataclasses.chat_message.ChatMessage]", - "handler": "haystack.dataclasses.state_utils.merge_lists", - } - }, - {"messages": [ChatMessage.from_user(text="What's the weather in Paris?")], "streaming_callback": None}, - { - "messages": [ - ChatMessage.from_user(text="What's the weather in Paris?"), - ChatMessage.from_assistant(text="Hello"), - ] - }, + '[{"type": "haystack.tools.tool.Tool", "data": {"name": "weather_tool", "description": "Provides weather information for a given location.", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}, "function": "test_agent.weather_function", "outputs_to_string": null, "inputs_from_state": null, "outputs_to_state": null}}]', + '["text"]', + '{"messages": {"type": "typing.List[haystack.dataclasses.chat_message.ChatMessage]", "handler": "haystack.dataclasses.state_utils.merge_lists"}}', + '{"messages": [{"role": "user", "meta": {}, "name": null, "content": [{"text": "What\'s the weather in Paris?"}]}], "streaming_callback": null}', + '{"messages": [{"role": "user", "meta": {}, "name": null, "content": [{"text": "What\'s the weather in Paris?"}]}, {"role": "assistant", "meta": {}, "name": null, "content": [{"text": "Hello"}]}]}', 1, ] for idx, record in enumerate(tags_records): @@ -918,59 +877,18 @@ class TestAgentTracing: expected_tag_values = [ "chat_generator", "MockChatGeneratorWithRunAsync", - {"messages": "list", "tools": "list"}, - {}, - {}, - { - "messages": [ChatMessage.from_user(text="What's the weather in Paris?")], - "tools": [ - Tool( - name="weather_tool", - description="Provides weather information for a given location.", - parameters={ - "type": "object", - "properties": {"location": {"type": "string"}}, - "required": ["location"], - }, - function=weather_function, - outputs_to_string=None, - inputs_from_state=None, - outputs_to_state=None, - ) - ], - }, + '{"messages": "list", "tools": "list"}', + "{}", + "{}", + '{"messages": [{"role": "user", "meta": {}, "name": null, "content": [{"text": "What\'s the weather in Paris?"}]}], "tools": [{"type": "haystack.tools.tool.Tool", "data": {"name": "weather_tool", "description": "Provides weather information for a given location.", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}, "function": "test_agent.weather_function", "outputs_to_string": null, "inputs_from_state": null, "outputs_to_state": null}}]}', 1, - {"replies": [ChatMessage.from_assistant(text="Hello from run_async")]}, + '{"replies": [{"role": "assistant", "meta": {}, "name": null, "content": [{"text": "Hello from run_async"}]}]}', 100, - [ - Tool( - name="weather_tool", - description="Provides weather information for a given location.", - parameters={ - "type": "object", - "properties": {"location": {"type": "string"}}, - "required": ["location"], - }, - function=weather_function, - outputs_to_string=None, - inputs_from_state=None, - outputs_to_state=None, - ) - ], - ["text"], - { - "messages": { - "type": "typing.List[haystack.dataclasses.chat_message.ChatMessage]", - "handler": "haystack.dataclasses.state_utils.merge_lists", - } - }, - {"messages": [ChatMessage.from_user(text="What's the weather in Paris?")], "streaming_callback": None}, - { - "messages": [ - ChatMessage.from_user(text="What's the weather in Paris?"), - ChatMessage.from_assistant(text="Hello from run_async"), - ] - }, + '[{"type": "haystack.tools.tool.Tool", "data": {"name": "weather_tool", "description": "Provides weather information for a given location.", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}, "function": "test_agent.weather_function", "outputs_to_string": null, "inputs_from_state": null, "outputs_to_state": null}}]', + '["text"]', + '{"messages": {"type": "typing.List[haystack.dataclasses.chat_message.ChatMessage]", "handler": "haystack.dataclasses.state_utils.merge_lists"}}', + '{"messages": [{"role": "user", "meta": {}, "name": null, "content": [{"text": "What\'s the weather in Paris?"}]}], "streaming_callback": null}', + '{"messages": [{"role": "user", "meta": {}, "name": null, "content": [{"text": "What\'s the weather in Paris?"}]}, {"role": "assistant", "meta": {}, "name": null, "content": [{"text": "Hello from run_async"}]}]}', 1, ] for idx, record in enumerate(tags_records): diff --git a/test/tracing/test_logging_tracer.py b/test/tracing/test_logging_tracer.py index 0f1daeeba..959c76148 100644 --- a/test/tracing/test_logging_tracer.py +++ b/test/tracing/test_logging_tracer.py @@ -58,13 +58,13 @@ class TestLoggingTracer: span.set_tag("key", {"a": 1, "b": [2, 3, 4]}) assert "Operation: test" in caplog.text - assert "key={'a': 1, 'b': [2, 3, 4]}" in caplog.text + assert 'key={"a": 1, "b": [2, 3, 4]}' in caplog.text assert len(caplog.records) == 2 # structured logging assert caplog.records[0].operation_name == "test" assert caplog.records[1].tag_name == "key" - assert caplog.records[1].tag_value == {"a": 1, "b": [2, 3, 4]} + assert caplog.records[1].tag_value == '{"a": 1, "b": [2, 3, 4]}' def test_apply_color_strings(self, caplog) -> None: tracer = LoggingTracer(tags_color_strings={"key": "color_string"}) @@ -119,12 +119,12 @@ class TestLoggingTracer: input_tag_value = [ record.tag_value for record in tags_records if record.tag_name == "haystack.component.input" ][0] - assert input_tag_value == {"word": "world"} + assert input_tag_value == '{"word": "world"}' output_tag_value = [ record.tag_value for record in tags_records if record.tag_name == "haystack.component.output" ][0] - assert output_tag_value == {"output": "Hello, world!"} + assert output_tag_value == '{"output": "Hello, world!"}' tracing.tracer.is_content_tracing_enabled = False tracing.disable_tracing()