How to Set Up Logging with LogRecorder and WandbRecorder in EvoRL
To set up logging in EvoRL, instantiate LogRecorder for local file output and WandbRecorder for Weights & Biases dashboards, then wrap them in a ChainRecorder to broadcast metrics to both backends simultaneously.
EvoRL implements a lightweight, extensible Recorder framework that standardizes how training metrics are captured and stored. The emi-group/evorl repository provides two production-ready implementations—LogRecorder for human-readable files and WandbRecorder for cloud-based experiment tracking—both designed to work interchangeably through a unified interface defined in evorl/recorders/recorder.py.
Understanding the Recorder Architecture
The logging system centers on an abstract base class that enforces a consistent lifecycle across all recording backends.
In evorl/recorders/recorder.py, the Recorder class defines three abstract methods:
init()– Prepares the recording backend (opens files, initializes API connections).write(data, step)– Persists a dictionary of metrics at a specific training step.close()– Finalizes and flushes buffers, terminates connections.
The ChainRecorder class implements the same interface while acting as a container. It accepts a list of Recorder instances and forwards every lifecycle call to each contained recorder. This design allows a single write() call to propagate to multiple destinations—file logs and WandB dashboards—without modifying training loop code.
Configuring LogRecorder for Local File Output
LogRecorder provides durable, human-readable logging to disk with optional console output.
Located in evorl/recorders/log_recorder.py, this recorder:
- Creates a dedicated Python logger named
"LogRecorder". - Attaches a
FileHandlerpointing to the user-specifiedlog_path. - Serializes data as YAML after converting JAX-native structures (
np.ndarray,np.generic,pd.Series/DataFrame) to standard Python types.
This conversion ensures that JAX tensors and pandas objects—common in EvoRL workflows—serialize cleanly without raising type errors.
from pathlib import Path
from evorl.recorders import LogRecorder
# Initialize file-based logging with console mirroring
log_recorder = LogRecorder(
log_path=Path("./experiments/run_001.log"),
console=True
)
log_recorder.init()
Configuring WandbRecorder for Weights & Biases
WandbRecorder streams metrics to Weights & Biases for real-time visualization and experiment comparison.
Implemented in evorl/recorders/wandb_recorder.py, this recorder:
- Invokes
wandb.init(**self.wandb_kwargs)using the supplied project name, run name, configuration dictionary, tags, and output directory. - Converts pandas objects into WandB-native visualizations (
Histogram,Table). - Calls
wandb.log(data, step=step)to transmit scalar metrics and media.
from pathlib import Path
from evorl.recorders import WandbRecorder
wandb_recorder = WandbRecorder(
project="evorl-experiments",
name="ppo-cartpole-v1",
config={"lr": 3e-4, "gamma": 0.99},
tags=["ppo", "cartpole"],
path=Path("./wandb_outputs")
)
wandb_recorder.init()
Integrating Recorders via Hydra Configuration
The standard EvoRL training pipeline automates recorder setup through Hydra configuration. The setup_recorders function in scripts/train.py reads config.recorders—a list of strings specifying which backends to activate—and constructs the appropriate instances.
# scripts/train.py
def setup_recorders(config: DictConfig, workflow_name: str):
output_dir = Path(config.output_dir)
recorders = []
exp_name = "_".join([
workflow_name,
config.env.env_name,
config.env.env_type
])
for rec in config.recorders:
match rec:
case "wandb":
wandb_recorder = WandbRecorder(
project=config.project,
name=exp_name,
group="dev",
config=OmegaConf.to_container(config, resolve=True),
tags=[workflow_name, config.env.env_name],
path=output_dir,
)
recorders.append(wandb_recorder)
case "log":
log_recorder = LogRecorder(
log_path=output_dir / f"{exp_name}.log",
console=True,
)
recorders.append(log_recorder)
return recorders
The workflow wraps the returned list in a ChainRecorder via workflow.add_recorders(recorders), enabling unified logging across all configured backends.
To activate both recorders, modify your Hydra configuration:
# configs/config.yaml
recorders: ["log", "wandb"]
project: evorl-demo
tags: ["benchmark", "v1"]
Then launch training:
python -m evorl.scripts.train \
env.env_name=CartPole \
env.env_type=classic \
workflow_cls=evorl.workflows.RLWorkflow
Manual Setup Without Hydra
For custom training scripts outside the Hydra ecosystem, instantiate and link recorders manually:
from pathlib import Path
from evorl.recorders import LogRecorder, WandbRecorder, ChainRecorder
# 1. Create individual recorders
log = LogRecorder(log_path=Path("./local.log"), console=True)
wandb = WandbRecorder(
project="custom-project",
name="manual-run",
config={"batch_size": 256},
path=Path("./outputs")
)
# 2. Bundle into ChainRecorder
recorders = ChainRecorder([log, wandb])
recorders.init()
# 3. Log training metrics
for step in range(100):
metrics = {"reward": step * 0.1, "loss": 1.0 / (step + 1)}
recorders.write(metrics, step=step)
# 4. Cleanup
recorders.close()
This pattern gives you full control over initialization timing and resource management while maintaining compatibility with EvoRL's standardized logging interface.
Summary
- Recorder is the abstract base class in
evorl/recorders/recorder.pythat definesinit(),write(), andclose()for all logging backends. - LogRecorder writes YAML-formatted logs to disk, automatically converting JAX and pandas structures to Python-native types.
- WandbRecorder initializes Weights & Biases runs and streams metrics via
wandb.log(), supporting rich visualizations for pandas data. - ChainRecorder aggregates multiple recorders, allowing simultaneous file and cloud logging through a single interface.
- Hydra integration via
scripts/train.pyautomatically constructs recorders from theconfig.recorderslist, handling experiment naming and path resolution.
Frequently Asked Questions
What file format does LogRecorder use to store metrics?
LogRecorder serializes metrics as YAML in the specified log file. Before writing, it converts JAX arrays (np.ndarray, np.generic) and pandas objects (Series, DataFrame) to standard Python lists and dictionaries to ensure compatibility with the YAML serializer.
Can I use both LogRecorder and WandbRecorder simultaneously?
Yes. Pass both recorders to a ChainRecorder instance, or list both "log" and "wandb" in your Hydra config.recorders list. The ChainRecorder forwards write() calls to both backends, ensuring local file persistence and cloud dashboard updates occur at every logging step.
How does WandbRecorder handle experiment configuration?
During initialization, WandbRecorder passes the config dictionary directly to wandb.init() via the wandb_kwargs parameter. According to the source code in evorl/recorders/wandb_recorder.py, this configuration populates the run's hyperparameter panel in the Weights & Biases dashboard, enabling filtering and grouping across experiments.
Where is the log file saved when using the Hydra training script?
The setup_recorders function in scripts/train.py constructs the log path by combining config.output_dir with an experiment name derived from the workflow type, environment name, and tags. The file follows the pattern {output_dir}/{workflow_name}_{env_name}_{env_type}.log.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →