Skip to content

Send data with OpenTelemetry

Fixter ingests telemetry over standard OpenTelemetry (OTLP/HTTP). If your services already emit OpenTelemetry, through the Collector, an SDK, or an auto-instrumentation agent, connecting them to Fixter is three steps and no code changes. (Just getting started? Onboarding is the guided path; this page is the depth behind its manual tier.) On Claude Code you do not wire any of this by hand: the plugin provisions the key and configures export for you.

  1. Open Settings > API keys in the Fixter app.
  2. Click Create key and give it a label you’ll recognize later, like production-collector.
  3. Copy the key immediately. For security it is shown only this once; if you lose it, revoke it and create a new one.

Keys look like fixter_sk_.... Store it wherever your infrastructure keeps secrets, and export it in the shell you’ll use below:

export FIXTER_API_KEY="fixter_sk_..."

No workspace yet? Email info@fixter.dev and one of our founders will set you up.

Step 2: Point your OpenTelemetry setup at Fixter

Section titled “Step 2: Point your OpenTelemetry setup at Fixter”

Pick the path that matches your setup:

  • On Kubernetes: run the Fixter collector (Path A).
  • You already run an OpenTelemetry Collector: add a Fixter exporter to it (Path B).
  • Anything else (a plain process, a VM, Docker): export straight from your application (Path C).

Path A: run the Fixter collector (Kubernetes)

Section titled “Path A: run the Fixter collector (Kubernetes)”

The Fixter collector is a standard OpenTelemetry Collector that Fixter pre-configures and publishes, so there is no proprietary agent involved. On Kubernetes it is the recommended path, installed as a Helm chart.

Create the fixter namespace and, inside it, a Secret named fixter-credentials holding the key from Step 1. Then install the chart pointing at that Secret:

helm install fixter-collector \
oci://ghcr.io/fixter-dev/charts/fixter-collector \
--namespace fixter \
--set fixter.existingSecret=fixter-credentials \
--set fixter.clusterName=<your-cluster>

Pass the key by Secret reference, never --set fixter.apiKey=..., which would leave it in your shell history and the pod’s process list.

Installed on its own, the chart brings pod logs and host and cluster metrics into Fixter with no application changes at all. It parses JSON pod logs for severity and trace correlation, and auto-routes common database logs (Postgres, MySQL, Kafka and others). To add each app’s own traces and logs on top, point its workload at the collector’s in-cluster Service instead of at ingest.fixter.dev:

OTEL_EXPORTER_OTLP_ENDPOINT=http://fixter-collector-agent.fixter.svc.cluster.local:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_SERVICE_NAME=checkout-service

The Claude Code plugin installs and configures this chart for you, including the Secret and the case where a GitOps or Terraform system already manages your Helm releases.

Path B: add Fixter to a Collector you already run

Section titled “Path B: add Fixter to a Collector you already run”

If you already run an OpenTelemetry Collector, one exporter block sends its telemetry to Fixter as well, covering every service that exports to it whatever the language. Add the exporter to your Collector’s configuration file (the YAML you start it with via --config; on package installs typically /etc/otelcol/config.yaml) and reference it from each pipeline:

# otel-collector-config.yaml
exporters:
otlphttp/fixter:
endpoint: https://ingest.fixter.dev
headers:
Authorization: "Bearer ${env:FIXTER_API_KEY}"
compression: gzip
service:
pipelines:
logs:
exporters: [otlphttp/fixter] # append to your existing exporters list
traces:
exporters: [otlphttp/fixter]
metrics:
exporters: [otlphttp/fixter]

Then restart the Collector (for example systemctl restart otelcol, or redeploy the container) with FIXTER_API_KEY present in its environment.

Path C: export straight from your application

Section titled “Path C: export straight from your application”

No Collector needed: every OpenTelemetry SDK and auto-instrumentation agent can send directly to Fixter. The universal contract is four environment variables, the same in every language:

