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

# Instrument an agent

> Initialize the Surface Area SDK with one call, then capture spans with the decorator and context-manager APIs.

Instrumenting an agent takes one call to start tracing, plus a decorator or context manager wherever you want a span. Auto-instrumentation of LLM libraries is covered in [Auto-instrumentation](./auto-instrumentation).

## Initialize tracing with one call

Call `tracing.init()` once at startup. It configures an OpenTelemetry tracer provider, connects to Surface Area from your environment, and instruments installed AI libraries.

```python theme={null}
import gatewaysdk.tracing as tracing

tracing.init()
```

`init()` finds your Surface Area project from three environment variables. Set them before the process starts.

| Variable | Purpose |
| - | - |
| `GATEWAY_HOST` | Surface Area server URL, for example `https://withgateway.ai` |
| `GATEWAY_PUBLIC_KEY` | Project public key (`pk-lf-...`) |
| `GATEWAY_SECRET_KEY` | Project secret key (`sk-lf-...`) |
| `GATEWAY_OTLP_ENDPOINT` | Optional override for the OTLP export endpoint |

Copy the host and generate a key pair from your project's **Settings** page.

<img src="https://mintcdn.com/surface-d3d890e1/I9MKHQA4beHtjYQ2/screenshots/settings-api-keys.png?fit=max&auto=format&n=I9MKHQA4beHtjYQ2&q=85&s=8d09ea8539a455188076358038a4ab8a" alt="Project settings and API keys" width="2880" height="1800" data-path="screenshots/settings-api-keys.png" />

*The project Settings page. Copy the Host Name into `GATEWAY_HOST`, and create your `pk-lf-…` / `sk-lf-…` keys under the API keys tab.*

<Info>
  With the three required variables set, the SDK builds the export URL automatically by appending `/api/public/otel/v1/traces` to the host. Override that path only with `GATEWAY_OTLP_ENDPOINT` or the `gateway_endpoint` parameter. See [Export to Surface Area](./export) for details.
</Info>

### Pass credentials directly instead of environment variables

Provide the host and keys as arguments when the environment is not an option. Read them from your own configuration. Never hardcode secrets in source.

```python theme={null}
import os
import gatewaysdk.tracing as tracing

tracing.init(
    service_name="my-agent",
    environment="production",
    version="1.2.3",
    gateway_host=os.environ["GATEWAY_HOST"],
    gateway_public_key=os.environ["GATEWAY_PUBLIC_KEY"],
    gateway_secret_key=os.environ["GATEWAY_SECRET_KEY"],
)
```

### Useful init parameters

`init()` is keyword-only.

| Parameter | Type | Default | Description |
| - | - | - | - |
| `service_name` | `str` | `"gatewaysdk-tracing"` | Service name on the resource attributes |
| `environment` | `str` | `None` | Environment label (`production`, `staging`) for filtering traces |
| `version` | `str` | `None` | Application version or git SHA for tracking regressions |
| `agent` | `str` \| `dict` \| `AgentIdentity` | `None` | The agent this process runs as (stamped on every trace). See [Metadata & identity](./metadata) |
| `instrument_default` | `bool` | `True` | Auto-instrument installed AI libraries |
| `debug` | `bool` \| `str` | `False` | Console logging level: `True`, `"DEBUG"`, `"INFO"`, `"WARNING"`, or `"ERROR"` |

<Info>
  Pass `debug="INFO"` while you set tracing up. It logs the init summary, instrumentor activation, and export success or failure, without the full firehose of `True`.
</Info>

## Flush spans before the process exits

Spans are batched and exported in the background. Call `tracing.shutdown()` before the process exits so pending spans are flushed; otherwise a short-lived script can drop its last traces.

```python theme={null}
import atexit
import gatewaysdk.tracing as tracing

tracing.init()
atexit.register(tracing.shutdown)
```

Call `tracing.flush()` to force export at a checkpoint without ending the session.

```python theme={null}
tracing.flush()
```

## Trace a function with a decorator

Apply `@tracing.trace` to a function to capture its input and output as a span. The span name defaults to the function name.

