Skip to content

Commit 4a82a03

Browse files
committed
logging: make log levels/format configurable
This allows users to prevent the root logger from swallowing logs, for example logs emitted by plugins and dependencies (such as the MusicBrainz API client).
1 parent 0fec858 commit 4a82a03

File tree

2 files changed

+72
-18
lines changed

2 files changed

+72
-18
lines changed

beets/logging.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,9 @@
2222

2323
import threading
2424
from copy import copy
25-
from logging import (
26-
DEBUG,
27-
INFO,
28-
NOTSET,
29-
WARNING,
30-
FileHandler,
31-
Filter,
32-
Handler,
33-
Logger,
34-
NullHandler,
35-
StreamHandler,
36-
)
25+
from logging import (DEBUG, INFO, NOTSET, WARNING, FileHandler, Filter,
26+
Formatter, Handler, Logger, NullHandler, StreamHandler,
27+
getLevelNamesMapping)
3728

3829
__all__ = [
3930
"DEBUG",
@@ -42,11 +33,13 @@
4233
"WARNING",
4334
"FileHandler",
4435
"Filter",
36+
"Formatter",
4537
"Handler",
4638
"Logger",
4739
"NullHandler",
4840
"StreamHandler",
4941
"getLogger",
42+
"getLevelNamesMapping",
5043
]
5144

5245

beets/ui/__init__.py

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import textwrap
3030
import traceback
3131
from difflib import SequenceMatcher
32-
from typing import TYPE_CHECKING, Any, Callable
32+
from typing import TYPE_CHECKING, Any, Callable, OrderedDict, cast
3333

3434
import confuse
3535

@@ -1637,11 +1637,7 @@ def _configure(options):
16371637
overlay_path = None
16381638
config.set_args(options)
16391639

1640-
# Configure the logger.
1641-
if config["verbose"].get(int):
1642-
log.set_global_level(logging.DEBUG)
1643-
else:
1644-
log.set_global_level(logging.INFO)
1640+
_configure_logging()
16451641

16461642
if overlay_path:
16471643
log.debug(
@@ -1661,6 +1657,71 @@ def _configure(options):
16611657
return config
16621658

16631659

1660+
def _configure_logging():
1661+
"""Configure logging levels and handlers."""
1662+
root_logger = logging.getLogger()
1663+
1664+
if config["verbose"].get(int):
1665+
level = logging.DEBUG
1666+
else:
1667+
level = logging.INFO
1668+
1669+
log.set_global_level(level)
1670+
root_logger.setLevel(level)
1671+
1672+
log_format = config["logging"]["format"].get(
1673+
confuse.String(default="{message}")
1674+
)
1675+
date_format = config["logging"]["date_format"].get(
1676+
confuse.String(default="%Y-%m-%d %H:%M:%S")
1677+
)
1678+
1679+
# Remove the `StreamHandler` we added earlier so we can make a new one with
1680+
# the user's format.
1681+
for logger in [log, root_logger]:
1682+
stream_handlers = [
1683+
handler
1684+
for handler in logger.handlers
1685+
if isinstance(handler, logging.StreamHandler)
1686+
]
1687+
for handler in stream_handlers:
1688+
logger.removeHandler(handler)
1689+
1690+
handler = logging.StreamHandler()
1691+
handler.setFormatter(
1692+
logging.Formatter(
1693+
fmt=cast(str, log_format),
1694+
datefmt=cast(str, date_format),
1695+
style="{",
1696+
validate=True,
1697+
)
1698+
)
1699+
logger.addHandler(handler)
1700+
1701+
level_names_mapping = logging.getLevelNamesMapping()
1702+
log_levels = config["logging"]["levels"].get(
1703+
confuse.MappingValues(
1704+
confuse.OneOf(
1705+
allowed=[
1706+
confuse.Integer(),
1707+
confuse.OneOf(allowed=level_names_mapping.keys()),
1708+
]
1709+
)
1710+
)
1711+
)
1712+
1713+
if log_levels:
1714+
for name, level in cast(OrderedDict, log_levels).items():
1715+
name = None if name == "root" else name
1716+
logger = logging.getLogger(name)
1717+
if isinstance(level, int):
1718+
logger.setLevel(level)
1719+
else:
1720+
logger.setLevel(level_names_mapping[level])
1721+
1722+
logging.getLogger("musicbrainzngs.mbxml").setLevel(logging.WARNING)
1723+
1724+
16641725
def _ensure_db_directory_exists(path):
16651726
if path == b":memory:": # in memory db
16661727
return

0 commit comments

Comments
 (0)