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

# Set up Logs

> Ship application and system logs over OTLP, get full-text search and pattern clustering, and correlate a log line with the trace it belongs to.

Logs arrive over the same OTLP endpoint as everything else. What separates a
useful log setup from a noisy one is not the transport — it is which fields you
populate on the way in, because those are what search, filtering and trace
correlation are built on.

<Info>
  **Before you start, you need two values.**

  1. **Your base endpoint** — shown on **Get Started** in the dashboard. These
     pages write it as `$OIQ_ENDPOINT`.
  2. **A license key** — created in **Settings → API keys**, starting
     `oiq_`. Requires the Admin role. See
     [Create a license key](/get-started/license-keys). These pages write it as
     `$OIQ_LICENSE_KEY`.

  Export both before running anything below:

  ```bash theme={null}
  export OIQ_ENDPOINT="https://app.aiaxoniq.com/otlp"   # or your own
  export OIQ_LICENSE_KEY="oiq_..."
  ```
</Info>

## The fields that matter

Every log line is stored with these, and each one drives something you can do
with it later:

| Field                               | What it enables                                    | Where it comes from                                   |
| :---------------------------------- | :------------------------------------------------- | :---------------------------------------------------- |
| `body`                              | Full-text search                                   | The log message                                       |
| `service_name`                      | Filtering by service; the link to Services and APM | `service.name` resource attribute                     |
| `severity_text` / `severity_number` | Level filters, error counts                        | The SDK's log level mapping                           |
| `trace_id` / `span_id`              | **Jump from a log line to its trace**              | Automatic when logs are emitted inside an active span |
| `host_name`                         | Filtering by host; the link to Infrastructure      | `host.name` resource attribute                        |
| `service_version`                   | Comparing log volume across releases               | `service.version` resource attribute                  |
| `attributes`                        | Structured filtering on your own fields            | Whatever you attach to the record                     |
| `resource_attributes`               | Environment, region, cluster filtering             | The resource                                          |

<Note>
  **Trace correlation is free, but only if the log is emitted inside the span.**
  `trace_id` and `span_id` are populated by the SDK's log appender from the active
  context. A line written from a background goroutine or a detached worker has no
  active span and lands with empty ids — which is correct, not a bug, but it will
  not link.
</Note>

## Sending logs

<Tabs>
  <Tab title="From the application">
    Use your language's OpenTelemetry log appender so the SDK attaches trace
    context automatically. The endpoint and headers are the same two variables
    used for traces and metrics:

    ```bash theme={null}
    export OTEL_EXPORTER_OTLP_ENDPOINT="$OIQ_ENDPOINT"
    export OTEL_EXPORTER_OTLP_HEADERS="x-license-key=$OIQ_LICENSE_KEY"
    export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
    export OTEL_SERVICE_NAME="checkout-api"
    ```

    <Warning>
      Use OTLP over **HTTP** with an `oiq_` key. The gRPC path expects a signed
      license JWT and will reject a dashboard-issued key with an authentication
      error that looks like a network problem.
    </Warning>
  </Tab>

  <Tab title="From files or stdout">
    Where you cannot change the application, the Collector reads logs from disk or
    from the container runtime and adds the resource attributes:

    ```yaml theme={null}
    receivers:
      filelog:
        include: [/var/log/myapp/*.log]
        operators:
          - type: json_parser
            timestamp:
              parse_from: attributes.ts
              layout: "%Y-%m-%dT%H:%M:%S.%LZ"
            severity:
              parse_from: attributes.level

    processors:
      resource:
        attributes:
          - key: service.name
            value: checkout-api
            action: upsert

    exporters:
      otlphttp:
        endpoint: "$OIQ_ENDPOINT"
        headers:
          x-license-key: "$OIQ_LICENSE_KEY"

    service:
      pipelines:
        logs:
          receivers: [filelog]
          processors: [resource]
          exporters: [otlphttp]
    ```

    Logs collected this way carry no trace context unless the application already
    prints `trace_id` into the line and you map it with an operator.
  </Tab>

  <Tab title="System logs">
    On a Linux host, the `journald` receiver picks up systemd unit logs. The
    [Linux VM page](/send-data/platforms/linux) has the full collector unit,
    including keeping the key out of the config file.
  </Tab>
</Tabs>

## Parse before you send, not after

A log line stored as one opaque string is searchable but not filterable. Parsing
JSON at the Collector — or emitting structured logs from the application — turns
fields into `attributes` you can filter on directly, which is both faster and
cheaper than a full-text scan.

The rule of thumb: anything you will ever want to *filter* by should be an
attribute; anything you will only ever *read* can stay in the body.

## What you get once logs arrive

<CardGroup cols={2}>
  <Card title="Search" icon="magnifying-glass" href="/guides/logs/search">
    Full-text over the body, plus field filters and a query syntax for combining
    them.
  </Card>

  <Card title="Live tail" icon="wave-pulse" href="/guides/logs/live-tail">
    A streaming view of lines as they arrive, filtered the same way.
  </Card>

  <Card title="Patterns" icon="layer-group" href="/guides/logs/patterns">
    Clusters near-identical lines so a million repeats read as one pattern with a
    count.
  </Card>
</CardGroup>

## Retention

Logs are kept for the retention window on your plan — **30 days** unless your plan
says otherwise. Retention is applied on read as well as on storage, so a search
over a wider range than your plan allows returns what is inside the window rather
than erroring.

## Volume control

Logs are usually the highest-volume signal. Two levers, in order of effect:

1. **Do not ship debug level from production.** Filter at the source, where it
   costs nothing.
2. **Drop known-noisy lines at the Collector** with a `filter` processor — health
   check hits, readiness probes, chatty third-party libraries.

Sampling logs is a poor third option: unlike traces, a sampled log set answers
"how many times did this happen" wrongly.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Logs arrive but the Logs page shows no service">
    The resource has no `service.name`. Add it with a `resource` processor in the
    Collector, or set `OTEL_SERVICE_NAME` in the application.
  </Accordion>

  <Accordion title="A log line will not link to its trace">
    Check that `trace_id` is non-empty on the line. If it is empty, the log was
    emitted outside an active span — common in startup code, background jobs and
    exception handlers that run after the span has ended.
  </Accordion>

  <Accordion title="Timestamps are wrong or clustered at ingest time">
    The parser did not find the timestamp field, so the receive time was used
    instead. Check the `timestamp.parse_from` path and the layout string against
    an actual line.
  </Accordion>
</AccordionGroup>

## Next

<CardGroup cols={2}>
  <Card title="Set up Monitoring" icon="gauge-high" href="/send-data/setup/monitoring">
    Metrics and traces, so log lines have traces to link to.
  </Card>

  <Card title="Set up Infrastructure" icon="server" href="/send-data/setup/infrastructure">
    Hosts, containers and Kubernetes.
  </Card>
</CardGroup>
