from __future__ import annotations
import logging
from logging import CRITICAL
from logging import DEBUG
from logging import ERROR
from logging import FATAL
from logging import INFO
from logging import WARN
from logging import WARNING
import os
import sys
import threading
import colorlog
__all__ = [
"CRITICAL",
"DEBUG",
"ERROR",
"FATAL",
"INFO",
"WARN",
"WARNING",
]
_lock: threading.Lock = threading.Lock()
_default_handler: logging.Handler | None = None
def create_default_formatter() -> logging.Formatter:
"""Create a default formatter of log messages.
This function is not supposed to be directly accessed by library users.
"""
header = "[%(levelname)1.1s %(asctime)s]"
message = "%(message)s"
if _color_supported():
return colorlog.ColoredFormatter(
f"%(log_color)s{header}%(reset)s {message}",
)
return logging.Formatter(f"{header} {message}")
def _color_supported() -> bool:
"""Detection of color support."""
# NO_COLOR environment variable:
if os.environ.get("NO_COLOR", None):
return False
if not hasattr(sys.stderr, "isatty") or not sys.stderr.isatty():
return False
else:
return True
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_propagation()`.
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