Skip to content

Commit 413781c

Browse files
committed
Use rich library for logging
1 parent 141bc8d commit 413781c

12 files changed

+78
-132
lines changed

beets/autotag/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from .match import Proposal, current_metadata, tag_album, tag_item # noqa
3232

3333
# Global logger.
34-
log = logging.getLogger("beets")
34+
log = logging.getLogger(__name__)
3535

3636
# Metadata fields that are already hardcoded, or where the tag name changes.
3737
SPECIAL_FIELDS = {

beets/autotag/hooks.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747

4848
JSONDict = Dict[str, Any]
4949

50-
log = logging.getLogger("beets")
50+
log = logging.getLogger(__name__)
5151

5252

5353
# Classes used to represent candidate options.

beets/autotag/match.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
VA_ARTISTS = ("", "various artists", "various", "va", "unknown")
5656

5757
# Global logger.
58-
log = logging.getLogger("beets")
58+
log = logging.getLogger(__name__)
5959

6060

6161
# Recommendation enumeration.

beets/autotag/mb.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
# The above copyright notice and this permission notice shall be
1313
# included in all copies or substantial portions of the Software.
1414

15-
"""Searches for albums in the MusicBrainz database.
16-
"""
15+
"""Searches for albums in the MusicBrainz database."""
16+
1717
from __future__ import annotations
1818

1919
import re
@@ -70,7 +70,7 @@ def get_message(self):
7070
)
7171

7272

73-
log = logging.getLogger("beets")
73+
log = logging.getLogger(__name__)
7474

7575
RELEASE_INCLUDES = [
7676
"artists",

beets/importer.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
]
7272

7373
# Global logger.
74-
log = logging.getLogger("beets")
74+
log = logging.getLogger(__name__)
7575

7676

7777
class ImportAbort(Exception):

beets/library.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
# `memoryview` tells it that we actually mean non-text data.
4444
BLOB_TYPE = memoryview
4545

46-
log = logging.getLogger("beets")
46+
log = logging.getLogger(__name__)
4747

4848

4949
# Library-specific query types.

beets/logging.py

+7-46
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@
2020
calls (`debug`, `info`, etc).
2121
"""
2222

23-
2423
import logging
25-
import sys
2624
import threading
2725
from copy import copy
2826

@@ -47,7 +45,7 @@ def logsafe(val):
4745
return val
4846

4947

50-
class StrFormatLogger(logging.Logger):
48+
class StrFormatLogRecord(logging.LogRecord):
5149
"""A version of `Logger` that uses `str.format`-style formatting
5250
instead of %-style formatting and supports keyword arguments.
5351
@@ -59,47 +57,9 @@ class StrFormatLogger(logging.Logger):
5957
achieve this with less code.
6058
"""
6159

62-
class _LogMessage:
63-
def __init__(self, msg, args, kwargs):
64-
self.msg = msg
65-
self.args = args
66-
self.kwargs = kwargs
67-
68-
def __str__(self):
69-
args = [logsafe(a) for a in self.args]
70-
kwargs = {k: logsafe(v) for (k, v) in self.kwargs.items()}
71-
return self.msg.format(*args, **kwargs)
72-
73-
def _log(
74-
self,
75-
level,
76-
msg,
77-
args,
78-
exc_info=None,
79-
extra=None,
80-
stack_info=False,
81-
**kwargs,
82-
):
83-
"""Log msg.format(*args, **kwargs)"""
84-
m = self._LogMessage(msg, args, kwargs)
85-
86-
stacklevel = kwargs.pop("stacklevel", 1)
87-
if sys.version_info >= (3, 8):
88-
stacklevel = {"stacklevel": stacklevel}
89-
else:
90-
# Simply ignore this when not supported by current Python version.
91-
# Can be dropped when we remove support for Python 3.7.
92-
stacklevel = {}
93-
94-
return super()._log(
95-
level,
96-
m,
97-
(),
98-
exc_info=exc_info,
99-
extra=extra,
100-
stack_info=stack_info,
101-
**stacklevel,
102-
)
60+
def getMessage(self):
61+
args = [logsafe(a) for a in self.args]
62+
return self.msg.format(*args)
10363

10464

10565
class ThreadLocalLevelLogger(logging.Logger):
@@ -130,12 +90,13 @@ def set_global_level(self, level):
13090
self.setLevel(level)
13191

13292

133-
class BeetsLogger(ThreadLocalLevelLogger, StrFormatLogger):
93+
class BeetsLogger(ThreadLocalLevelLogger):
13494
pass
13595

13696

13797
my_manager = copy(logging.Logger.manager)
138-
my_manager.loggerClass = BeetsLogger
98+
my_manager.setLoggerClass(BeetsLogger)
99+
logging.setLogRecordFactory(StrFormatLogRecord)
139100

140101

141102
# Act like the stdlib logging module by re-exporting its namespace.

beets/plugins.py

+1-20
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
LASTFM_KEY = "2dc3914abf35f0d9c92d97d8f8e42b43"
3434

3535
# Global logger.
36-
log = logging.getLogger("beets")
36+
log = logging.getLogger(__name__)
3737

3838

3939
class PluginConflictException(Exception):
@@ -44,23 +44,6 @@ class PluginConflictException(Exception):
4444
"""
4545

4646

47-
class PluginLogFilter(logging.Filter):
48-
"""A logging filter that identifies the plugin that emitted a log
49-
message.
50-
"""
51-
52-
def __init__(self, plugin):
53-
self.prefix = f"{plugin.name}: "
54-
55-
def filter(self, record):
56-
if hasattr(record.msg, "msg") and isinstance(record.msg.msg, str):
57-
# A _LogMessage from our hacked-up Logging replacement.
58-
record.msg.msg = self.prefix + record.msg.msg
59-
elif isinstance(record.msg, str):
60-
record.msg = self.prefix + record.msg
61-
return True
62-
63-
6447
# Managing the plugins themselves.
6548

