Before you start, you need two values.
- Your base endpoint — shown on Get Started in the dashboard. These
pages write it as
$OIQ_ENDPOINT. - A license key — created in Settings → License Keys, starting
oiq_. Requires the Admin role. See Create a license key. These pages write it as$OIQ_LICENSE_KEY.
docker-compose.yml and Docker Compose v2 — docker compose version should succeed. Note the space; docker-compose v1 is
end-of-life and its env_file handling differs.
Why a service rather than a sidecar per container
One collector serves the whole stack. Compose puts every service on a shared network with DNS, sohttp://collector:4318 resolves from any container without
publishing a single port to the host.
That matters more than the convenience: your application services never receive
the license key. Only the collector does. When you rotate the key, you change
one service definition instead of auditing every container’s environment.
1. Write the config
Save this next to yourdocker-compose.yml.
config.yaml
2. Add the collector service
docker-compose.yml
The
:? in ${OIQ_ENDPOINT:?…} is doing real work. Without it, an unset
variable becomes an empty string and Compose starts a collector that exports
to nowhere, logging retries you have to go looking for. With it, docker compose up refuses to start and tells you which variable is missing.root_path so the mounted host filesystem is used:
config.yaml
3. Provide the two values
Compose reads a.env file beside docker-compose.yml automatically:
.env
4. Start it
Verify
The collector’s metrics port is not published, so read it from inside the Compose network rather than from your shell:send_failed at zero with sent climbing is a working stack. Then open Logs
in the product, set the range to the last 15 minutes, and search for one of your
service names.
Troubleshooting
'required variable OIQ_ENDPOINT is missing a value'
'required variable OIQ_ENDPOINT is missing a value'
Working as intended — the
:? guard caught an unset variable before starting
a collector that would have exported nowhere.Confirm .env sits beside docker-compose.yml, not beside config.yaml
if those are different directories. Compose looks next to the Compose file,
or wherever --env-file points.Services cannot resolve 'collector'
Services cannot resolve 'collector'
Compose DNS uses the service key, not
container_name. In the file
above the service is collector, so the name is http://collector:4318 even
though the container is called aiaxoniq-collector.Services in different Compose projects are on different networks and cannot
see each other without an explicit shared external network.Application containers start before the collector is ready
Application containers start before the collector is ready
depends_on waits for the container to start, not for it to be listening.
In practice this is harmless: OpenTelemetry SDKs buffer and retry, so early
spans are not lost — they arrive once the collector accepts connections.If early data genuinely matters, add a healthcheck and
depends_on: {collector: {condition: service_healthy}}.The collector starts, then logs 'Exporting failed. Will retry'
The collector starts, then logs 'Exporting failed. Will retry'
Read the
error field on that line — it names the cause exactly.no such host— the endpoint hostname does not resolve. Check$OIQ_ENDPOINTagainst the value on Get Started.connection refused— the host resolves but nothing is listening on that port.401 Unauthorized— the key is missing, malformed or revoked.404— the endpoint already ends in/v1/…. It must be the base URL; the collector appends the signal path itself.
Nothing at all in the logs after 'Everything is ready'
Nothing at all in the logs after 'Everything is ready'
The collector is running and receiving nothing. That is an application-side
problem, not a collector one — your services are not exporting to it.Check that your application’s
OTEL_EXPORTER_OTLP_ENDPOINT points at the
collector’s OTLP port (4318 for HTTP, 4317 for gRPC), not at aiAxonIQ.401 with a key you know is correct
401 with a key you know is correct
Two causes that are not about the key’s value:
- A trailing newline. A key read from a file created by a shell heredoc,
or a Kubernetes Secret made with
--from-file, carries the newline as part of the value. Use--from-literal, orprintfrather thanecho. - A validation outage. If the receiver cannot reach the service that
validates keys it fails closed and returns the same
401. A sudden401across every service at once, with a key you have not changed, is far more likely to be this. Check$OIQ_ENDPOINT/healthfirst.
Config changes appear to do nothing
Config changes appear to do nothing
The collector reads its configuration only at startup. Restart it after any
edit, and confirm the file you edited is the one mounted into the process —
a bind mount pointing at a path that does not exist silently yields the
image’s default config rather than an error.
Next
Instrument your application
Zero-code setup per language.
Kubernetes
When the stack moves to a cluster.
Verify your data
Confirm it landed.