Logging Tutorial#

This tutorial teaches you how to use the Minto library’s logging functionality and various logging control methods.

1. Basic Log Output#

Let’s start by trying the basic logging functionality.

import minto
import ommx_openjij_adapter as oj_ad
import jijmodeling as jm
import time

# Create an Experiment with logging enabled
exp = minto.Experiment(
    name="tutorial_experiment",
    auto_saving=False,     # Disable saving for tutorial
)

def create_problem():
    n = jm.Placeholder("n")
    rows = jm.Placeholder("rows", ndim=1)
    cols = jm.Placeholder("cols", ndim=1)
    value = jm.Placeholder("value", ndim=1)
    nnz = value.len_at(0)
    problem = jm.Problem("qubo")
    i = jm.Element("i", nnz)
    x = jm.BinaryVar("x", shape=(n,))

    problem += jm.sum(i, value[i] * x[rows[i]] * x[cols[i]])

    return problem

def qubo_instance_data():
    n = 5
    rows = [0, 1, 2, 3, 4]
    cols = [1, 2, 3, 4, 0]
    value = [1.0, -1.0, 2.0, -2.0, 3.0]
    return {"n": n, "rows": rows, "cols": cols, "value": value}

interpreter = jm.Interpreter(qubo_instance_data())
instance = interpreter.eval_problem(create_problem())

# Create and execute a run
run = exp.run()
with run:
    num_sweeps = 1000
    run.log_parameter("solver_type", "SimulatedAnnealing")
    run.log_parameter("temperature", 1.0)
    run.log_parameter("num_sweeps", num_sweeps)

    solution = oj_ad.OMMXOpenJijSAAdapter.solve(instance, num_sweeps=num_sweeps)
    run.log_solution(solution)

# Finish the experiment
exp.finish_experiment()
[2025-08-04 21:43:10] πŸš€ Starting experiment 'tutorial_experiment'
[2025-08-04 21:43:10]   β”œβ”€ πŸ“Š Environment: OS: Darwin 24.5.0, CPU: Apple M2 (8 cores), Memory: 24.0 GB, Python: 3.11.11
[2025-08-04 21:43:10]   β”œβ”€ πŸ“Š Environment Information
[2025-08-04 21:43:10]       β”œβ”€ OS: Darwin 24.5.0
[2025-08-04 21:43:10]       β”œβ”€ Platform: macOS-15.5-arm64-arm-64bit
[2025-08-04 21:43:10]       β”œβ”€ CPU: Apple M2 (8 cores)
[2025-08-04 21:43:10]       β”œβ”€ Memory: 24.0 GB
[2025-08-04 21:43:10]       β”œβ”€ Architecture: arm64
[2025-08-04 21:43:10]       β”œβ”€ Python: 3.11.11
[2025-08-04 21:43:10]       β”œβ”€ Virtual Environment: /Users/yuyamashiro/workspace/minto/.venv
[2025-08-04 21:43:10]       β”œβ”€ Key Package Versions:
[2025-08-04 21:43:10]   β”œβ”€ πŸ“Š Environment: OS: Darwin 24.5.0, CPU: Apple M2 (8 cores), Memory: 24.0 GB, Python: 3.11.11
[2025-08-04 21:43:10]   β”œβ”€ πŸ“Š Environment Information
[2025-08-04 21:43:10]       β”œβ”€ OS: Darwin 24.5.0
[2025-08-04 21:43:10]       β”œβ”€ Platform: macOS-15.5-arm64-arm-64bit
[2025-08-04 21:43:10]       β”œβ”€ CPU: Apple M2 (8 cores)
[2025-08-04 21:43:10]       β”œβ”€ Memory: 24.0 GB
[2025-08-04 21:43:10]       β”œβ”€ Architecture: arm64
[2025-08-04 21:43:10]       β”œβ”€ Python: 3.11.11
[2025-08-04 21:43:10]       β”œβ”€ Virtual Environment: /Users/yuyamashiro/workspace/minto/.venv
[2025-08-04 21:43:10]       β”œβ”€ Key Package Versions:
[2025-08-04 21:43:10]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:43:10]       β”œβ”€ πŸ“ Parameter: solver_type = SimulatedAnnealing
[2025-08-04 21:43:10]       β”œβ”€ πŸ“ Parameter: temperature = 1.0
[2025-08-04 21:43:10]       β”œβ”€ πŸ“ Parameter: num_sweeps = 1000
[2025-08-04 21:43:10]       β”œβ”€ 🎯 Solution '0': objective: -2.000, feasible: True
[2025-08-04 21:43:10]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:43:10] 🎯 Experiment 'tutorial_experiment' completed: 1 runs, total time: 0.2s
[2025-08-04 21:43:10]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:43:10]       β”œβ”€ πŸ“ Parameter: solver_type = SimulatedAnnealing
[2025-08-04 21:43:10]       β”œβ”€ πŸ“ Parameter: temperature = 1.0
[2025-08-04 21:43:10]       β”œβ”€ πŸ“ Parameter: num_sweeps = 1000
[2025-08-04 21:43:10]       β”œβ”€ 🎯 Solution '0': objective: -2.000, feasible: True
[2025-08-04 21:43:10]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:43:10] 🎯 Experiment 'tutorial_experiment' completed: 1 runs, total time: 0.2s

