import logging
import os
import sys
from datetime import datetime
from edisgo.tools import config as cfg_edisgo
[docs]def setup_logger(
file_name=None,
log_dir=None,
loggers=None,
stream_output=sys.stdout,
debug_message=False,
reset_loggers=False,
):
"""
Setup different loggers with individual logging levels and where to write output.
The following table from python 'Logging Howto' shows you when which logging level
is used.
.. tabularcolumns:: |l|L|
+--------------+---------------------------------------------+
| Level | When it's used |
+==============+=============================================+
| ``DEBUG`` | Detailed information, typically of interest |
| | only when diagnosing problems. |
+--------------+---------------------------------------------+
| ``INFO`` | Confirmation that things are working as |
| | expected. |
+--------------+---------------------------------------------+
| ``WARNING`` | An indication that something unexpected |
| | happened, or indicative of some problem in |
| | the near future (e.g. 'disk space low'). |
| | The software is still working as expected. |
+--------------+---------------------------------------------+
| ``ERROR`` | Due to a more serious problem, the software |
| | has not been able to perform some function. |
+--------------+---------------------------------------------+
| ``CRITICAL`` | A serious error, indicating that the program|
| | itself may be unable to continue running. |
+--------------+---------------------------------------------+
Parameters
----------
file_name : str or None
Specifies file name of file logging information is written to. Possible options
are:
* None (default)
Saves log file with standard name `%Y_%m_%d-%H:%M:%S_edisgo.log`.
* str
Saves log file with the specified file name.
log_dir : str or None
Specifies directory log file is saved to. Possible options are:
* None (default)
Saves log file in current working directory.
* "default"
Saves log file into directory configured in the configs.
* str
Saves log file into the specified directory.
loggers : None or list(dict)
* None
Configuration as shown in the example below is used. Configures root logger
with file and stream level warning and the edisgo logger with file and
stream level debug.
* list(dict)
List of dicts with the logger configuration. Each dictionary must contain
the following keys and corresponding values:
* 'name'
Specifies name of the logger as string, e.g. 'root' or 'edisgo'.
* 'file_level'
Specifies file logging level. Possible options are:
* "debug"
Logs logging messages with logging level logging.DEBUG and above.
* "info"
Logs logging messages with logging level logging.INFO and above.
* "warning"
Logs logging messages with logging level logging.WARNING and above.
* "error"
Logs logging messages with logging level logging.ERROR and above.
* "critical"
Logs logging messages with logging level logging.CRITICAL.
* None
No logging messages are logged.
* 'stream_level'
Specifies stream logging level. Possible options are the same as for
`file_level`.
stream_output : stream
Default sys.stdout is used. sys.stderr is also possible.
debug_message : bool
If True the handlers of every configured logger is printed.
reset_loggers : bool
If True the handlers of all loggers are cleared before configuring the loggers.
Examples
--------
>>> setup_logger(
>>> loggers=[
>>> {"name": "root", "file_level": "warning", "stream_level": "warning"},
>>> {"name": "edisgo", "file_level": "info", "stream_level": "info"}
>>> ]
>>> )
"""
def create_dir(dir_path):
if not os.path.isdir(dir_path):
os.mkdir(dir_path)
def get_default_root_dir():
dir_path = str(cfg_edisgo.get("user_dirs", "root_dir"))
return os.path.join(os.path.expanduser("~"), dir_path)
def create_home_dir():
dir_path = get_default_root_dir()
create_dir(dir_path)
cfg_edisgo.load_config("config_system.cfg")
if file_name is None:
now = datetime.now()
file_name = now.strftime("%Y_%m_%d-%H:%M:%S_edisgo.log")
if log_dir == "default":
create_home_dir()
log_dir = os.path.join(
get_default_root_dir(), cfg_edisgo.get("user_dirs", "log_dir")
)
create_dir(log_dir)
if log_dir is not None:
file_name = os.path.join(log_dir, file_name)
if reset_loggers:
existing_loggers = [logging.getLogger()] # get the root logger
existing_loggers = existing_loggers + [
logging.getLogger(name) for name in logging.root.manager.loggerDict
]
for logger in existing_loggers:
logger.handlers.clear()
loglevel_dict = {
"debug": logging.DEBUG,
"info": logging.INFO,
"warning": logging.WARNING,
"error": logging.ERROR,
"critical": logging.CRITICAL,
None: logging.CRITICAL + 1,
}
file_formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s: %(message)s"
)
stream_formatter = logging.Formatter("%(name)s - %(levelname)s: %(message)s")
if loggers is None:
loggers = [
{"name": "root", "file_level": "warning", "stream_level": "warning"},
{"name": "edisgo", "file_level": "info", "stream_level": "info"},
]
for logger_config in loggers:
logger_name = logger_config["name"]
logger_file_level = loglevel_dict[logger_config["file_level"]]
logger_stream_level = loglevel_dict[logger_config["stream_level"]]
if logger_name == "root":
logger = logging.getLogger()
else:
logger = logging.getLogger(logger_name)
logger.propagate = False
if logger_file_level < logger_stream_level:
logger.setLevel(logger_file_level)
else:
logger.setLevel(logger_stream_level)
if logger_file_level < logging.CRITICAL + 1:
file_handler = logging.FileHandler(file_name)
file_handler.setLevel(logger_file_level)
file_handler.setFormatter(file_formatter)
logger.addHandler(file_handler)
if logger_stream_level < logging.CRITICAL + 1:
console_handler = logging.StreamHandler(stream=stream_output)
console_handler.setLevel(logger_stream_level)
console_handler.setFormatter(stream_formatter)
logger.addHandler(console_handler)
if debug_message:
print(f"Handlers of logger {logger_name}: {logger.handlers}")