Skip to content

Steps, scales & labels

A series is identified by (metric_name, scale, labels). Two points with the same name but a different scale or different labels go to different series, each with its own step axis. This page covers the arguments that shape series identity and the step axis.

Each series has its own step axis. The step argument to log controls it:

step value meaning
None (default) auto-increment from the series’ last step
a single int the step of the first point; further points in the call continue from it
a sequence/array an explicit step per point (length must match value)
metrana.log("loss", 0.5) # auto: next step
metrana.log("loss", [a, b, c], step=100) # steps 100, 101, 102
metrana.log("loss", [a, b, c], step=[10, 20, 30]) # explicit steps

Auto-increment is the common case for a single-writer series. Use explicit steps when you log out of order, resume a run, or want a metric pinned to your global training step (see Retrieving the last step).

timestamp works exactly like step, in Unix milliseconds:

  • None (default) — the server stamps each point on arrival.
  • a single int — applied to every point in the call.
  • a sequence/array — one timestamp per point (length must match value).
import time
now_ms = int(time.time() * 1000)
metrana.log("loss", loss, timestamp=now_ms)

These three arguments shape series identity:

The step scale — a StandardMetricScale value: "ML_STEP", "EPISODE", or "ENVIRONMENT_STEP". None defaults to ML_STEP. Only log / log_distributed take scale; the RL helpers fix their own scale (see RL metrics).

import metrana
metrana.log("custom_metric", v, scale=metrana.StandardMetricScale.ML_STEP)
metrana.log("custom_metric", v, scale="ML_STEP") # strings work too

A dict[str, str] that, together with the name and scale, identifies the series. Two points with the same name but different labels form different series — useful for splitting a metric by a dimension:

metrana.log("loss", per_layer_loss, labels={"layer": "3"})
metrana.log("reward", r, labels={"policy": "greedy"})

A shorthand that adds the label {"evaluation": "true"} (unless you already set the evaluation key in labels), so evaluation points form a series distinct from otherwise identical training points:

metrana.log("reward", train_reward) # training series
metrana.log("reward", eval_reward, evaluation=True) # distinct eval series
metrana.log("reward", r, labels={"policy": "greedy"}) # distinct labelled series

metrana.get_last_step(metric_name, scale=None, labels=None) returns the last step logged for a series, or None if nothing has been logged yet. Pass the same scale / labels you logged it with.

This value is seeded from the server at init(), so after a restart or resume you can continue from where the run left off:

last = metrana.get_last_step("loss")
next_step = 0 if last is None else last + 1
metrana.log("loss", loss, step=next_step)

This is the building block for resuming a run with explicit steps — see Resuming & forking. The RL equivalent is get_env_last_rl_step_and_episode.