prime-rl uses loguru for logging with a global logger pattern. All logs are captured at the deployment level (stdout/stderr redirection for local, tee for SLURM) under {output_dir}/logs/. For RL training, we recommend streaming logs into tmux panes (as set up by tmux.sh).
We use a singleton pattern with a module-level global logger instance (_LOGGER).
from prime_rl.utils.logger import setup_logger, get_logger
# At entrypoint - call ONCE
logger = setup_logger("info")
# Anywhere else in codebase
logger = get_logger()
logger.info("Hello world")How it works:
-
get_logger()- Returns the global logger instance. Always works — ifsetup_loggerhasn't been called yet, it initializes a default logger automatically. Safe to call from any module at any time. -
setup_logger(log_level)- Configures (or reconfigures) the global logger:- Creates an isolated loguru
Loggerinstance (not the defaultloguru.logger) to prevent third-party code from hijacking our logs - Adds a stdout handler with colorized output (or JSON output if
json_logging=True) - Can be called multiple times — cleans up the previous logger before creating a new one
- Creates an isolated loguru
-
reset_logger()- Resets the global logger toNone:- Used in subprocesses that inherit parent state (e.g., env workers)
- Used in tests between test cases
Logs are captured at the deployment level — the entrypoint redirects subprocess stdout/stderr to files (local) or tee captures them (SLURM). The structure is consistent across deployment types: logs/trainer.log and logs/inference.log always exist, regardless of whether the run is local or multi-node SLURM.
{output_dir}/logs/
├── trainer.log # trainer stdout (rank 0 only)
├── orchestrator.log # orchestrator stdout
├── inference.log # vLLM inference server stdout
├── trainer/
│ └── torchrun/ # per-rank stdout/stderr (all ranks)
└── envs/
├── train/{env_name}/
│ ├── env_server.log
│ └── env_worker_{id}.log
└── eval/{env_name}/
└── ...
{output_dir}/logs/
├── trainer.log -> trainer/node_0.log (symlink)
├── inference.log -> inference/node_0.log (symlink)
├── orchestrator.log # orchestrator stdout
├── trainer/
│ ├── node_0.log # per-node trainer output (rank 0 only)
│ ├── node_1.log
│ └── torchrun/ # per-rank stdout/stderr (all ranks)
├── inference/
│ ├── node_0.log # per-node inference output
│ ├── node_1.log
│ └── router_0.log # vllm-router per replica
└── envs/
└── ...
Environment logs live under logs/envs/train/{env_name}/ and logs/envs/eval/{env_name}/. Env log verbosity is controlled by orchestrator.log.vf_level.
Only rank 0 output is shown in trainer.log. Per-rank logs from all ranks are available under logs/trainer/torchrun/{rdzv_id}/attempt_0/{rank}/{stdout,stderr}.log, written by torchrun's --log-dir.
scripts/tmux.sh sets up a tmux session for RL runs with four panes:
- Trainer: follows
{output_dir}/logs/trainer.log - Orchestrator: follows
{output_dir}/logs/orchestrator.log - Envs: follows
{output_dir}/logs/envs/*/*/*.log - Inference: follows
{output_dir}/logs/inference.log