Skip to content

Ingestion SDK overview

The Metrana ingestion SDK (the metrana package) is the client library your training code uses to send data to Metrana. You call a handful of functions — init, log, close — from your training loop, and your metrics, attributes, and reinforcement-learning data show up in the portal.

import metrana
# Reads the API key from the METRANA_API_KEY environment variable (see below).
metrana.init(workspace_name="my-team", project_name="my-project", run_name="run-001")
for step in range(num_steps):
metrana.log("loss", loss)
metrana.close()

That is the whole shape of it. The rest of these docs are about the details that make logging cheap, correct, and durable at scale.

metrana is a thin Python layer over a native Rust engine (metrana-logging-engine, via PyO3). The Python layer owns the public API, argument validation, the orchestration identifier, and the optional rendering pipeline; the engine owns everything performance-sensitive — batching, queueing, backpressure, step assignment, run creation/resume/fork, gRPC streaming, retries, and the on-disk spool.

The engine runs on a background thread. When you call log, your value is validated, handed to the engine’s queue, and control returns to your training loop immediately — the network send happens off the hot path. This is what keeps logging cheap even at high step rates.

your loop ──log()──▶ [Python validation] ──▶ [engine queue] ──▶ [batch + gRPC stream] ──▶ Metrana
└─(on delivery failure)─▶ [disk spool] ──▶ recovery

The philosophy: favour delivery, fail loudly

Section titled “The philosophy: favour delivery, fail loudly”

An experiment tracker that silently drops metrics is worse than useless — you find out your data has holes only when you go to analyze it. Metrana is built around the opposite default:

  • It keeps trying to deliver your data (retries with backoff, optional disk spool).
  • If it truly cannot deliver, it fails loudly — the next log / flush / close raises — rather than dropping data silently.
  • It never blocks your loop forever: every wait is bounded.

These defaults mean a healthy run pays almost nothing, and an unhealthy one surfaces the problem instead of hiding it. You can tune the trade-off (drop-and-continue instead of fail-loud, retry forever, etc.) — see Guarantees & retries — but the defaults are chosen for correctness first.

The single most impactful thing you can turn on for a real run is the disk spool, which turns even a sustained backend outage into a transparent failover.

Once your code is logging, the data appears in the portal:

What you log Where it appears
The run (name, config) The runs table, config as attributes
config / log_attributes A run’s Overview
log / log_distributed metrics A run’s Charts and Dashboard
RL per-episode / per-step data The run’s Environments views