Saphan StudioDocs
Integrations

Running a metrics export

Three keys, the egress admission the address does not grant you, what each exit status means, and the one limit to read before you schedule anything.

For the operator who runs the export and reads its result.

After reading it you can configure a collector, admit it, run one export cycle, and tell a partial success from a complete one.

Before you start: a collector that speaks OTLP/HTTP, and what the export gives you read once — it is the page that says which series exist.

saphan otel export runs one explicit export cycle. It reads the resolved workspace record, sends the metrics to the configured collector, and prints both the row-source report and the endpoint counters.

1 · Three keys

Set the destination before enabling export, so you never have an enabled exporter pointing nowhere.

saphan config set otel.endpoint_name production-collector --workspace <workspace>
saphan config set otel.endpoint_url http://<collector>:4318/v1/metrics --workspace <workspace>
saphan config set otel.enabled true --workspace <workspace>
keymeaning
otel.enabledtrue or false. Absent means false — telemetry never starts because a key was left unset
otel.endpoint_nameyour label for the collector. It is the only endpoint identity that reaches the wire, and it rides the exporter's health points rather than the record metrics
otel.endpoint_urlthe collector's OTLP/HTTP metrics endpoint

otel.endpoint_url accepts http or https only, and refuses a user:password@ prefix or a query string. saphan config show prints this key verbatim, so a credential smuggled into the URL would be published. Authentication is not configurable through this key — if your collector needs credentials, put it behind something that supplies them.

2 · Setting the address grants no network access

The address is configuration. Reaching it is a separate, explicit permission. The collector must be admitted in the workspace's egress policy, by address and port.

This is the mistake operators actually make. When an export fails at the wire, check the egress admission before you suspect the collector — the exporter's own refusal reminds you of exactly this.

Validate the document the export command will actually load, rather than the one you think it will:

saphan otel validate-policy <state-dir>/egress/policy.json --workspace <workspace>

A collector on a private range is admissible and must be chosen deliberately — there is a configuration key that permits private ranges to be named. ⛔ Loopback and the cloud metadata endpoint stay refused regardless, and so does link-local space.

For a hostname, admission has two stages, and the distinction shows up in the refusal:

  1. the policy must admit the configured host and port;
  2. the exporter resolves the name once and applies the hard-deny and private-range rules to the address it got, then dials that exact approved address — it does not resolve the name again.

⇒ A refusal naming a denied address therefore means the hostname was admitted but its resolved address was not. Fix the collector's DNS, or admit the narrow private range deliberately.

Redirects are refused. Configure the final metrics URL, not something that forwards to it — the exporter does not follow a redirect even when the target would otherwise be admitted. That matters most for a collector behind a redirecting proxy.

See Egress control for the policy document itself.

3 · Run one cycle

saphan otel export --workspace <workspace>

It prints the row-source report — every metric it emitted, and every one it declined with the reason — followed by the per-endpoint counters:

countermeaning
acceptedrows the exporter submitted
exportedrows the collector answered successfully
malformedrows rejected before transmission, because the metric shape was invalid
rejectedthe collector received a valid request and rejected points
failed, refused, buffered, dropped, depthanything non-zero means the cycle did not fully land

Anything non-zero beyond accepted and exported makes the command exit non-zero.

4 · What the exit status means

exitmeaningwhat to do
0the cycle completed and no counter reports unaccepted or remaining rowsnothing — but see step 5
1configuration or the egress policy is missing or invalidset the keys, create the policy, validate it, retry
2the cycle ran, but the collector or the wire did not accept every rowcheck the collector is listening, the URL is right, and its host and port are admitted
3otel.enabled is absent or false — no export was attemptedconfigure the endpoint, then enable it

A disabled exporter refuses loudly and exits 3. It never exits 0 having done nothing, because a silent success is how an operator concludes telemetry is flowing when it is not.

5 · Confirm on the collector, not from the exit status

Exit 0 is the exporter's account of an HTTP response, not proof the collector kept anything. Confirm receipt independently — read the collector's own logs, or whatever sink you configured it to write.

What to read before you schedule anything

Every invocation exports the whole record. There is no cursor and no acknowledgement yet, so calling the command again replays every row, including delta sums. ⇒ Use it for an operator-requested reading. Do not schedule repeated calls until a cursor exists — a scheduled job against this build produces a dashboard that climbs because of the schedule rather than because of the fleet.

Operator-invoked only. There is no timer and no hook on the run path, and that is deliberate: an export must never slow a run down.

No authentication through the endpoint key, and ⚠ a successful export is not a delivery guarantee — both above.

On this page