Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 75 additions & 5 deletions content/Guides/agent-tracing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default handler;`} py={`from agentuity import AgentRequest, AgentResponse
from opentelemetry.trace.status import Status, StatusCode

async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
async with context.tracer.start_as_current_span("process-request") as span:
with context.tracer.start_as_current_span("process-request") as span:
try:
# Add attributes to identify the span
span.set_attribute("userId", "123")
Expand All @@ -83,9 +83,71 @@ async def run(request: AgentRequest, response: AgentResponse, context: AgentCont

### Span Attributes and Events

**Attributes** provide metadata about the span (user IDs, operation types, parameters)
**Attributes** provide metadata about the span (user IDs, operation types, parameters)
**Events** mark specific moments in time with additional context (milestones, state changes)

## Language-Specific Patterns

OpenTelemetry uses different patterns per language, but both achieve the same tracing results.

**JavaScript/TypeScript** uses a callback-based pattern:
```typescript
context.tracer.startActiveSpan('span-name', async (span) => {
// Automatic span lifecycle management through callback scope
const result = await someAsyncWork();
return result;
});
```

**Python** uses a context manager pattern:
```python
with context.tracer.start_as_current_span("span-name") as span:
# Automatic span lifecycle management through with statement
result = await some_async_work()
return result
```

### Working with Async Operations

In Python, **span creation is synchronous, but the work inside can be async**:

- The `with context.tracer.start_as_current_span()` line itself is synchronous
- Inside the `with` block, you can have async operations (`await`)
- The span automatically closes when the `with` block exits
- This is different from `async with` (which would be for async context managers)

Here's how to properly handle async operations within spans:

```python
from agentuity import AgentRequest, AgentResponse, AgentContext
from opentelemetry.trace.status import Status, StatusCode

async def process_user_data(request: AgentRequest, response: AgentResponse, context: AgentContext):
with context.tracer.start_as_current_span("process-user-data") as span:
try:
# Set attributes using semantic conventions
span.set_attribute("enduser.id", "123")
span.set_attribute("operation.type", "data-processing")

# Async operations work perfectly inside the sync span
user_data = await fetch_user_data()
processed_result = await process_data(user_data)

# Add events to mark progress
span.add_event("data-processed", {
"itemCount": len(processed_result),
"processingTimeMs": 150
})

return response.json(processed_result)
except Exception as error:
# Enhanced error handling
span.record_exception(error)
span.set_status(Status(StatusCode.ERROR, str(error)))
context.logger.error(f"Error processing data: {error}")
raise
```

## Advanced Tracing Patterns

### Nested Spans
Expand Down Expand Up @@ -149,13 +211,13 @@ from agentuity import AgentRequest, AgentResponse, AgentContext
from opentelemetry.trace.status import Status, StatusCode

async def run(request: AgentRequest, response: AgentResponse, context: AgentContext):
async with context.tracer.start_as_current_span("agent-request") as parent_span:
with context.tracer.start_as_current_span("agent-request") as parent_span:
try:
parent_span.set_attribute("trigger", request.trigger())
data = await request.data.json()

# Create child span for data processing
async with context.tracer.start_as_current_span("process-data") as child_span:
with context.tracer.start_as_current_span("process-data") as child_span:
try:
child_span.add_event("processing-started", {
"timestamp": time.time()
Expand Down Expand Up @@ -214,6 +276,14 @@ Tracing works seamlessly with other Agentuity features:
- **External integrations**: Monitor API calls and third-party services
- **Streaming responses**: Trace streaming operations and chunks

## Other Considerations

- **Semantic conventions**: Use standardized attribute names like `enduser.id`, `operation.type` for better consistency across your traces
- **Enhanced error handling**: The `Status(StatusCode.ERROR, message)` pattern provides more detailed error information than basic status codes
- **Performance optimization**: Be mindful of span overhead in high-frequency operations. Focus tracing on meaningful operations rather than every small function call

## Viewing Traces

You can view traces in the session timeline visualization:

<ThemeImage baseName="agent-session-detail" alt="Trace Visualization with Span Hierarchy" />
Expand Down
2 changes: 1 addition & 1 deletion content/Introduction/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ my-project/
├── agentuity.yaml # Project configuration
├── .env # Environment variables
├── pyproject.toml # Dependencies and configuration
└── agents/ # Agents directory
└── agentuity_agents/ # Agents directory
└── my-agent/ # Individual agent
└── agent.py # Agent entry point
```
Expand Down
2 changes: 1 addition & 1 deletion content/SDKs/python/api-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1390,7 +1390,7 @@ from agentuity.sdk import AgentContext
from opentelemetry.trace.status import Status, StatusCode

# Create a span
async with context.tracer.start_as_current_span("process-data") as span:
with context.tracer.start_as_current_span("process-data") as span:
try:
# Add attributes to the span
span.set_attribute("userId", "123")
Expand Down