2. Custom Log Configuration#

Let’s customize how logs are displayed.

from minto.logging_config import LogConfig, LogLevel, LogFormat

# Simple log configuration
simple_config = LogConfig(
    format=LogFormat.SIMPLE,
    show_timestamps=False,
    show_icons=False,
    show_colors=False
)

print("=== Simple Log Configuration ===")
exp_simple = minto.Experiment(
    name="simple_experiment",
    verbose_logging=True,
    log_config=simple_config,
    auto_saving=False,
    collect_environment=False
)

run = exp_simple.run()
with run:
    run.log_parameter("method", "QAOA")
    run.log_parameter("layers", 3)

exp_simple.finish_experiment()
=== Simple Log Configuration ===
Starting experiment 'simple_experiment'
  β”œβ”€ Created run #0
      β”œβ”€ Parameter: method = QAOA
      β”œβ”€ Parameter: layers = 3
  β”œβ”€ Run #0 completed (0.0s)
Experiment 'simple_experiment' completed: 1 runs, total time: 0.0s
  β”œβ”€ Created run #0
      β”œβ”€ Parameter: method = QAOA
      β”œβ”€ Parameter: layers = 3
  β”œβ”€ Run #0 completed (0.0s)
Experiment 'simple_experiment' completed: 1 runs, total time: 0.0s
# Detailed log configuration
detailed_config = LogConfig(
    level=LogLevel.DEBUG,
    format=LogFormat.DETAILED,
    show_timestamps=True,
    show_icons=True,
    show_colors=False,  # Colors are often disabled in Jupyter environments
    max_parameter_length=200  # Increase maximum parameter display length
)

print("\n=== Detailed Log Configuration ===")
exp_detailed = minto.Experiment(
    name="detailed_experiment",
    verbose_logging=True,
    log_config=detailed_config,
    auto_saving=False,
    collect_environment=False
)

run = exp_detailed.run()
with run:
    run.log_parameter("algorithm", "Quantum Annealing")
    run.log_parameter("annealing_time", 20.0)

    # Log objects
    problem_data = {
        "variables": 100,
        "constraints": 50,
        "objective": "minimize"
    }
    run.log_object("problem_instance", problem_data)

exp_detailed.finish_experiment()
=== Detailed Log Configuration ===
[2025-08-04 21:43:23] [INFO] πŸš€ Starting experiment 'detailed_experiment'
[2025-08-04 21:43:23] [INFO]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:43:23] [INFO]       β”œβ”€ πŸ“ Parameter: algorithm = Quantum Annealing
[2025-08-04 21:43:23] [INFO]       β”œβ”€ πŸ“ Parameter: annealing_time = 20.0
[2025-08-04 21:43:23] [INFO]       β”œβ”€ πŸ“ Object 'problem_instance' (dict): 3 keys
[2025-08-04 21:43:23] [INFO]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:43:23] [INFO] 🎯 Experiment 'detailed_experiment' completed: 1 runs, total time: 0.0s
[2025-08-04 21:43:23] [INFO]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:43:23] [INFO]       β”œβ”€ πŸ“ Parameter: algorithm = Quantum Annealing
[2025-08-04 21:43:23] [INFO]       β”œβ”€ πŸ“ Parameter: annealing_time = 20.0
[2025-08-04 21:43:23] [INFO]       β”œβ”€ πŸ“ Object 'problem_instance' (dict): 3 keys
[2025-08-04 21:43:23] [INFO]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:43:23] [INFO] 🎯 Experiment 'detailed_experiment' completed: 1 runs, total time: 0.0s