```python theme={null}
import gatewaysdk.tracing as tracing

tracing.init()

@tracing.trace
def summarize(text: str) -> dict:
    return {"summary": text[:100]}

summarize("a long document...")
```

Pass a custom name, or turn off input or output capture, with keyword arguments.

```python theme={null}
@tracing.trace(name="custom-step", capture_output=False)
def process(data):
    do_work(data)
```

The decorator works on async functions with no change.

```python theme={null}
@tracing.trace
async def fetch_and_answer(query: str) -> str:
    return await answer(query)
```

## Trace a block with a context manager

Use `tracing.trace` as a context manager to start a root span and set input and output explicitly. The block yields the OpenTelemetry span, so you can attach attributes to it.

```python theme={null}
import gatewaysdk.tracing as tracing

tracing.init()

with tracing.trace("answer-question", input=query) as span:
    result = run_agent(query)
    span.set_attribute(tracing.semconv.TRACE_OUTPUT, result)
```

Nest `tracing.span()` calls to record sub-steps as child spans. Each child appears under the active trace in the call tree.

```python theme={null}
with tracing.trace("answer-question", input=query):
    with tracing.span("retrieve", input=query) as s:
        docs = retrieve(query)
        s.set_attribute(tracing.semconv.OBSERVATION_OUTPUT, str(len(docs)))

    with tracing.span("generate"):
        answer = generate(docs)
```

Record a tool or API call with `tracing.tool()`. It marks the span as a client call and adds a `tool.name` attribute.

```python theme={null}
with tracing.tool("search_database", input=query) as s:
    rows = db.execute(query)
    s.set_attribute(tracing.semconv.OBSERVATION_OUTPUT, str(len(rows)))
```

<Info>
  Async code has matching context managers: `tracing.atrace()` for a root span and `tracing.aspan()` for a child span. They behave like their synchronous counterparts.
</Info>

### Errors are recorded automatically

The `trace`, `span`, and `tool` context managers record exceptions for you. If the block raises, the exception is recorded on the span and its status is set to error before the exception propagates.

```python theme={null}
import gatewaysdk.tracing as tracing

with tracing.span("operation"):
    do_work()  # If this raises, the span is marked as an error and the exception is recorded
```

To mark a span as failed without raising, call `set_status` on the yielded span. It is a standard OpenTelemetry `Span`.

```python theme={null}
from opentelemetry.trace import Status, StatusCode
import gatewaysdk.tracing as tracing

with tracing.span("operation") as s:
    result = do_work()
    if not result.success:
        s.set_status(Status(StatusCode.ERROR, f"Operation failed: {result.error}"))
```

## A complete traced agent

<Steps>
  <Step title="Set your Surface Area connection">
    ```bash theme={null}
    export GATEWAY_HOST="https://withgateway.ai"
    export GATEWAY_PUBLIC_KEY="pk-lf-..."
    export GATEWAY_SECRET_KEY="sk-lf-..."
    ```
  </Step>

  <Step title="Write the agent">
    ```python theme={null}
    import atexit
    import gatewaysdk.tracing as tracing

    tracing.init(service_name="faq-bot", environment="production")
    atexit.register(tracing.shutdown)

    @tracing.trace
    def answer(question: str) -> str:
        with tracing.span("lookup", input=question) as s:
            facts = ["the sky is blue"]
            s.set_attribute(tracing.semconv.OBSERVATION_OUTPUT, str(facts))
        return f"Answer to {question!r}: {facts[0]}"

    print(answer("why is the sky blue?"))
    ```
  </Step>

  <Step title="Run it and open the dashboard">
    Run the script, then open your project in Surface Area. The `faq-bot` trace appears with its nested `lookup` span.
  </Step>
</Steps>

## Where to go next

* [Auto-instrumentation](./auto-instrumentation): capture LLM and agent-framework calls with no span code.
* [Metadata & identity](./metadata): attach users, agents, tags, and custom metadata.
* [Sessions & traces](./sessions): group related runs into one session.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.