6649

@@ -85,8 +68,6 @@ def __init__(self, name=None):
8568

8669
self._log = log.getChild(self.name)
8770
self._log.setLevel(logging.NOTSET) # Use `beets` logger level.
88-
if not any(isinstance(f, PluginLogFilter) for f in self._log.filters):
89-
self._log.addFilter(PluginLogFilter(self))
9071

9172
def commands(self):
9273
"""Should return a list of beets.ui.Subcommand objects for

beets/ui/__init__.py

+32-14
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
CLI commands are implemented in the ui.commands module.
1818
"""
1919

20-
2120
import errno
2221
import optparse
2322
import os.path
@@ -31,6 +30,8 @@
3130

3231
import confuse
3332
from rich_tables.utils import diff, make_console
33+
from rich.logging import RichHandler
34+
from rich.traceback import install
3435

3536
from beets import config, library, logging, plugins, util
3637
from beets.autotag import mb
@@ -50,12 +51,31 @@
5051
else:
5152
colorama.init()
5253

53-
5454
log = logging.getLogger("beets")
55+
5556
if not log.handlers:
56-
log.addHandler(logging.StreamHandler())
57+
handler = RichHandler(
58+
show_path=False,
59+
show_level=True,
60+
omit_repeated_times=False,
61+
rich_tracebacks=True,
62+
tracebacks_show_locals=True,
63+
tracebacks_width=console.width,
64+
tracebacks_extra_lines=1,
65+
keywords=["Sending event", "import"],
66+
markup=True,
67+
)
68+
handler.setFormatter(
69+
logging.Formatter(
70+
"[b grey42]{name:<20}[/] {message}", datefmt="%T", style="{"
71+
)
72+
)
73+
log.addHandler(handler)
74+
5775
log.propagate = False # Don't propagate to root handler.
5876

77+
install(console=console, show_locals=True)
78+
5979

6080
PF_KEY_QUERIES = {
6181
"comp": "comp:true",
@@ -122,14 +142,14 @@ def print_(*strings, **kwargs):
122142
(it defaults to a newline).
123143
"""
124144
if not strings:
125-
strings = ['']
145+
strings = [""]
126146

127147
try:
128148
for string in strings:
129149
if isinstance(string, str):
130150
console.print(string)
131151
else:
132-
console.print(string, end='\n')
152+
console.print(string, end="\n")
133153
except:
134154
console.print_exception(show_locals=True)
135155

@@ -311,7 +331,7 @@ def input_options(
311331

312332
# Wrap the query text.
313333
# Start prompt with U+279C: Heavy Round-Tipped Rightwards Arrow
314-
prompt = colorize("action", "\u279C ")
334+
prompt = colorize("action", "\u279c ")
315335
line_length = 0
316336
for i, (part, length) in enumerate(
317337
zip(prompt_parts, prompt_part_lengths)
@@ -380,7 +400,7 @@ def input_yn(prompt, require=False):
380400
"yes" unless `require` is `True`, in which case there is no default.
381401
"""
382402
# Start prompt with U+279C: Heavy Round-Tipped Rightwards Arrow
383-
yesno = colorize("action", "\u279C ") + colorize(
403+
yesno = colorize("action", "\u279c ") + colorize(
384404
"action_description", "Enter Y or N:"
385405
)
386406
sel = input_options(("y", "n"), require, prompt, yesno)
@@ -884,8 +904,8 @@ def _field_diff(field, old, old_fmt, new, new_fmt):
884904
return None
885905

886906
# Get formatted values for output.
887-
oldval = old_fmt.get(field, u'')
888-
newval = new_fmt.get(field, u'')
907+
oldval = old_fmt.get(field, "")
908+
newval = new_fmt.get(field, "")
889909

890910
return diff(str(oldval), str(newval))
891911

@@ -1188,9 +1208,7 @@ def __init__(self, *args, **kwargs):
11881208
"""
11891209
# A more helpful default usage.
11901210
if "usage" not in kwargs:
1191-
kwargs[
1192-
"usage"
1193-
] = """
1211+
kwargs["usage"] = """
11941212
%prog COMMAND [ARGS...]
11951213
%prog help COMMAND"""
11961214
kwargs["add_help_option"] = False
@@ -1560,8 +1578,8 @@ def main(args=None):
15601578
raise
15611579
except UserError as exc:
15621580
message = exc.args[0] if exc.args else None
1563-
if 'No matching' in message:
1564-
log.error(u'error: {0}', message)
1581+
if "No matching" in message:
1582+
log.error("error: {0}", message)
15651583
else:
15661584
console.print_exception(extra_lines=4, show_locals=True)
15671585
sys.exit(1)

beets/ui/commands.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
console = Console(force_terminal=True, force_interactive=True)
5555

5656
# Global logger.
57-
log = logging.getLogger("beets")
57+
log = logging.getLogger(__name__)
5858

5959
# The list of default subcommands. This is populated with Subcommand
6060
# objects that can be fed to a SubcommandsOptionParser.

beets/util/artresizer.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
PROXY_URL = "https://images.weserv.nl/"
3232

33-
log = logging.getLogger("beets")
33+
log = logging.getLogger(__name__)
3434

3535

3636
def resize_url(url, maxwidth, quality=0):

0 commit comments

Comments
 (0)