> ## 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 Monitoring

> Get metrics and application traces flowing, so the Services, APM and Metrics pages have something to show. Covers OpenTelemetry SDKs, the Collector, and Prometheus remote-write.

Monitoring is two signals that arrive separately and are read together: **metrics**
answer *how much, how often, how slow* over long windows, and **traces** answer
*where did this one request spend its time*. You can send either on its own —
neither blocks the other — but the Services and APM pages are built assuming both.

<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>

## What each page needs

| Page                                        | Needs                                               | Arrives from                               |
| :------------------------------------------ | :-------------------------------------------------- | :----------------------------------------- |
| **Metrics**                                 | Any metric                                          | SDK, Collector, or Prometheus remote-write |
| **Services**                                | Traces with a `service.name`                        | SDK or Collector                           |
| **APM** — endpoints, latency, errors, Apdex | Traces with HTTP semantic attributes                | SDK or Collector                           |
| **Service map**                             | Traces with parent/child span links across services | SDK or Collector                           |
| **Deployments, Versions**                   | `service.version` on the resource                   | SDK or Collector                           |

A page with no data is not an error state — it is a page whose signal has not
arrived. If Services is empty, no traces carrying `service.name` have been
received inside the current time range.

## Traces

<Steps>
  <Step title="Point the SDK at your endpoint">
    Every OpenTelemetry SDK reads the same two variables. Set them wherever your
    process gets its environment — the container spec, the systemd unit, the
    platform's config UI.

    ```bash theme={null}
    export OTEL_EXPORTER_OTLP_ENDPOINT="$OIQ_ENDPOINT"
    export OTEL_EXPORTER_OTLP_HEADERS="x-license-key=$OIQ_LICENSE_KEY"
    export OTEL_SERVICE_NAME="checkout-api"
    export OTEL_RESOURCE_ATTRIBUTES="service.version=1.4.2,deployment.environment=production"
    ```

    <Warning>
      **Use OTLP over HTTP, not gRPC, when you authenticate with an `oiq_` key.**
      The two transports are validated differently: the gRPC path on port `4317`
      expects a signed license JWT, while the HTTP path accepts the dashboard-issued
      `oiq_<hex>` keys. Pointing a gRPC exporter at an `oiq_` key produces
      authentication failures that read like a networking problem. Set
      `OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf` if your SDK defaults to gRPC.
    </Warning>
  </Step>

  <Step title="Instrument the application">
    Auto-instrumentation covers the common frameworks without code changes — see
    [Zero-code instrumentation](/send-data/otel/zero-code). For anything it does
    not reach, [manual instrumentation](/send-data/otel/manual-instrumentation)
    adds spans by hand.
  </Step>

  <Step title="Confirm the spans landed">
    Open **APM → Services**. A service appears the first time a span carrying its
    `service.name` is written, and stays listed while data remains inside
    retention. If it is missing, see
    [Verify your data](/get-started/verify-data).
  </Step>
</Steps>

### Set `service.version` from the start

`service.version` is what turns the **Versions** and **Deployments** pages from
empty into useful, and it is far easier to set now than to backfill later — spans
already written keep whatever they were written with. Use whatever your build
already knows: a git SHA, a semver tag, an image digest.

## Metrics

Two sources, both supported, and they can run side by side.

<Tabs>
  <Tab title="OpenTelemetry">
    Metrics travel over the same endpoint and headers as traces. If you set the
    variables above, an SDK or Collector exporting metrics needs nothing further.

    OpenTelemetry metric names arrive dotted — `http.server.request.duration`.
  </Tab>

  <Tab title="Prometheus remote-write">
    If you already run Prometheus, keep it. Add a `remote_write` block and your
    existing scrape targets flow through unchanged:

    ```yaml theme={null}
    remote_write:
      - url: "$OIQ_ENDPOINT/api/v1/prom/write"
        headers:
          x-license-key: "$OIQ_LICENSE_KEY"
    ```

    Prometheus metric names arrive underscored — `http_requests_total`. Both
    shapes are listed in the metric catalogue and both chart the same way.

    See [Prometheus remote-write](/send-data/prometheus) for relabelling and
    filtering before send.
  </Tab>
</Tabs>

<Note>
  **Remote-write can be refused by plan.** If your plan does not include metrics,
  the receiver rejects the write rather than accepting and discarding it. The
  rejection is visible in your Prometheus logs as a non-2xx from the remote-write
  URL.
</Note>

## Projects and APM

APM is the one product where **projects** narrow what you see. A project maps to a
set of services, and the APM pages filter to that set.

* Pass `projectId` to look at one project
* Pass `scope=account` to read across the whole account
* Sending neither is refused, deliberately — a request that states no scope is a
  bug in the caller, and answering account-wide data under one project's heading
  is the failure that refusal prevents

Other products — Logs, Infrastructure, Kubernetes, Metrics — are account-scoped
and do not take `projectId`.

## Cost control before you scale up

Traces are the expensive signal. Decide sampling before you roll instrumentation
out widely, not after the first bill:

* **Head sampling** in the SDK drops spans at the source and costs nothing to run
* **Tail sampling** in the Collector keeps every error and slow trace while
  dropping the uninteresting majority — more useful, more moving parts

[Sampling](/send-data/otel/sampling) covers both.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Services page is empty but the app is running">
    The spans are not arriving, or they carry no `service.name`. Check the SDK's
    own diagnostic log for exporter errors, then confirm the endpoint and key with
    [Verify your data](/get-started/verify-data).
  </Accordion>

  <Accordion title="401 or 403 from the exporter">
    Nearly always one of three things: an `oiq_` key sent over gRPC instead of
    HTTP, the header spelled something other than `x-license-key`, or a key that
    was revoked. Header names in gRPC metadata must be lower-case.
  </Accordion>

  <Accordion title="Metrics arrive but charts look coarse over long ranges">
    Expected. A wide time range is answered from pre-aggregated rollups rather
    than raw samples, so resolution drops as the window grows. See
    [Exploring metrics](/guides/metrics/overview).
  </Accordion>
</AccordionGroup>

## Next

<CardGroup cols={2}>
  <Card title="Set up Logs" icon="file-lines" href="/send-data/setup/logs">
    Correlate logs with the traces you just enabled.
  </Card>

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