3. Solver Execution Logging#

Let’s learn how to automatically log solver execution time and parameters.

# Define QUBO problem using jijmodeling (same as in basic example)
def create_problem():
    n = jm.Placeholder("n")
    rows = jm.Placeholder("rows", ndim=1)
    cols = jm.Placeholder("cols", ndim=1)
    value = jm.Placeholder("value", ndim=1)
    nnz = value.len_at(0)
    problem = jm.Problem("qubo")
    i = jm.Element("i", nnz)
    x = jm.BinaryVar("x", shape=(n,))

    problem += jm.sum(i, value[i] * x[rows[i]] * x[cols[i]])

    return problem

def qubo_instance_data():
    n = 5
    rows = [0, 1, 2, 3, 4]
    cols = [1, 2, 3, 4, 0]
    value = [1.0, -1.0, 2.0, -2.0, 3.0]
    return {"n": n, "rows": rows, "cols": cols, "value": value}

# Prepare the problem instance
interpreter = jm.Interpreter(qubo_instance_data())
instance = interpreter.eval_problem(create_problem())

# Execute solver logging with real OpenJij solver
exp = minto.Experiment(
    name="solver_logging_experiment",
    verbose_logging=True,
    auto_saving=False,
    collect_environment=False
)

run = exp.run()
with run:
    # Method 1: Manual parameter logging and solver execution
    run.log_parameter("solver_type", "SimulatedAnnealing")
    run.log_parameter("num_sweeps", 2000)
    run.log_parameter("temperature", 1.0)

    # Execute solver directly
    solution = oj_ad.OMMXOpenJijSAAdapter.solve(instance, num_sweeps=2000)
    run.log_solution(solution)

    print("\n--- Using log_solver wrapper ---")

    # Method 2: Using log_solver wrapper for automatic parameter logging
    def solve_with_openjij(instance, num_sweeps=1000, seed=None):
        """Wrapper function for OpenJij solver"""
        return oj_ad.OMMXOpenJijSAAdapter.solve(
            instance,
            num_sweeps=num_sweeps,
            seed=seed
        )

    # Wrap the solver function to automatically log parameters and execution time
    wrapped_solver = run.log_solver(
        "OpenJij_SA",
        solve_with_openjij,
        exclude_params=["seed"]  # Exclude seed from logging if desired
    )

    # Execute solver with automatic parameter and timing logging
    solution2 = wrapped_solver(
        instance=instance,
        num_sweeps=1500,
        seed=42
    )

    run.log_solution(solution2)

exp.finish_experiment()
[2025-08-04 21:43:29] πŸš€ Starting experiment 'solver_logging_experiment'
[2025-08-04 21:43:29]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Parameter: solver_type = SimulatedAnnealing
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Parameter: num_sweeps = 2000
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Parameter: temperature = 1.0
[2025-08-04 21:43:29]       β”œβ”€ 🎯 Solution '0': objective: -2.000, feasible: True

--- Using log_solver wrapper ---
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Parameter: solver_name = OpenJij_SA
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Object 'instance' (ommx.Instance): instance logged
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Parameter: num_sweeps = 1500
[2025-08-04 21:43:29]       β”œβ”€ βš™οΈ Solver 'OpenJij_SA' executed (0.002s)
[2025-08-04 21:43:29]       β”œβ”€ 🎯 Solution 'OpenJij_SA_result': objective: -2.000, feasible: True
[2025-08-04 21:43:29]       β”œβ”€ 🎯 Solution '2': objective: -2.000, feasible: True
[2025-08-04 21:43:29]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:43:29] 🎯 Experiment 'solver_logging_experiment' completed: 1 runs, total time: 0.0s
[2025-08-04 21:43:29]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Parameter: solver_type = SimulatedAnnealing
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Parameter: num_sweeps = 2000
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Parameter: temperature = 1.0
[2025-08-04 21:43:29]       β”œβ”€ 🎯 Solution '0': objective: -2.000, feasible: True

--- Using log_solver wrapper ---
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Parameter: solver_name = OpenJij_SA
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Object 'instance' (ommx.Instance): instance logged
[2025-08-04 21:43:29]       β”œβ”€ πŸ“ Parameter: num_sweeps = 1500
[2025-08-04 21:43:29]       β”œβ”€ βš™οΈ Solver 'OpenJij_SA' executed (0.002s)
[2025-08-04 21:43:29]       β”œβ”€ 🎯 Solution 'OpenJij_SA_result': objective: -2.000, feasible: True
[2025-08-04 21:43:29]       β”œβ”€ 🎯 Solution '2': objective: -2.000, feasible: True
[2025-08-04 21:43:29]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:43:29] 🎯 Experiment 'solver_logging_experiment' completed: 1 runs, total time: 0.0s

