> ## Documentation Index
> Fetch the complete documentation index at: https://docs.muxx.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Tracing

> Understand and implement tracing with the Muxx Python SDK.

Tracing helps you understand the flow of operations in your LLM application by grouping related calls together.

## Trace Hierarchy

Muxx uses a hierarchical tracing model:

```text theme={null}
Trace: "process-document"
|-- Span: "parse-document"
|-- Span: "extract-entities"
|   |-- Generation: GPT-4o call
|-- Span: "summarize"
|   |-- Generation: GPT-4o call
|-- Span: "format-output"
```

## Creating Traces

### With Decorators

```python theme={null}
from muxx import trace

@trace("my-operation")
def my_function():
    # All LLM calls inside are grouped under this trace
    pass
```

### With Context Manager

```python theme={null}
from muxx import Muxx

muxx = Muxx()

with muxx.trace("my-operation"):
    # All LLM calls inside are grouped under this trace
    pass
```

### Manual Trace Management

```python theme={null}
from muxx import Muxx

muxx = Muxx()

trace = muxx.start_trace("my-operation")
try:
    # Your code here
    pass
finally:
    trace.end()
```

## Creating Spans

Spans represent individual operations within a trace.

### With Decorators

```python theme={null}
from muxx import trace, span

@trace("document-processing")
def process_document(doc: str):

    @span("extraction")
    def extract():
        # LLM call for extraction
        pass

    @span("summarization")
    def summarize(data):
        # LLM call for summarization
        pass

    data = extract()
    return summarize(data)
```

### With Context Manager

```python theme={null}
from muxx import Muxx

muxx = Muxx()

with muxx.trace("document-processing"):
    with muxx.span("extraction"):
        # Extraction logic
        pass

    with muxx.span("summarization"):
        # Summarization logic
        pass
```

## Nested Spans

Spans can be nested to represent sub-operations:

```python theme={null}
from muxx import trace, span

@trace("complex-operation")
def complex_operation():

    @span("step-1")
    def step_one():

        @span("step-1a")
        def sub_step():
            # Nested operation
            pass

        sub_step()

    step_one()
```

## Adding Metadata

### To Traces

```python theme={null}
@trace("user-request", metadata={
    "user_id": "user_123",
    "session_id": "sess_abc",
    "feature": "chat"
})
def handle_request():
    pass
```

### To Spans

```python theme={null}
@span("llm-call", metadata={
    "model": "gpt-4o",
    "purpose": "summarization"
})
def make_llm_call():
    pass
```

## Trace Context

Access the current trace context:

```python theme={null}
from muxx import get_current_trace, get_current_span

@trace("my-trace")
def my_function():
    current_trace = get_current_trace()
    print(f"Trace ID: {current_trace.id}")

    with span("my-span"):
        current_span = get_current_span()
        print(f"Span ID: {current_span.id}")
```

## Async Tracing

Tracing works seamlessly with async code:

```python theme={null}
import asyncio
from muxx import trace, span

@trace("async-operation")
async def async_operation():

    @span("async-step")
    async def async_step():
        await asyncio.sleep(1)

    await async_step()
```

## Best Practices

<AccordionGroup>
  <Accordion title="Name traces by user action">
    Use names like `user-signup`, `document-upload`, `chat-message` rather than technical names.
  </Accordion>

  <Accordion title="Keep spans focused">
    Each span should represent one logical operation. Don't create spans that are too broad or too narrow.
  </Accordion>

  <Accordion title="Add meaningful metadata">
    Include user IDs, feature flags, and other context that helps with debugging and analytics.
  </Accordion>

  <Accordion title="Handle errors properly">
    Traces and spans automatically capture errors, but you can add additional context.
  </Accordion>
</AccordionGroup>
