import logging
from logging import CRITICAL # NOQA
from logging import DEBUG # NOQA
from logging import ERROR # NOQA
from logging import FATAL # NOQA
from logging import INFO # NOQA
from logging import WARN # NOQA
from logging import WARNING # NOQA
import threading
from typing import Optional
import colorlog
_lock: threading.Lock = threading.Lock()
_default_handler: Optional[logging.Handler] = None
def create_default_formatter() -> colorlog.ColoredFormatter:
"""Create a default formatter of log messages.
This function is not supposed to be directly accessed by library users.
"""
return colorlog.ColoredFormatter(
"%(log_color)s[%(levelname)1.1s %(asctime)s]%(reset)s %(message)s"
)
def _get_library_name() -> str:
return __name__.split(".")[0]
def _get_library_root_logger() -> logging.Logger:
return logging.getLogger(_get_library_name())
def _configure_library_root_logger() -> None:
global _default_handler
with _lock:
if _default_handler:
# This library has already configured the library root logger.
return
_default_handler = logging.StreamHandler() # Set sys.stderr as stream.
_default_handler.setFormatter(create_default_formatter())
# Apply our default configuration to the library root logger.
library_root_logger: logging.Logger = _get_library_root_logger()
library_root_logger.addHandler(_default_handler)
library_root_logger.setLevel(logging.INFO)
library_root_logger.propagate = False
def _reset_library_root_logger() -> None:
global _default_handler
with _lock:
if not _default_handler:
return
library_root_logger: logging.Logger = _get_library_root_logger()
library_root_logger.removeHandler(_default_handler)
library_root_logger.setLevel(logging.NOTSET)
_default_handler = None
def get_logger(name: str) -> logging.Logger:
"""Return a logger with the specified name.
This function is not supposed to be directly accessed by library users.
"""
_configure_library_root_logger()
return logging.getLogger(name)
[docs]def get_verbosity() -> int:
"""Return the current level for the Optuna's root logger.
Example:
Get the default verbosity level.
.. testsetup::
def objective(trial):
x = trial.suggest_float("x", -100, 100)
y = trial.suggest_categorical("y", [-1, 0, 1])
return x**2 + y
.. testcode::
import optuna
# The default verbosity level of Optuna is `optuna.logging.INFO`.
print(optuna.logging.get_verbosity())
# 20
print(optuna.logging.INFO)
# 20
# There are logs of the INFO level.
study = optuna.create_study()
study.optimize(objective, n_trials=5)
# [I 2021-10-31 05:35:17,232] A new study created ...
# [I 2021-10-31 05:35:17,238] Trial 0 finished with value: ...
# [I 2021-10-31 05:35:17,245] Trial 1 finished with value: ...
# ...
.. testoutput::
:hide:
20
20
Returns:
Logging level, e.g., ``optuna.logging.DEBUG`` and ``optuna.logging.INFO``.
.. note::
Optuna has following logging levels:
- ``optuna.logging.CRITICAL``, ``optuna.logging.FATAL``
- ``optuna.logging.ERROR``
- ``optuna.logging.WARNING``, ``optuna.logging.WARN``
- ``optuna.logging.INFO``
- ``optuna.logging.DEBUG``
"""
_configure_library_root_logger()
return _get_library_root_logger().getEffectiveLevel()
[docs]def set_verbosity(verbosity: int) -> None:
"""Set the level for the Optuna's root logger.
Example:
Set the logging level ``optuna.logging.WARNING``.
.. testsetup::
def objective(trial):
x = trial.suggest_int("x", -10, 10)
return x**2
.. testcode::
import optuna
# There are INFO level logs.
study = optuna.create_study()
study.optimize(objective, n_trials=10)
# [I 2021-10-31 02:59:35,088] Trial 0 finished with value: 16.0 ...
# [I 2021-10-31 02:59:35,091] Trial 1 finished with value: 1.0 ...
# [I 2021-10-31 02:59:35,096] Trial 2 finished with value: 1.0 ...
# Setting the logging level WARNING, the INFO logs are suppressed.
optuna.logging.set_verbosity(optuna.logging.WARNING)
study.optimize(objective, n_trials=10)
.. testcleanup::
optuna.logging.set_verbosity(optuna.logging.INFO)
Args:
verbosity:
Logging level, e.g., ``optuna.logging.DEBUG`` and ``optuna.logging.INFO``.
.. note::
Optuna has following logging levels:
- ``optuna.logging.CRITICAL``, ``optuna.logging.FATAL``
- ``optuna.logging.ERROR``
- ``optuna.logging.WARNING``, ``optuna.logging.WARN``
- ``optuna.logging.INFO``
- ``optuna.logging.DEBUG``
"""
_configure_library_root_logger()
_get_library_root_logger().setLevel(verbosity)
[docs]def disable_default_handler() -> None:
"""Disable the default handler of the Optuna's root logger.
Example:
Stop and then resume logging to :obj:`sys.stderr`.
.. testsetup::
def objective(trial):
x = trial.suggest_float("x", -100, 100)
y = trial.suggest_categorical("y", [-1, 0, 1])
return x**2 + y
.. testcode::
import optuna
study = optuna.create_study()
# There are no logs in sys.stderr.
optuna.logging.disable_default_handler()
study.optimize(objective, n_trials=10)
# There are logs in sys.stderr.
optuna.logging.enable_default_handler()
study.optimize(objective, n_trials=10)
# [I 2020-02-23 17:00:54,314] Trial 10 finished with value: ...
# [I 2020-02-23 17:00:54,356] Trial 11 finished with value: ...
# ...
"""
_configure_library_root_logger()
assert _default_handler is not None
_get_library_root_logger().removeHandler(_default_handler)
[docs]def enable_default_handler() -> None:
"""Enable the default handler of the Optuna's root logger.
Please refer to the example shown in :func:`~optuna.logging.disable_default_handler()`.
"""
_configure_library_root_logger()
assert _default_handler is not None
_get_library_root_logger().addHandler(_default_handler)
[docs]def disable_propagation() -> None:
"""Disable propagation of the library log outputs.
Note that log propagation is disabled by default. You only need to use this function
to stop log propagation when you use :func:`~optuna.logging.enable_propogation()`.
Example:
Stop propagating logs to the root logger on the second optimize call.
.. testsetup::
def objective(trial):
x = trial.suggest_float("x", -100, 100)
y = trial.suggest_categorical("y", [-1, 0, 1])
return x**2 + y
.. testcode::
import optuna
import logging
optuna.logging.disable_default_handler() # Disable the default handler.
logger = logging.getLogger()
logger.setLevel(logging.INFO) # Setup the root logger.
logger.addHandler(logging.FileHandler("foo.log", mode="w"))
optuna.logging.enable_propagation() # Propagate logs to the root logger.
study = optuna.create_study()
logger.info("Logs from first optimize call") # The logs are saved in the logs file.
study.optimize(objective, n_trials=10)
optuna.logging.disable_propagation() # Stop propogating logs to the root logger.
logger.info("Logs from second optimize call")
# The new logs for second optimize call are not saved.
study.optimize(objective, n_trials=10)
with open("foo.log") as f:
assert f.readline().startswith("A new study created")
assert f.readline() == "Logs from first optimize call\\n"
# Check for logs after second optimize call.
assert f.read().split("Logs from second optimize call\\n")[-1] == ""
"""
_configure_library_root_logger()
_get_library_root_logger().propagate = False
[docs]def enable_propagation() -> None:
"""Enable propagation of the library log outputs.
Please disable the Optuna's default handler to prevent double logging if the root logger has
been configured.
Example:
Propagate all log output to the root logger in order to save them to the file.
.. testsetup::
def objective(trial):
x = trial.suggest_float("x", -100, 100)
y = trial.suggest_categorical("y", [-1, 0, 1])
return x**2 + y
.. testcode::
import optuna
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO) # Setup the root logger.
logger.addHandler(logging.FileHandler("foo.log", mode="w"))
optuna.logging.enable_propagation() # Propagate logs to the root logger.
optuna.logging.disable_default_handler() # Stop showing logs in sys.stderr.
study = optuna.create_study()
logger.info("Start optimization.")
study.optimize(objective, n_trials=10)
with open("foo.log") as f:
assert f.readline().startswith("A new study created")
assert f.readline() == "Start optimization.\\n"
"""
_configure_library_root_logger()
_get_library_root_logger().propagate = True