4. Multiple Run Execution#

Let’s execute multiple runs and verify the hierarchical log display.

# Parameter sweep experiment
exp = minto.Experiment(
    name="parameter_sweep",
    verbose_logging=True,
    auto_saving=False,
    collect_environment=False
)

# Execute with different temperature parameters
temperatures = [0.1, 0.5, 1.0, 2.0]

for i, temp in enumerate(temperatures):
    run = exp.run()
    with run:
        run.log_parameter("temperature", temp)
        run.log_parameter("algorithm", "Simulated Annealing")
        run.log_parameter("max_iterations", 1000)

        # Execute dummy optimization
        time.sleep(0.05)  # Simulate computation time

        # Simulate results based on temperature
        import random
        energy = random.uniform(-100, -50) * (1 + temp)

        run.log_parameter("final_energy", energy)

exp.finish_experiment()
[2025-08-04 21:43:55] πŸš€ Starting experiment 'parameter_sweep'
[2025-08-04 21:43:55]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: temperature = 0.1
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: algorithm = Simulated Annealing
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: max_iterations = 1000
[2025-08-04 21:43:55]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: temperature = 0.1
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: algorithm = Simulated Annealing
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: max_iterations = 1000
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: final_energy = -62.28833959601645
[2025-08-04 21:43:55]   β”œβ”€ βœ… Run #0 completed (0.1s)
[2025-08-04 21:43:55]   β”œβ”€ πŸƒ Created run #1
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: temperature = 0.5
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: algorithm = Simulated Annealing
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: max_iterations = 1000
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: final_energy = -62.28833959601645
[2025-08-04 21:43:55]   β”œβ”€ βœ… Run #0 completed (0.1s)
[2025-08-04 21:43:55]   β”œβ”€ πŸƒ Created run #1
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: temperature = 0.5
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: algorithm = Simulated Annealing
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: max_iterations = 1000
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: final_energy = -84.82287831504644
[2025-08-04 21:43:55]   β”œβ”€ βœ… Run #1 completed (0.1s)
[2025-08-04 21:43:55]   β”œβ”€ πŸƒ Created run #2
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: temperature = 1.0
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: algorithm = Simulated Annealing
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: max_iterations = 1000
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: final_energy = -84.82287831504644
[2025-08-04 21:43:55]   β”œβ”€ βœ… Run #1 completed (0.1s)
[2025-08-04 21:43:55]   β”œβ”€ πŸƒ Created run #2
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: temperature = 1.0
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: algorithm = Simulated Annealing
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: max_iterations = 1000
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: final_energy = -148.74892665102823
[2025-08-04 21:43:55]   β”œβ”€ βœ… Run #2 completed (0.1s)
[2025-08-04 21:43:55]   β”œβ”€ πŸƒ Created run #3
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: temperature = 2.0
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: algorithm = Simulated Annealing
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: max_iterations = 1000
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: final_energy = -148.74892665102823
[2025-08-04 21:43:55]   β”œβ”€ βœ… Run #2 completed (0.1s)
[2025-08-04 21:43:55]   β”œβ”€ πŸƒ Created run #3
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: temperature = 2.0
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: algorithm = Simulated Annealing
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: max_iterations = 1000
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: final_energy = -159.64497314052375
[2025-08-04 21:43:55]   β”œβ”€ βœ… Run #3 completed (0.1s)
[2025-08-04 21:43:55] 🎯 Experiment 'parameter_sweep' completed: 4 runs, total time: 0.2s
[2025-08-04 21:43:55]       β”œβ”€ πŸ“ Parameter: final_energy = -159.64497314052375
[2025-08-04 21:43:55]   β”œβ”€ βœ… Run #3 completed (0.1s)
[2025-08-04 21:43:55] 🎯 Experiment 'parameter_sweep' completed: 4 runs, total time: 0.2s

5. Using Global Configuration#

Let’s learn how to set global log configuration and share it across multiple experiments.

from minto.logger import configure_logging, get_logger

# Global log configuration
configure_logging(
    enabled=True,
    level=LogLevel.INFO,
    show_timestamps=True,
    show_icons=True,
    show_colors=False  # For Jupyter environments
)

