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

# Logs

> Scope logs by environment or deployment, then filter by request ID for individual predictions.

Baseten assigns a unique request ID to every predict call and returns it in the `X-Baseten-Request-Id` response header, so you can trace a single prediction through your model's logs.

<Note>
  Per-request log filtering requires Truss version 0.15.5 or later. Upgrade with `pip install --upgrade truss`.
</Note>

## Scope by environment or deployment

The Logs tab can show entries from a single deployment or from every deployment in an environment. Use the dropdowns at the top of the tab to switch.

Environment scope aggregates logs across every deployment in that environment, including past deployments still serving traffic during a rollout. Use it to follow a request across deployment boundaries or to watch a promotion in progress.

Deployment scope restricts logs to a single deployment ID. Use it to isolate behavior to one version, such as a development deployment.

The same scope applies to live tail and historical search.

## Events

The **volume chart** at the top of the Logs tab always shows markers for the same [platform events](/observability/metrics#events) as Metrics. There's no toggle to enable. Hover a marker for details.

## Get the request ID

The first step is capturing the request ID from the response. Baseten includes it in every predict response, regardless of whether the call is synchronous, asynchronous, or gRPC. The exact location depends on the protocol you're using:

<Tabs>
  <Tab title="HTTP">
    **To get the request ID from an HTTP call**:

    When you make a predict call, include the `-sD-` flag to print response headers alongside the body:

    ```bash theme={"system"}
    curl -sD- -X POST "https://model-{MODEL_ID}.api.baseten.co/production/predict" \
      -H "Authorization: Bearer $BASETEN_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"prompt": "Hello"}'
    ```

    The request ID appears as a response header:

    ```
    X-Baseten-Request-Id: 31255019cf83c4d0c7492a5006591e1f502a5
    ```
  </Tab>

  <Tab title="gRPC">
    **To get the request ID from a gRPC call**:

    For gRPC calls, the request ID is in the response trailer metadata rather than an HTTP header. Use the `-vv` flag with `grpcurl` to surface it:

    ```bash theme={"system"}
    grpcurl -vv \
      -H "baseten-authorization: Api-Key $BASETEN_API_KEY" \
      -H "baseten-model-id: model-{MODEL_ID}" \
      -d '{"name": "World"}' \
      model-{MODEL_ID}.grpc.api.baseten.co:443 \
      example.Greeter/SayHello
    ```

    Look for `x-baseten-request-id` in the trailer metadata at the end of the response:

    ```
    x-baseten-request-id: 31255019cf83c4d0c7492a5006591e1f502a5
    ```
  </Tab>

  <Tab title="Async">
    **To get the request ID from an async call**:

    Async predict calls return the request ID in two places: the response header and the JSON body, so you can capture it programmatically without parsing headers:

    ```bash theme={"system"}
    curl -sD- -X POST "https://model-{MODEL_ID}.api.baseten.co/production/async_predict" \
      -H "Authorization: Bearer $BASETEN_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"prompt": "Hello"}'
    ```

    ```
    X-Baseten-Request-Id: 31255019cf83c4d0c7492a5006591e1f502a5
    ```

    ```json theme={"system"}
    {"request_id": "31255019cf83c4d0c7492a5006591e1f502a5"}
    ```
  </Tab>
</Tabs>

## Filter logs by request ID

Once you have a request ID, open the model's logs page and enter it in the search filter bar using the `requestId:` prefix:

```
requestId:31255019cf83c4d0c7492a5006591e1f502a5
```

The view narrows to show only log entries from that request. Each log line also displays the request ID alongside the replica ID, so you can confirm you're looking at the right trace even when scrolling through mixed output.

## Logging with request context

For standard Truss models, Baseten automatically attaches the request ID to any log emitted through Python's `logging` module during a predict call. No configuration is required. Use a logger:

```python theme={"system"}
import logging

logger = logging.getLogger(__name__)

class Model:
    def predict(self, request):
        logger.info("Starting prediction")  # request_id is added automatically
        ...
```

## Custom servers

For standard Truss models, Baseten handles request ID logging automatically through the framework's built-in JSON formatter. No configuration is required.

Custom servers don't have this built-in support, so you need to do two things: extract the `x-baseten-request-id` header from incoming requests, and include it as a top-level `request_id` key in your JSON log output. Both steps are covered in the setup guides for [custom HTTP servers](/development/model/custom-server#per-request-logging) and [custom gRPC servers](/development/model/grpc#per-request-logging).

## Download logs

Download a deployment's logs as a file from the **Logs** tab. Baseten runs the export as a background job and saves the file when it's ready, so the download reflects the full time range and filters you selected, not only the lines loaded in the view.

To download logs:

1. Sign in to your workspace at [app.baseten.co](https://app.baseten.co) and choose **Dedicated Inference** in the sidebar, then select your model.
2. Choose the **Logs** tab and set the deployment or environment scope, time range, and any filters (level, request ID, replica, or search).
3. Choose **Download CSV** or **Download JSON**.

The file downloads automatically once it finishes preparing.

A single download covers up to 7 days and 100,000 log lines. If you reach either limit, shorten the time range or add filters and export again.

### Fetch logs from the CLI

To pull logs from a terminal or script, use the Baseten CLI:

```bash theme={"system"}
baseten model deployment logs --model-id <model-id> --deployment-id <deployment-id> --since 1h
```

Scope the window with `--start` and `--end` or `--since`, up to 7 days. Stream live logs with `--tail`, and pass `--output jsonl` for machine-readable output. See the [`baseten model deployment logs`](/reference/cli/baseten/model-deployment#logs) reference for the full set of filters.

## Export logs to an OTLP endpoint

You can stream the same logs that appear in the Baseten dashboard to any backend that accepts [OTLP over HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp), including Honeycomb, Datadog, Grafana Cloud, Sentry, and Sumo Logic. Once configured, every new log line is forwarded to your endpoint in near real time, so you can build dashboards, alerts, and long-term retention on top of your inference traffic without scraping the dashboard.

<Note>
  Log export is rolling out gradually. If the **OTEL connection** card isn't visible in your settings, contact Baseten support to enable it for your organization.
</Note>

### What gets exported

The exporter forwards every log you would see in the Baseten dashboard, which includes:

* **Build logs:** image builds for new deployments.
* **Deploy and promotion logs:** lifecycle events emitted as a deployment activates, scales, or is promoted to an environment.
* **Serving logs:** stdout and stderr from your model replicas, including anything you write through Python's `logging` module.

Each record is sent as an OTLP `LogRecord` with `service.name = "baseten"` and an allowlisted set of attributes:

| Attribute          | Description                                                                                  |
| ------------------ | -------------------------------------------------------------------------------------------- |
| `message`          | The log line.                                                                                |
| `model_id`         | Stable ID of the model the log came from.                                                    |
| `model_version_id` | Deployment (model version) the log came from.                                                |
| `environment`      | Environment name, such as `production` or `staging`, when the deployment is attached to one. |
| `replica`          | Replica ID for serving logs.                                                                 |
| `request_id`       | Per-prediction request ID. Matches the `X-Baseten-Request-Id` header.                        |
| `training_job_id`  | Training job ID for training logs.                                                           |
| `chainlet_id`      | Chainlet ID for [Chains](/development/chain/overview).                                       |
| `exc_info`         | Formatted Python traceback, when the log carries an exception.                               |

Baseten maps the original log level to OTLP `SeverityNumber` and `SeverityText` (`DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL`) and strips internal labels that aren't on the allowlist before export, so your backend only receives the same fields you see in the dashboard.

Exports start from the moment the connection is enabled. Historical logs are not backfilled, and delivery is best-effort: Baseten retries transient failures with exponential backoff, but records can be dropped if your endpoint is unreachable for an extended period.

### Configure a connection

Each Baseten organization can have one OTLP destination at a time. The setting is organization-wide, so every team's logs go to the same endpoint.

To configure a connection:

1. Sign in to your workspace at [app.baseten.co](https://app.baseten.co) and choose **General settings** under **Organization settings** in the sidebar.
2. In the **OTEL connection** card, choose **Add connection**.
3. For **Endpoint URL**, type the full HTTPS URL of your OTLP/HTTP logs receiver, including the path (`/v1/logs` for most receivers). For per-vendor values, see the integration notes below.
4. For **Header name**, type the HTTP header your backend uses to authenticate.
5. For **Header value**, type the credential for that header. Baseten stores the value encrypted and never displays it again.
6. (Optional) Choose **Add header** to send up to three additional headers with every export request.
7. Choose **Save**. New log records start flowing to your endpoint within a few seconds.

To rotate credentials or change destinations, use the edit icon on the saved connection. Removing the connection stops exports immediately.

### Verify the connection

**Test** on a saved connection sends a probe log record and reports whether your endpoint accepted it. It covers endpoints on these domains: `grafana.net`, `datadoghq.com`, `datadoghq.eu`, `newrelic.com`, `honeycomb.io`, `dynatrace.com`, `elastic.co`, `axiom.co`, `coralogix.com`, `logz.io`, `signalfx.com`, `chronosphere.io`, `signoz.cloud`, and `sentry.io`. Endpoints on any other domain receive logs normally, but **Test** returns an error instead of sending a probe.

Once enabled, the **OTEL connection** card reports a health status. The card reports an unhealthy connection when an export failed in the past 30 minutes and no export succeeded in the past 5 minutes. A healthy status does not guarantee successful delivery. A connection with no delivery attempts also appears healthy.

For a check that works with any backend, send a prediction to an active deployment, take the `X-Baseten-Request-Id` value from the response, and search your backend for that ID. Exports cover only new log lines, so a workspace with no active deployments produces none.

### Integration notes

The endpoint and header values below come from each vendor's OTLP/HTTP documentation. Check those docs for the most current values for your account and region.

<Tabs>
  <Tab title="Honeycomb">
    Honeycomb accepts OTLP/HTTP at `https://api.honeycomb.io/v1/logs` (or a region-specific host such as `https://api.eu1.honeycomb.io/v1/logs`). Authenticate with an ingest API key:

    * **Endpoint URL:** `https://api.honeycomb.io/v1/logs`
    * **Header name:** `x-honeycomb-team`
    * **Header value:** Your Honeycomb ingest API key.

    On Honeycomb environments that route by `service.name`, logs land in a dataset named `baseten`. Honeycomb Classic accounts and other dataset-routing setups route differently. See [Honeycomb's OTLP/HTTP reference](https://docs.honeycomb.io/send-data/logs/honeycomb-exporter/) for dataset routing and regional endpoints.
  </Tab>

  <Tab title="Datadog">
    Datadog accepts OTLP/HTTP logs directly on its intake endpoint, so you don't need to run the Datadog Agent or an OpenTelemetry Collector. Authenticate with a Datadog API key:

    * **Endpoint URL:** `https://http-intake.logs.<site>.datadoghq.com/v1/logs`, where `<site>` is your Datadog site (`us1`, `us3`, `us5`, `eu`, `ap1`, and so on).
    * **Header name:** `dd-api-key`
    * **Header value:** An API key from your Datadog **Organization Settings → API Keys** page (at `https://<site>.datadoghq.com/organization-settings/api-keys`).

    See [Datadog's OTLP logs intake docs](https://docs.datadoghq.com/opentelemetry/setup/otlp_ingest/logs/) for the per-site endpoint and request format.
  </Tab>

  <Tab title="Grafana Cloud">
    Grafana Cloud exposes an OTLP gateway per stack. Use the gateway URL and basic auth token from your stack's **OpenTelemetry** connection page:

    * **Endpoint URL:** `https://otlp-gateway-<zone>.grafana.net/otlp/v1/logs`
    * **Header name:** `Authorization`
    * **Header value:** `Basic <base64(instanceID:token)>`

    The exported logs appear in Loki and can be queried alongside the rest of your Grafana Cloud telemetry. See [Grafana Cloud's OTLP setup docs](https://grafana.com/docs/grafana-cloud/send-data/otlp/send-data-otlp/) for the exact gateway URL and token format.
  </Tab>

  <Tab title="Sentry">
    Sentry accepts OTLP/HTTP logs on a per-project ingest endpoint. Authenticate with your project's public key:

    * **Endpoint URL:** `https://o<orgId>.ingest.sentry.io/api/<projectId>/integration/otlp/v1/logs`
    * **Header name:** `x-sentry-auth`
    * **Header value:** `sentry sentry_key=<publicKey>`

    Find the org ID, project ID, and public key in your Sentry project under **Settings → Client Keys (DSN)**. See [Sentry's direct OTLP logs docs](https://docs.sentry.io/concepts/otlp/direct/logs/) for details.
  </Tab>

  <Tab title="Sumo Logic">
    Sumo Logic accepts OTLP/HTTP logs on an OTLP/HTTP source attached to a hosted collector.

    Create an OTLP/HTTP source in Sumo Logic:

    1. Sign in to Sumo Logic at [service.sumologic.com](https://service.sumologic.com) and choose **Data Management** in the sidebar, then choose **Collection**.
    2. Choose **Add Collector**, then choose **Hosted Collector**.
    3. For **Name**, type a name for the collector, then choose **Save**.
    4. Choose **OK** to confirm adding a source to the new collector.
    5. Search for `OTLP` and choose **OTLP/HTTP**.
    6. For **Name**, type a name for the source, then choose **Save**.
    7. In the **HTTP Source Address** dialog, choose **Auth Header**, then copy the **Header** and **URL** values.

    Choose **Show URL** on the source to retrieve the address later.

    Use these values in the Baseten OTEL connection:

    * **Endpoint URL:** The **URL** value copied from Sumo Logic, with `/v1/logs` appended. The final URL contains `v1` twice.
    * **Header name:** `Authorization`.
    * **Header value:** The complete **Header** value copied from Sumo Logic, in the format `x-sumo-token: <token>`.

    A presigned URL also works. Append `/v1/logs` to the presigned URL, then fill the required header fields with `Authorization` and the **Header** value from the **Auth Header** tab. Sumo Logic ignores this header because the URL contains the authentication token.

    For more information, see [Sumo Logic's OTLP/HTTP source documentation](https://www.sumologic.com/help/docs/send-data/hosted-collectors/http-source/otlp/).
  </Tab>
</Tabs>

Other OTLP/HTTP collectors work the same way. If your backend isn't listed, fill in the endpoint URL and the auth header (name and value) it documents for OTLP, and Baseten will start sending logs to it.
