Coverage for src/ensembl/utils/logging.py: 100%
20 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-06 14:10 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-06 14:10 +0000
1# See the NOTICE file distributed with this work for additional information
2# regarding copyright ownership.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15"""Easy initialisation functionality to set an event logging system.
17Examples:
19 >>> import logging, pathlib
20 >>> from ensembl.utils.logging import init_logging
21 >>> logfile = pathlib.Path("test.log")
22 >>> init_logging("INFO", logfile, "DEBUG")
23 >>> logging.info("This message is written in both stderr and the log file")
24 >>> logging.debug("This message is only written in the log file")
26"""
28from __future__ import annotations
30__all__ = [
31 "LogLevel",
32 "init_logging",
33 "init_logging_with_args",
34]
36import argparse
37import logging
38from typing import Optional, Union
40from ensembl.utils import StrPath
43LogLevel = Union[int, str]
46def init_logging(
47 log_level: LogLevel = "WARNING",
48 log_file: Optional[StrPath] = None,
49 log_file_level: LogLevel = "DEBUG",
50 msg_format: str = "%(asctime)s\t%(levelname)s\t%(message)s",
51 date_format: str = r"%Y-%m-%d_%H:%M:%S",
52) -> None:
53 """Initialises the logging system.
55 By default, all the log messages corresponding to `log_level` (and above) will be printed in the
56 standard error. If `log_file` is provided, all messages of `log_file_level` level (and above) will
57 be written into the provided file.
59 Args:
60 log_level: Minimum logging level for the standard error.
61 log_file: Logging file where to write logging messages besides the standard error.
62 log_file_level: Minimum logging level for the logging file.
63 msg_format: A format string for the logged output as a whole. More information:
64 https://docs.python.org/3/library/logging.html#logrecord-attributes
65 date_format: A format string for the date/time portion of the logged output. More information:
66 https://docs.python.org/3/library/logging.html#logging.Formatter.formatTime
68 """
69 # Configure the basic logging system, setting the root logger to the minimum log level available
70 # to avoid filtering messages in any handler due to "parent delegation". Also close and remove any
71 # existing handlers before setting this configuration.
72 logging.basicConfig(format=msg_format, datefmt=date_format, level="DEBUG", force=True)
73 # Set the correct log level of the new StreamHandler (by default it is set to NOTSET)
74 logging.root.handlers[0].setLevel(log_level)
75 if log_file:
76 # Create the log file handler and add it to the root logger
77 formatter = logging.Formatter(msg_format, datefmt=date_format)
78 file_handler = logging.FileHandler(log_file)
79 file_handler.setLevel(log_file_level)
80 file_handler.setFormatter(formatter)
81 logging.root.addHandler(file_handler)
84def init_logging_with_args(args: argparse.Namespace) -> None:
85 """Processes the Namespace object provided to call `init_logging()` with the correct arguments.
87 Args:
88 args: Namespace populated by an argument parser.
90 """
91 args_dict = vars(args)
92 log_args = {x: args_dict[x] for x in ["log_level", "log_file", "log_file_level"] if x in args_dict}
93 init_logging(**log_args)