feat: replace verbosity flag with log-level flag (#1496)
using a string flag is better when using environement variables.
This commit is contained in:
parent
ba4eeaaff2
commit
40130303dd
|
@ -5,7 +5,7 @@ from typing import Optional
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from .logging import LogLevel, level_from_verbosity, setup_logger
|
from .logging import LogLevel, level_from_name, setup_logger
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
|
@ -26,13 +26,14 @@ class AbstractApp(ABC):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
verbosity: int,
|
log_level: str,
|
||||||
log_filepath: Optional[PathLike] = None,
|
log_filepath: Optional[PathLike] = None,
|
||||||
):
|
):
|
||||||
|
self.log_level = level_from_name(log_level)
|
||||||
|
|
||||||
if log_filepath is not None:
|
if log_filepath is not None:
|
||||||
self.log_filepath = Path(log_filepath)
|
self.log_filepath = Path(log_filepath)
|
||||||
|
|
||||||
self.log_level = level_from_verbosity(verbosity)
|
|
||||||
setup_logger(level=self.log_level, filepath=self.log_filepath)
|
setup_logger(level=self.log_level, filepath=self.log_filepath)
|
||||||
|
|
||||||
logger.info(f"Starting {self.name}...")
|
logger.info(f"Starting {self.name}...")
|
||||||
|
|
|
@ -3,6 +3,7 @@ from typing import Callable
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from .config import DEFAULT_ENV_PREFIX
|
from .config import DEFAULT_ENV_PREFIX
|
||||||
|
from .logging import INFO, LOG_LEVEL_MAP
|
||||||
|
|
||||||
|
|
||||||
def cli_logging_options(func: Callable) -> Callable:
|
def cli_logging_options(func: Callable) -> Callable:
|
||||||
|
@ -10,26 +11,16 @@ def cli_logging_options(func: Callable) -> Callable:
|
||||||
Decorator function to add logging options to a click application.
|
Decorator function to add logging options to a click application.
|
||||||
|
|
||||||
This decorator add the following arguments:
|
This decorator add the following arguments:
|
||||||
- verbosity: int
|
- log_level: str
|
||||||
- log_filepath: Path
|
- log_filepath: Optional[Path]
|
||||||
"""
|
"""
|
||||||
func = click.option(
|
func = click.option(
|
||||||
"-v",
|
"--log-level",
|
||||||
"--verbose",
|
"log_level",
|
||||||
"verbosity",
|
envvar=f"{DEFAULT_ENV_PREFIX}_LOG_LEVEL",
|
||||||
envvar=f"{DEFAULT_ENV_PREFIX}_VERBOSITY",
|
type=click.Choice(list(LOG_LEVEL_MAP.keys())),
|
||||||
count=True,
|
default=INFO.name,
|
||||||
default=0,
|
help="Name of the logging level.",
|
||||||
help="Increase logging verbosity (use -vvv to debug).",
|
|
||||||
)(func)
|
|
||||||
|
|
||||||
func = click.option(
|
|
||||||
"-q",
|
|
||||||
"--quiet",
|
|
||||||
"verbosity",
|
|
||||||
is_flag=True,
|
|
||||||
flag_value=-1,
|
|
||||||
help="Decrease logging verbosity.",
|
|
||||||
)(func)
|
)(func)
|
||||||
|
|
||||||
func = click.option(
|
func = click.option(
|
||||||
|
|
|
@ -26,23 +26,27 @@ INFO = LogLevel(name="info", no=20)
|
||||||
DEBUG = LogLevel(name="debug", no=10)
|
DEBUG = LogLevel(name="debug", no=10)
|
||||||
TRACE = LogLevel(name="trace", no=5)
|
TRACE = LogLevel(name="trace", no=5)
|
||||||
|
|
||||||
|
LOG_LEVEL_MAP = {
|
||||||
|
ERROR.name: ERROR,
|
||||||
|
WARNING.name: WARNING,
|
||||||
|
INFO.name: INFO,
|
||||||
|
DEBUG.name: DEBUG,
|
||||||
|
TRACE.name: TRACE,
|
||||||
|
}
|
||||||
|
|
||||||
def level_from_verbosity(verbosity: int) -> LogLevel:
|
|
||||||
|
def level_from_name(name: str) -> LogLevel:
|
||||||
"""
|
"""
|
||||||
Find logging level, depending on the verbosity requested.
|
Find logging level, depending on the name provided.
|
||||||
|
|
||||||
-q -1 => ERROR
|
:param name: name (one of "error", "warning", "info", "debug", "trace") of the log level
|
||||||
default 0 => WARNING
|
:returns: log level guessed from the name
|
||||||
-v 1 => INFO
|
:raises ValueError: on invalid level name
|
||||||
-vv 2 => DEBUG
|
|
||||||
-vvv 3 => TRACE
|
|
||||||
|
|
||||||
:param verbosity: verbosity (between -1 and 3) of the logger
|
|
||||||
:returns: log level guessed from the verbosity
|
|
||||||
"""
|
"""
|
||||||
if verbosity < 0:
|
name = name.lower()
|
||||||
return ERROR
|
if name not in LOG_LEVEL_MAP:
|
||||||
return [WARNING, INFO, DEBUG, TRACE][min(3, verbosity)]
|
raise ValueError(f"invalid level name '{name}'")
|
||||||
|
return LOG_LEVEL_MAP[name]
|
||||||
|
|
||||||
|
|
||||||
def setup_logger(
|
def setup_logger(
|
||||||
|
|
|
@ -7,29 +7,32 @@ from libretime_shared.logging import (
|
||||||
DEBUG,
|
DEBUG,
|
||||||
INFO,
|
INFO,
|
||||||
create_task_logger,
|
create_task_logger,
|
||||||
level_from_verbosity,
|
level_from_name,
|
||||||
setup_logger,
|
setup_logger,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"verbosity,level_name,level_no",
|
"name,level_name,level_no",
|
||||||
[
|
[
|
||||||
(-100, "error", 40),
|
("error", "error", 40),
|
||||||
(-1, "error", 40),
|
("warning", "warning", 30),
|
||||||
(0, "warning", 30),
|
("info", "info", 20),
|
||||||
(1, "info", 20),
|
("debug", "debug", 10),
|
||||||
(2, "debug", 10),
|
("trace", "trace", 5),
|
||||||
(3, "trace", 5),
|
|
||||||
(100, "trace", 5),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_level_from_verbosity(verbosity, level_name, level_no):
|
def test_level_from_name(name, level_name, level_no):
|
||||||
level = level_from_verbosity(verbosity)
|
level = level_from_name(name)
|
||||||
assert level.name == level_name
|
assert level.name == level_name
|
||||||
assert level.no == level_no
|
assert level.no == level_no
|
||||||
|
|
||||||
|
|
||||||
|
def test_level_from_name_invalid():
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
level_from_name("invalid")
|
||||||
|
|
||||||
|
|
||||||
def test_setup_logger(tmp_path: Path):
|
def test_setup_logger(tmp_path: Path):
|
||||||
log_filepath = tmp_path / "test.log"
|
log_filepath = tmp_path / "test.log"
|
||||||
extra_log_filepath = tmp_path / "extra.log"
|
extra_log_filepath = tmp_path / "extra.log"
|
||||||
|
|
Loading…
Reference in New Issue