How to Enable Tracing in WayFlow#
Tracing is a crucial aspect of any application, allowing developers to monitor and analyze the behavior of their system. In the context of an agentic framework like WayFlow, tracing allows you to understand the interactions between agents, tools, and other components.
In this guide, you will learn how to:
Create a SpanExporter
Set up tracing in WayFlow
Save your traces in a file
What is Tracing?#
Tracing refers to the process of collecting and analyzing data about the execution of a program or system. This data can include information about function calls, variable assignments, and other events that occur during execution. By analyzing this data, developers can identify performance bottlenecks, debug issues, and optimize their system for better performance.
Why is Tracing Important?#
Tracing is essential for several reasons:
Debugging: Tracing helps developers identify and diagnose issues in their agents. By analyzing the trace data, they can pinpoint the exact location and cause of errors.
Performance Optimization: Tracing provides insights into the performance characteristics of an agent, enabling developers to identify bottlenecks and optimize their architectures for better efficiency.
Monitoring: Tracing allows developers to monitor the behavior of their agents in real-time, enabling them to detect anomalies and respond promptly to issues.
Basic implementation#
To set up tracing in WayFlow, you need to provide an implementation of the SpanProcessor and SpanExporter classes.
A SpanProcessor is a common concept in the observability world. It is a component in the tracing pipeline responsible for receiving and processing spans as they are created and completed by the application. SpanProcessor sit between the tracing backend and the exporter, allowing developers to implement logic such as batching, filtering, modification, or immediate export of Spans. When a Span ends, the SpanProcessor determines what happens to it next, whether it’s sent off immediately, or collected for more efficient periodic export (e.g., doing batching). This flexible mechanism enables customization of trace data handling before it’s ultimately exported to backend observability systems.
A SpanExporter is a component that is responsible for sending finished spans, along with their collected trace data, from the application to an external backend or observability system for storage and analysis. The exporter receives spans from the SpanProcessor and translates them into the appropriate format for the target system, such as LangFuse, LangSmith, or OCI APM. Exporters encapsulate the logic required to connect, serialize, and transmit data, allowing OpenTelemetry to support a wide range of backends through a consistent, pluggable interface. This mechanism enables seamless integration of collected trace data with various monitoring and tracing platforms.
In the following sections you will learn how to implement a combination of SpanProcessor and SpanExporter that can export traces to a file.
SpanProcessor and SpanExporter#
Danger
Several security concerns arise when implementing SpanProcessors and SpanExporters, which include, but they are not limited to, the security of the network used to export traces, and the sensitivity of the information exported. Please refer to our Security Guidelines for more information.
As partially anticipated in the previous section, the most simple implementation of a SpanProcessor
is the one that exports the received Span as-is, without any modification, as soon as the Span is closed.
This implementation is provided by wayflowcore
, and it is called SimpleSpanProcessor.
You will use an instance of this SpanProcessor in this guide.
For what concerns the SpanExporter, you can implement a version of it that just prints the information contained in the Spans to a file at a given path. The implementation can focus on the export method, that opens the file in append mode, and it prints in it the content of the Spans retrieved through the to_tracing_info method.
import pprint
from pathlib import Path
from typing import List, Union
from wayflowcore.tracing.span import Span
from wayflowcore.tracing.spanexporter import SpanExporter
class FileSpanExporter(SpanExporter):
"""SpanExporter that prints spans to a file.
This class can be used for diagnostic purposes.
It prints the exported spans to a file.
"""
def __init__(self, filepath: Union[str, Path]):
if isinstance(filepath, str):
filepath = Path(filepath)
self.filepath: Path = filepath
def export(self, spans: List[Span]) -> None:
with open(self.filepath, "a") as file:
for span in spans:
print(
pprint.pformat(span.to_tracing_info(), width=80, compact=True),
file=file,
)
def force_flush(self, timeout_millis: int = 30000) -> bool:
return True
def startup(self) -> None:
pass
def shutdown(self) -> None:
pass
You can now combine SimpleSpanProcessor with the FileSpanExporter you just implemented to set up the basic components that will let you export traces to the desired file.
from wayflowcore.tracing.spanprocessor import SimpleSpanProcessor
span_processor = SimpleSpanProcessor(
span_exporter=FileSpanExporter(filepath="calculator_agent_traces.txt")
)
Tracking an agent#
Now that you have everything you need to process and export traces, you can work on your agent.
In this example, you are going to build a simple calculator agent with four tools, one for each of the basic operations: addition, subtraction, multiplication, division.
from wayflowcore.agent import Agent
from wayflowcore.models import VllmModel
from wayflowcore.tools import tool
@tool(description_mode="only_docstring")
def multiply(a: float, b: float) -> float:
"""Multiply two numbers"""
return a * b
@tool(description_mode="only_docstring")
def divide(a: float, b: float) -> float:
"""Divide two numbers"""
return a / b
@tool(description_mode="only_docstring")
def sum(a: float, b: float) -> float:
"""Sum two numbers"""
return a + b
@tool(description_mode="only_docstring")
def subtract(a: float, b: float) -> float:
"""Subtract two numbers"""
return a - b
llm = VllmModel(
model_id="LLAMA_MODEL_ID",
host_port="LLAMA_API_URL",
)
agent = Agent(
agent_id="calculator_agent",
name="Calculator agent",
custom_instruction="You are a calculator agent. Please use tools to do math.",
initial_message="Hi! I am a calculator agent. How can I help you?",
llm=llm,
tools=[sum, subtract, multiply, divide],
)
We now run your agent enabling traces, and using the FileSpanExporter
in order to export the traces in a file.
To do that, just wrap the execution loop of our agent in a Trace context manager.
from wayflowcore.tracing.span import ConversationSpan
from wayflowcore.tracing.trace import Trace
conversation = agent.start_conversation()
with Trace(span_processors=[span_processor]):
with ConversationSpan(conversation=conversation) as conversation_span:
conversation.execute()
conversation.append_user_message("Compute 2+3")
status = conversation.execute()
conversation_span.record_end_span_event(execution_status=status)
You can now run our code and inspect the traces saved in your file.
Agent Spec Exporting/Loading#
You can export the agent configuration to its Agent Spec configuration using the AgentSpecExporter
.
from wayflowcore.agentspec import AgentSpecExporter
config = AgentSpecExporter().to_json(agent)
Here is what the Agent Spec representation will look like ↓
Click here to see the assistant configuration.
{
"component_type": "ExtendedAgent",
"id": "calculator_agent",
"name": "Calculator agent",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [],
"outputs": [],
"llm_config": {
"component_type": "VllmConfig",
"id": "2f1ca95b-d333-43a6-9518-a995a87418c1",
"name": "LLAMA_MODEL_ID",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"default_generation_parameters": null,
"url": "LLAMA_API_URL",
"model_id": "LLAMA_MODEL_ID"
},
"system_prompt": "You are a calculator agent. Please use tools to do math.",
"tools": [
{
"component_type": "ServerTool",
"id": "bd8ba23f-162c-4c79-831d-96e03e40d2bd",
"name": "sum",
"description": "Sum two numbers",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"type": "number",
"title": "a"
},
{
"type": "number",
"title": "b"
}
],
"outputs": [
{
"type": "number",
"title": "tool_output"
}
]
},
{
"component_type": "ServerTool",
"id": "9bb68f19-8bd9-4089-8511-92afe680e21d",
"name": "subtract",
"description": "Subtract two numbers",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"type": "number",
"title": "a"
},
{
"type": "number",
"title": "b"
}
],
"outputs": [
{
"type": "number",
"title": "tool_output"
}
]
},
{
"component_type": "ServerTool",
"id": "e7d348eb-ced2-4d75-b80a-90c1b700ce7f",
"name": "multiply",
"description": "Multiply two numbers",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"type": "number",
"title": "a"
},
{
"type": "number",
"title": "b"
}
],
"outputs": [
{
"type": "number",
"title": "tool_output"
}
]
},
{
"component_type": "ServerTool",
"id": "29decfc0-687d-44de-bf96-3e0f8d716e8b",
"name": "divide",
"description": "Divide two numbers",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"type": "number",
"title": "a"
},
{
"type": "number",
"title": "b"
}
],
"outputs": [
{
"type": "number",
"title": "tool_output"
}
]
}
],
"toolboxes": [],
"context_providers": null,
"can_finish_conversation": false,
"max_iterations": 10,
"initial_message": "Hi! I am a calculator agent. How can I help you?",
"caller_input_mode": "always",
"agents": [],
"flows": [],
"agent_template": {
"component_type": "PluginPromptTemplate",
"id": "0d9a17fb-25aa-419a-97e6-f9fec9b327c3",
"name": "",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"messages": [
{
"role": "system",
"contents": [
{
"type": "text",
"content": "{% if custom_instruction %}{{custom_instruction}}{% endif %}"
}
],
"tool_requests": null,
"tool_result": null,
"display_only": false,
"sender": null,
"recipients": [],
"time_created": "2025-09-02T16:00:18.701799+00:00",
"time_updated": "2025-09-02T16:00:18.701801+00:00"
},
{
"role": "user",
"contents": [],
"tool_requests": null,
"tool_result": null,
"display_only": false,
"sender": null,
"recipients": [],
"time_created": "2025-09-02T16:00:18.691523+00:00",
"time_updated": "2025-09-02T16:00:18.691721+00:00"
},
{
"role": "system",
"contents": [
{
"type": "text",
"content": "{% if __PLAN__ %}The current plan you should follow is the following: \n{{__PLAN__}}{% endif %}"
}
],
"tool_requests": null,
"tool_result": null,
"display_only": false,
"sender": null,
"recipients": [],
"time_created": "2025-09-02T16:00:18.701837+00:00",
"time_updated": "2025-09-02T16:00:18.701838+00:00"
}
],
"output_parser": null,
"inputs": [
{
"description": "\"custom_instruction\" input variable for the template",
"type": "string",
"title": "custom_instruction",
"default": ""
},
{
"description": "\"__PLAN__\" input variable for the template",
"type": "string",
"title": "__PLAN__",
"default": ""
},
{
"type": "array",
"items": {},
"title": "__CHAT_HISTORY__"
}
],
"pre_rendering_transforms": null,
"post_rendering_transforms": [
{
"component_type": "PluginRemoveEmptyNonUserMessageTransform",
"id": "6eae1b8c-4319-4bd0-bd49-0828e82d16fd",
"name": "removeemptynonusermessage_messagetransform",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"component_plugin_name": "MessageTransformPlugin",
"component_plugin_version": "25.4.0.dev0"
}
],
"tools": null,
"native_tool_calling": true,
"response_format": null,
"native_structured_generation": true,
"generation_config": null,
"component_plugin_name": "PromptTemplatePlugin",
"component_plugin_version": "25.4.0.dev0"
},
"component_plugin_name": "AgentPlugin",
"component_plugin_version": "25.4.0.dev0",
"agentspec_version": "25.4.1"
}
component_type: ExtendedAgent
id: calculator_agent
name: Calculator agent
description: ''
metadata:
__metadata_info__: {}
inputs: []
outputs: []
llm_config:
component_type: VllmConfig
id: 2f1ca95b-d333-43a6-9518-a995a87418c1
name: LLAMA_MODEL_ID
description: null
metadata:
__metadata_info__: {}
default_generation_parameters: null
url: LLAMA_API_URL
model_id: LLAMA_MODEL_ID
system_prompt: You are a calculator agent. Please use tools to do math.
tools:
- component_type: ServerTool
id: bd8ba23f-162c-4c79-831d-96e03e40d2bd
name: sum
description: Sum two numbers
metadata:
__metadata_info__: {}
inputs:
- type: number
title: a
- type: number
title: b
outputs:
- type: number
title: tool_output
- component_type: ServerTool
id: 9bb68f19-8bd9-4089-8511-92afe680e21d
name: subtract
description: Subtract two numbers
metadata:
__metadata_info__: {}
inputs:
- type: number
title: a
- type: number
title: b
outputs:
- type: number
title: tool_output
- component_type: ServerTool
id: e7d348eb-ced2-4d75-b80a-90c1b700ce7f
name: multiply
description: Multiply two numbers
metadata:
__metadata_info__: {}
inputs:
- type: number
title: a
- type: number
title: b
outputs:
- type: number
title: tool_output
- component_type: ServerTool
id: 29decfc0-687d-44de-bf96-3e0f8d716e8b
name: divide
description: Divide two numbers
metadata:
__metadata_info__: {}
inputs:
- type: number
title: a
- type: number
title: b
outputs:
- type: number
title: tool_output
toolboxes: []
context_providers: null
can_finish_conversation: false
max_iterations: 10
initial_message: Hi! I am a calculator agent. How can I help you?
caller_input_mode: always
agents: []
flows: []
agent_template:
component_type: PluginPromptTemplate
id: 0d9a17fb-25aa-419a-97e6-f9fec9b327c3
name: ''
description: null
metadata:
__metadata_info__: {}
messages:
- role: system
contents:
- type: text
content: '{% if custom_instruction %}{{custom_instruction}}{% endif %}'
tool_requests: null
tool_result: null
display_only: false
sender: null
recipients: []
time_created: '2025-09-02T16:00:18.701799+00:00'
time_updated: '2025-09-02T16:00:18.701801+00:00'
- role: user
contents: []
tool_requests: null
tool_result: null
display_only: false
sender: null
recipients: []
time_created: '2025-09-02T16:00:18.691523+00:00'
time_updated: '2025-09-02T16:00:18.691721+00:00'
- role: system
contents:
- type: text
content: "{% if __PLAN__ %}The current plan you should follow is the following:\
\ \n{{__PLAN__}}{% endif %}"
tool_requests: null
tool_result: null
display_only: false
sender: null
recipients: []
time_created: '2025-09-02T16:00:18.701837+00:00'
time_updated: '2025-09-02T16:00:18.701838+00:00'
output_parser: null
inputs:
- description: '"custom_instruction" input variable for the template'
type: string
title: custom_instruction
default: ''
- description: '"__PLAN__" input variable for the template'
type: string
title: __PLAN__
default: ''
- type: array
items: {}
title: __CHAT_HISTORY__
pre_rendering_transforms: null
post_rendering_transforms:
- component_type: PluginRemoveEmptyNonUserMessageTransform
id: 6eae1b8c-4319-4bd0-bd49-0828e82d16fd
name: removeemptynonusermessage_messagetransform
description: null
metadata:
__metadata_info__: {}
component_plugin_name: MessageTransformPlugin
component_plugin_version: 25.4.0.dev0
tools: null
native_tool_calling: true
response_format: null
native_structured_generation: true
generation_config: null
component_plugin_name: PromptTemplatePlugin
component_plugin_version: 25.4.0.dev0
component_plugin_name: AgentPlugin
component_plugin_version: 25.4.0.dev0
agentspec_version: 25.4.1
You can then load the configuration back to an assistant using the AgentSpecLoader
.
from wayflowcore.agentspec import AgentSpecLoader
tool_registry = {
multiply.name: multiply,
divide.name: divide,
sum.name: sum,
subtract.name: subtract,
}
new_agent = AgentSpecLoader(tool_registry=tool_registry).load_json(config)
Note
This guide uses the following extension/plugin Agent Spec components:
PluginPromptTemplate
PluginRemoveEmptyNonUserMessageTransform
ExtendedAgent
See the list of available Agent Spec extension/plugin components in the API Reference
Using OpenTelemetry SpanProcessors#
OpenTelemetry is an open-source observability framework that provides standardized APIs and libraries to collect, process, and export telemetry data from distributed systems. This standard is agnostic with respect to the domain of application, so it can be easily adopted also for tracing in agentic frameworks.
Tracing in WayFlow is largely inspired by the OpenTelemetry standard, therefore most of the
concepts and APIs overlap.
For this reason, wayflowcore
offers the implementation of two SpanProcessors
that follow
the OpenTelemetry standard:
OtelSimpleSpanProcessor: A span processor that exports spans one by one
OtelBatchSpanProcessor: A span processor that exports spans in batches
These span processors wrap the OpenTelemetry implementation, transform WayFlow spans into OpenTelemetry ones,
and emulate the expected behavior of the processor.
Moreover, they allow using OpenTelemetry compatible SpanExporter
, like, for example,
those offered by the OpenTelemetry Exporters library.
Next steps#
Now that you’ve learned tracing in WayFlow, you might want to apply it in other scenarios:
Full code#
Click on the card at the top of this page to download the full code for this guide or copy the code below.
1# Copyright © 2025 Oracle and/or its affiliates.
2#
3# This software is under the Universal Permissive License
4# %%[markdown]
5# Code Example - How to Enable Tracing
6# ------------------------------------
7
8# How to use:
9# Create a new Python virtual environment and install the latest WayFlow version.
10# ```bash
11# python -m venv venv-wayflowcore
12# source venv-wayflowcore/bin/activate
13# pip install --upgrade pip
14# pip install "wayflowcore==26.1"
15# ```
16
17# You can now run the script
18# 1. As a Python file:
19# ```bash
20# python howto_tracing.py
21# ```
22# 2. As a Notebook (in VSCode):
23# When viewing the file,
24# - press the keys Ctrl + Enter to run the selected cell
25# - or Shift + Enter to run the selected cell and move to the cell below# (UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl) or Apache License
26# 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0), at your option.
27
28import logging
29import warnings
30
31warnings.filterwarnings("ignore")
32logging.basicConfig(level=logging.CRITICAL)
33
34
35# %%[markdown]
36## Span Exporter Setup
37
38# %%
39import pprint
40from pathlib import Path
41from typing import List, Union
42
43from wayflowcore.tracing.span import Span
44from wayflowcore.tracing.spanexporter import SpanExporter
45
46class FileSpanExporter(SpanExporter):
47 """SpanExporter that prints spans to a file.
48
49 This class can be used for diagnostic purposes.
50 It prints the exported spans to a file.
51 """
52
53 def __init__(self, filepath: Union[str, Path]):
54 if isinstance(filepath, str):
55 filepath = Path(filepath)
56 self.filepath: Path = filepath
57
58 def export(self, spans: List[Span]) -> None:
59 with open(self.filepath, "a") as file:
60 for span in spans:
61 print(
62 pprint.pformat(span.to_tracing_info(), width=80, compact=True),
63 file=file,
64 )
65
66 def force_flush(self, timeout_millis: int = 30000) -> bool:
67 return True
68
69 def startup(self) -> None:
70 pass
71
72 def shutdown(self) -> None:
73 pass
74
75# %%[markdown]
76## Build Calculator Agent
77
78# %%
79from wayflowcore.agent import Agent
80from wayflowcore.models import VllmModel
81from wayflowcore.tools import tool
82
83@tool(description_mode="only_docstring")
84def multiply(a: float, b: float) -> float:
85 """Multiply two numbers"""
86 return a * b
87
88
89@tool(description_mode="only_docstring")
90def divide(a: float, b: float) -> float:
91 """Divide two numbers"""
92 return a / b
93
94
95@tool(description_mode="only_docstring")
96def sum(a: float, b: float) -> float:
97 """Sum two numbers"""
98 return a + b
99
100
101@tool(description_mode="only_docstring")
102def subtract(a: float, b: float) -> float:
103 """Subtract two numbers"""
104 return a - b
105
106
107llm = VllmModel(
108 model_id="LLAMA_MODEL_ID",
109 host_port="LLAMA_API_URL",
110)
111
112agent = Agent(
113 agent_id="calculator_agent",
114 name="Calculator agent",
115 custom_instruction="You are a calculator agent. Please use tools to do math.",
116 initial_message="Hi! I am a calculator agent. How can I help you?",
117 llm=llm,
118 tools=[sum, subtract, multiply, divide],
119)
120
121# %%[markdown]
122## Export Config to Agent Spec
123
124# %%
125from wayflowcore.agentspec import AgentSpecExporter
126
127config = AgentSpecExporter().to_json(agent)
128
129# %%[markdown]
130## Load Agent Spec Config
131
132# %%
133from wayflowcore.agentspec import AgentSpecLoader
134
135tool_registry = {
136 multiply.name: multiply,
137 divide.name: divide,
138 sum.name: sum,
139 subtract.name: subtract,
140}
141new_agent = AgentSpecLoader(tool_registry=tool_registry).load_json(config)
142
143# %%[markdown]
144## Tracing Basics
145
146# %%
147from wayflowcore.tracing.spanprocessor import SimpleSpanProcessor
148
149span_processor = SimpleSpanProcessor(
150 span_exporter=FileSpanExporter(filepath="calculator_agent_traces.txt")
151)
152
153# %%[markdown]
154## Agent Execution With Tracing
155
156# %%
157from wayflowcore.tracing.span import ConversationSpan
158from wayflowcore.tracing.trace import Trace
159
160conversation = agent.start_conversation()
161with Trace(span_processors=[span_processor]):
162 with ConversationSpan(conversation=conversation) as conversation_span:
163 conversation.execute()
164 conversation.append_user_message("Compute 2+3")
165 status = conversation.execute()
166 conversation_span.record_end_span_event(execution_status=status)