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

> Collect host, container and Kubernetes metrics with the OpenTelemetry Collector — including the exact metric names the Infrastructure pages read, so a page is never empty for a reason you cannot see.

Infrastructure monitoring is the one setup where the pages read **specific metric
names**. An SDK cannot produce them; they come from the OpenTelemetry Collector's
host and container scrapers. If you run the Collector with the right scrapers
enabled, the pages fill in. If a page is empty, it is almost always because the
scraper that produces its metric is not running.

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

## Hosts

The `hostmetrics` receiver scrapes the machine it runs on. Enable these scrapers:

```yaml theme={null}
receivers:
  hostmetrics:
    collection_interval: 30s
    scrapers:
      cpu:
      load:
      memory:
      disk:
      filesystem:

processors:
  resourcedetection:
    detectors: [env, system]
    system:
      hostname_sources: ["os"]

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

service:
  pipelines:
    metrics:
      receivers: [hostmetrics]
      processors: [resourcedetection]
      exporters: [otlphttp]
```

<Warning>
  **`resourcedetection` is not optional here.** The Hosts pages key on the
  `host.name` and `host.id` resource attributes. Without the processor the metrics
  still arrive, but they belong to no host and the inventory stays empty.
</Warning>

### What each panel needs

| Panel        | Metric                                      | Scraper      |
| :----------- | :------------------------------------------ | :----------- |
| CPU          | `system.cpu.utilization`                    | `cpu`        |
| Load average | `system.cpu.load_average.1m`, `.5m`, `.15m` | `load`       |
| Memory       | `system.memory.utilization`                 | `memory`     |
| Disk I/O     | `system.disk.io`                            | `disk`       |
| Filesystem   | `system.filesystem.usage`                   | `filesystem` |

This is a useful debugging table: an empty CPU chart with a populated memory chart
means the `cpu` scraper is off, not that ingest is broken.

## Containers

The `docker_stats` receiver reads the Docker daemon and reports per-container
resource use.

```yaml theme={null}
receivers:
  docker_stats:
    endpoint: unix:///var/run/docker.sock
    collection_interval: 30s
```

The collector needs read access to the Docker socket — mount it, and prefer
read-only.

| Panel            | Metric                                                                       |
| :--------------- | :--------------------------------------------------------------------------- |
| CPU              | `container.cpu.utilization`                                                  |
| Memory used      | `container.memory.usage.total`                                               |
| Memory limit     | `container.memory.usage.limit`                                               |
| Memory %         | `container.memory.percent`                                                   |
| Network in / out | `container.network.io.usage.rx_bytes`, `container.network.io.usage.tx_bytes` |

See [Docker](/send-data/platforms/docker) and
[Docker Compose](/send-data/platforms/docker-compose) for complete deployments.

## Kubernetes

Kubernetes needs two collectors doing different jobs, and running only one is the
most common reason a cluster looks half-monitored:

<Steps>
  <Step title="A DaemonSet — one per node">
    Runs `kubeletstats` for per-pod and per-container resource use, and
    `hostmetrics` for the node itself. This is where the numbers come from.
  </Step>

  <Step title="A Deployment — one per cluster">
    Runs `k8s_cluster` for cluster-level state — node and pod counts, phases,
    conditions — and `k8sattributes` to enrich every record with pod, namespace,
    deployment and node names.
  </Step>
</Steps>

<Note>
  `k8sattributes` is what makes telemetry from a pod filterable by namespace,
  deployment and node — including **logs and traces**, not only metrics. It needs
  RBAC to read pods; the [Kubernetes page](/send-data/platforms/kubernetes) has
  the manifests and the role binding.
</Note>

## Verify

<Steps>
  <Step title="Check the collector is exporting">
    The Collector's own logs report exporter failures plainly. A repeated 401 is a
    key problem; a repeated connection error is an endpoint or egress problem.
  </Step>

  <Step title="Check the host appears">
    Open **Infrastructure → Hosts**. A host appears once metrics carrying its
    `host.name` have been written inside the current time range.
  </Step>

  <Step title="Check a specific panel">
    If the host is listed but one chart is empty, use the tables above to find
    which scraper produces that metric, and confirm it is enabled.
  </Step>
</Steps>

## Cardinality

Host and container metrics are low-cardinality by nature and stay cheap. The way
this setup becomes expensive is attributes added by hand — a per-request id or a
full URL path attached to an infrastructure metric multiplies its series count by
the number of distinct values. Keep resource attributes to things that describe
*where* the metric came from, not *what happened*.

## Infrastructure is account-scoped

Unlike APM, the Infrastructure and Kubernetes pages are not filtered by project.
A host is shared by whatever runs on it, so it belongs to the account rather than
to one project. There is no `projectId` to pass.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Hosts page is empty but metrics are arriving">
    `host.name` is missing from the resource. Add the `resourcedetection`
    processor with the `system` detector, and confirm it is listed in the pipeline
    `processors` — a processor defined but not wired into the pipeline does
    nothing.
  </Accordion>

  <Accordion title="One chart is empty and the rest are fine">
    A scraper is not enabled. Match the empty panel to its metric in the tables
    above, then check the `scrapers:` block.
  </Accordion>

  <Accordion title="Containers show no network figures">
    `container.network.io.usage.rx_bytes` and `tx_bytes` come from the Docker
    daemon. If the collector cannot read the socket, CPU and memory may still work
    through another path while network stays empty — check the socket mount and
    its permissions.
  </Accordion>

  <Accordion title="Kubernetes pods are listed without namespaces or deployments">
    The `k8sattributes` processor is missing, or lacks RBAC to read pods. It
    fails soft: records still arrive, just unenriched.
  </Accordion>
</AccordionGroup>

## Next

<CardGroup cols={2}>
  <Card title="Set up Monitoring" icon="gauge-high" href="/send-data/setup/monitoring">
    Metrics and application traces.
  </Card>

  <Card title="Set up Logs" icon="file-lines" href="/send-data/setup/logs">
    Application and system logs.
  </Card>
</CardGroup>
