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

# Custom Actions

> Audit any function with the @trail decorator

Use the `@trail` decorator to audit any function in your codebase — not just framework calls.

## Setup

```python theme={null}
from provenlog import trail

@trail(name="process_payment")
def process_payment(amount: float, currency: str):
    # Your code here
    return {"status": "completed", "transaction_id": "txn_123"}
```

When `process_payment` is called, ProvenLog automatically logs:

* `action_type` — always `CUSTOM`
* `action_name` — the `name` you provide (defaults to the function name)
* `action_input` — the function arguments
* `action_output` — the return value (wrapped as `{"return": ...}`)
* `action_status` — `success` or `error` (based on whether the function raises)
* `duration_ms` — how long the function took

## Parameters

```python theme={null}
@trail(
    client=None,                   # ProvenLogClient instance (uses default if omitted)
    name="process_payment",        # Action name (default: function.__name__)
    agent_id=None,                 # Override client's default agent_id
    metadata=None,                 # Extra metadata merged into each event
)
```

## Error handling

If the decorated function raises an exception, ProvenLog logs the event with:

* `action_status` set to `"error"`
* `error_message` set to the exception string

The exception is then re-raised — ProvenLog never swallows errors.

## Async support

The decorator works with both sync and async functions:

```python theme={null}
@trail(name="async_fetch")
async def fetch_data(url: str):
    # async code here
    return {"data": "..."}
```

## Prerequisites

The `@trail` decorator requires a `ProvenLogClient` to be active. When using auto-instrumentation (`plog run` or `import provenlog.auto`), a client is created automatically and registered as the default.

For explicit setup, create a client before calling any decorated functions:

```python theme={null}
from provenlog import ProvenLogClient, trail

client = ProvenLogClient(agent_id="my-agent")

@trail(name="my_action")
def my_action():
    return "done"

my_action()  # Logged via the active client
client.close()
```

You can also pass a client explicitly:

```python theme={null}
@trail(client=my_client, name="my_action")
def my_action():
    return "done"
```