print("=== Experiment 1 using Global Configuration ===")
exp1 = minto.Experiment(
    name="global_config_exp1",
    verbose_logging=True,  # Global configuration is automatically applied
    auto_saving=False,
    collect_environment=False
)

run = exp1.run()
with run:
    run.log_parameter("method", "Genetic Algorithm")
    run.log_parameter("population_size", 100)

exp1.finish_experiment()

print("\n=== Experiment 2 using Global Configuration ===")
exp2 = minto.Experiment(
    name="global_config_exp2",
    verbose_logging=True,  # Same global configuration is applied
    auto_saving=False,
    collect_environment=False
)

run = exp2.run()
with run:
    run.log_parameter("method", "Particle Swarm Optimization")
    run.log_parameter("swarm_size", 50)

exp2.finish_experiment()
=== Experiment 1 using Global Configuration ===
[2025-08-04 21:44:02] πŸš€ Starting experiment 'global_config_exp1'
[2025-08-04 21:44:02]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:44:02]       β”œβ”€ πŸ“ Parameter: method = Genetic Algorithm
[2025-08-04 21:44:02]       β”œβ”€ πŸ“ Parameter: population_size = 100
[2025-08-04 21:44:02]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:44:02] 🎯 Experiment 'global_config_exp1' completed: 1 runs, total time: 0.0s

=== Experiment 2 using Global Configuration ===
[2025-08-04 21:44:02] πŸš€ Starting experiment 'global_config_exp2'
[2025-08-04 21:44:02]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:44:02]       β”œβ”€ πŸ“ Parameter: method = Particle Swarm Optimization
[2025-08-04 21:44:02]       β”œβ”€ πŸ“ Parameter: swarm_size = 50
[2025-08-04 21:44:02]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:44:02] 🎯 Experiment 'global_config_exp2' completed: 1 runs, total time: 0.0s
[2025-08-04 21:44:02]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:44:02]       β”œβ”€ πŸ“ Parameter: method = Genetic Algorithm
[2025-08-04 21:44:02]       β”œβ”€ πŸ“ Parameter: population_size = 100
[2025-08-04 21:44:02]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:44:02] 🎯 Experiment 'global_config_exp1' completed: 1 runs, total time: 0.0s

=== Experiment 2 using Global Configuration ===
[2025-08-04 21:44:02] πŸš€ Starting experiment 'global_config_exp2'
[2025-08-04 21:44:02]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:44:02]       β”œβ”€ πŸ“ Parameter: method = Particle Swarm Optimization
[2025-08-04 21:44:02]       β”œβ”€ πŸ“ Parameter: swarm_size = 50
[2025-08-04 21:44:02]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:44:02] 🎯 Experiment 'global_config_exp2' completed: 1 runs, total time: 0.0s

6. Direct Logger Usage#

Let’s also check how to use the logger directly without the Experiment/Run classes.

# Get the global logger
logger = get_logger()

print("=== Direct Logger Usage ===")

# Manual experiment logging
logger.log_experiment_start("manual_experiment")

# Manual run logging
logger.log_run_start(0)
logger.log_parameter("manual_param", "direct_logging")
logger.log_object("custom_object", {"type": "manual", "value": 42})

# Log solver execution
logger.log_solver("manual_solver", execution_time=1.5)

# End run and experiment
logger.log_run_end(0, 2.0)
logger.log_experiment_end("manual_experiment", 2.0, 1)
=== Direct Logger Usage ===
[2025-08-04 21:44:06] πŸš€ Starting experiment 'manual_experiment'
[2025-08-04 21:44:06]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:44:06]       β”œβ”€ πŸ“ Parameter: manual_param = direct_logging
[2025-08-04 21:44:06]       β”œβ”€ πŸ“ Object 'custom_object' ({'type': 'manual', 'value': 42})
[2025-08-04 21:44:06]       β”œβ”€ βš™οΈ Solver 'manual_solver' executed (1.500s)
[2025-08-04 21:44:06]   β”œβ”€ βœ… Run #0 completed (2.0s)
[2025-08-04 21:44:06] 🎯 Experiment 'manual_experiment' completed: 1 runs, total time: 2.0s
[2025-08-04 21:44:06]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:44:06]       β”œβ”€ πŸ“ Parameter: manual_param = direct_logging
[2025-08-04 21:44:06]       β”œβ”€ πŸ“ Object 'custom_object' ({'type': 'manual', 'value': 42})
[2025-08-04 21:44:06]       β”œβ”€ βš™οΈ Solver 'manual_solver' executed (1.500s)
[2025-08-04 21:44:06]   β”œβ”€ βœ… Run #0 completed (2.0s)
[2025-08-04 21:44:06] 🎯 Experiment 'manual_experiment' completed: 1 runs, total time: 2.0s