OTEL_SERVICE_NAME=checkout-service # how Fixter names your service
OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.fixter.dev
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf # Fixter speaks OTLP over HTTP, not gRPC
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer $FIXTER_API_KEY"

Set those wherever your process gets its environment, add your language’s OpenTelemetry instrumentation, and you’re exporting. Concrete recipes:

Logs are configured separately from traces, and how much is automatic depends on your stack. Instrumentation gives you traces and metrics; logs need a bridge from your logging library, and it is not free everywhere. The Java agent auto-bridges logback and log4j2, so logs come with no extra work. Node exports logs only for Winston, Pino, or Bunyan (plain console sends none). Python needs opentelemetry-instrumentation-logging to bridge stdlib logging. Go, PHP, and Ruby have no stable log bridge yet and ship logs as JSON through a collector instead. Each tab below notes what its stack needs; do not assume logs arrive just because traces do.

# install the auto-instrumentation bundle
npm install @opentelemetry/auto-instrumentations-node

How you load it depends on whether your app is CommonJS or ES modules, and getting it wrong fails silently. With the CommonJS loader on an ESM app, traces still appear (CommonJS deps pulled in through interop are patched) while ESM-loaded libraries like pino are not, so no logs and no trace_id reach Fixter and nothing errors or warns.

CommonJS (a require-based app, no "type": "module" in package.json):

# the four OTEL_* vars set as above
node --require @opentelemetry/auto-instrumentations-node/register app.js

ES modules ("type": "module", or .mjs files): --require does not hook ESM imports. Register the ESM loader hook from a small file and start the app with --import (Node also deprecates --require in favour of --import):

// instrumentation.mjs
import { register } from 'node:module';
register('import-in-the-middle/hook.mjs', import.meta.url);
await import('@opentelemetry/auto-instrumentations-node/register');
# the four OTEL_* vars set as above
node --import ./instrumentation.mjs app.js

Logs need an instrumented log library. Auto-instrumentation exports logs only for Winston, Pino, or Bunyan; a service that logs through plain console.log sends traces and metrics but no logs at all. If you use console, move to one of those to get queryable logs and the trace_id on each line that ties a log to its trace.

Where do the env vars go? Wherever your deploy defines its environment:

You run onSet them in
A plain process / VMthe shell, a .env loader, or the systemd unit (Environment=)
DockerENV/-e, or environment: in compose
Kubernetes (any flavor: EKS, GKE, self-managed)the Deployment’s env: block, with the key from a Secret
AWS ECSthe task definition’s environment/secrets

Store the API key as a secret in all of these; it’s a credential, not config.

  1. Open the Logs page in the Fixter app (it’s also where you land after login).
  2. The default view shows the last hour. If your service logged anything since Step 2, it’s here; use the filter bar to narrow to your service name.
  3. Click the tail button next to the query bar to stream new logs live while you exercise your service.

Sent metrics or traces instead? Metrics appear on the Metrics page; traces attach to your logs (any log with a trace opens its full trace view). From here, connect your agent over MCP and ask it about your data instead.

What each signal is for, what you get without writing instrumentation yourself, and what happens to it all once it lands: Telemetry.

  • 401 in your exporter or Collector logs: the Authorization header isn’t reaching Fixter or the key was revoked. Re-check Step 1 and that the env var is actually set in the process’s environment.
  • Exporter errors mentioning gRPC: set OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf (see Step 2).
  • Traces arrive but no logs (Node): the app is ESM and was started with --require, which does not instrument ESM imports, or it logs through plain console.log. Use the --import loader and a Winston/Pino/Bunyan logger (see the Node.js recipe in Step 2).
  • Data arrives but under the wrong name: set OTEL_SERVICE_NAME.
  • Batches partially rejected: the exporter logs show Fixter’s partialSuccess message naming the first rejected record and why.

Still stuck? Email info@fixter.dev and one of our founders will help you fix your problem asap.