7. Environment-Specific Configuration Examples#

Let’s check recommended configurations for different environments (development, production, CI).

# Development environment configuration
dev_config = LogConfig(
    level=LogLevel.DEBUG,
    format=LogFormat.DETAILED,
    show_timestamps=True,
    show_icons=True,
    show_colors=False,  # For Jupyter
    max_parameter_length=300  # Allow longer parameter values in development
)

print("=== Development Environment Configuration ===")
exp_dev = minto.Experiment(
    name="development_test",
    verbose_logging=True,
    log_config=dev_config,
    auto_saving=False,
    collect_environment=False
)

run = exp_dev.run()
with run:
    run.log_parameter("debug_mode", True)
    run.log_parameter("verbose_output", True)

exp_dev.finish_experiment()

# Production environment configuration
prod_config = LogConfig(
    level=LogLevel.WARNING,
    format=LogFormat.MINIMAL,  # Use MINIMAL instead of COMPACT
    show_timestamps=True,
    show_icons=False,
    show_colors=False,
    max_parameter_length=50  # Limit parameter length in production
)

print("\n=== Production Environment Configuration ===")
exp_prod = minto.Experiment(
    name="production_test",
    verbose_logging=True,
    log_config=prod_config,
    auto_saving=False,
    collect_environment=False
)

run = exp_prod.run()
with run:
    run.log_parameter("production_mode", True)
    # Only WARNING level and above are displayed, so normal parameter logs won't be shown

exp_prod.finish_experiment()
=== Development Environment Configuration ===
[2025-08-04 21:44:55] [INFO] πŸš€ Starting experiment 'development_test'
[2025-08-04 21:44:55] [INFO]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:44:55] [INFO]       β”œβ”€ πŸ“ Parameter: debug_mode = True
[2025-08-04 21:44:55] [INFO]       β”œβ”€ πŸ“ Parameter: verbose_output = True
[2025-08-04 21:44:55] [INFO]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:44:55] [INFO] 🎯 Experiment 'development_test' completed: 1 runs, total time: 0.0s

=== Production Environment Configuration ===
[2025-08-04 21:44:55] [INFO]   β”œβ”€ πŸƒ Created run #0
[2025-08-04 21:44:55] [INFO]       β”œβ”€ πŸ“ Parameter: debug_mode = True
[2025-08-04 21:44:55] [INFO]       β”œβ”€ πŸ“ Parameter: verbose_output = True
[2025-08-04 21:44:55] [INFO]   β”œβ”€ βœ… Run #0 completed (0.0s)
[2025-08-04 21:44:55] [INFO] 🎯 Experiment 'development_test' completed: 1 runs, total time: 0.0s

=== Production Environment Configuration ===

8. Disabling Logging#

Set just the verbose_logging parameter to False to disable logging for an individual experiment.

# Method 1: Disable logging for individual experiments
print("=== Method 1: Disable logging for individual experiments ===")
exp_no_log = minto.Experiment(
    name="no_logging_experiment",
    verbose_logging=False,  # Disable logging for this experiment
    auto_saving=False,
    collect_environment=False
)

run = exp_no_log.run()
with run:
    # These log calls will not produce any output
    run.log_parameter("param1", "value1")
    run.log_parameter("param2", 42)
    print("Parameters logged, but no log output shown")

exp_no_log.finish_experiment()
=== Method 1: Disable logging for individual experiments ===
Parameters logged, but no log output shown

Summary#

In this tutorial, we learned about the Minto library’s logging functionality:

  1. Basic Log Output: Easy logging activation with verbose_logging=True

  2. Custom Configuration: Detailed control of log display using LogConfig

  3. Solver Logging: Automatic logging of solver execution with log_solver

  4. Hierarchical Display: Clear hierarchical structure for multiple runs

  5. Global Configuration: Batch configuration with configure_logging

  6. Direct Logger: Flexible control with low-level APIs

  7. Environment Adaptation: Optimization for development and production environments

By utilizing these features, you can efficiently monitor experiment progress and significantly improve debugging and optimization work.