Skip to content

Commit

Permalink
Use the logging module directly instead of home-grown code.
Browse files Browse the repository at this point in the history
This has the advantage of overall less custom code; as well as support
for per-module configuration. This would enable a potential solution for
ultrabug#1479, since in the future
it can allow per-module configuration of log levels.

I expect this to mainly help module creators, allowing them to enable
logging for only their module, while disabling all other messages. It
also is easier to use, since the `logging` module's interface is
generally simpler than `self.py3`.

Here, I've made the decision to keep the message format as close as
possible to the existing log messages.
  • Loading branch information
rlerm committed Jan 31, 2022
1 parent 5e2a3c1 commit 4b2ee49
Showing 1 changed file with 34 additions and 22 deletions.
56 changes: 34 additions & 22 deletions py3status/core.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import logging
import logging.handlers
import pkg_resources
import sys
import time
Expand All @@ -24,6 +26,12 @@

LOG_LEVELS = {"error": LOG_ERR, "warning": LOG_WARNING, "info": LOG_INFO}

LOGGING_LEVELS = {
"error": logging.ERROR,
"warning": logging.WARNING,
"info": logging.INFO,
}

DBUS_LEVELS = {"error": "critical", "warning": "normal", "info": "low"}

CONFIG_SPECIAL_SECTIONS = [
Expand All @@ -40,6 +48,8 @@
ENTRY_POINT_NAME = "py3status"
ENTRY_POINT_KEY = "entry_point"

_logger = logging.getLogger('core')


class Runner(Thread):
"""
Expand Down Expand Up @@ -523,10 +533,30 @@ def load_modules(self, modules_list, user_modules):
msg = f'Loading module "{module}" failed ({err}).'
self.report_exception(msg, level="warning")

def _setup_logging(self):
"""Set up the global logger."""
root = logging.getLogger(name=None)
if self.config.get("debug"):
root.setLevel(logging.DEBUG)
else:
root.setLevel(logging.DEBUG)

log_file = self.config.get("log_file")
if log_file:
handler = logging.FileHandler(log_file, encoding='utf8')
else:
logging.handlers.SysLogHandler()
handler.setFormatter(logging.Formatter(
fmt='%(asctime)s %(levelname)s %(module)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
style='%'))
root.addHandler(handler)

def setup(self):
"""
Setup py3status and spawn i3status/events/modules threads.
"""
self._setup_logging()

# log py3status and python versions
self.log("=" * 8)
Expand Down Expand Up @@ -879,29 +909,11 @@ def notify_update(self, update, urgent=False):
def log(self, msg, level="info"):
"""
log this information to syslog or user provided logfile.
This is soft-deprecated; prefer using the 'logging' module directly in
new code.
"""
if not self.config.get("log_file"):
# If level was given as a str then convert to actual level
level = LOG_LEVELS.get(level, level)
syslog(level, f"{msg}")
else:
# Binary mode so fs encoding setting is not an issue
with self.config["log_file"].open("ab") as f:
log_time = time.strftime("%Y-%m-%d %H:%M:%S")
# nice formatting of data structures using pretty print
if isinstance(msg, (dict, list, set, tuple)):
msg = pformat(msg)
# if multiline then start the data output on a fresh line
# to aid readability.
if "\n" in msg:
msg = "\n" + msg
out = f"{log_time} {level.upper()} {msg}\n"
try:
# Encode unicode strings to bytes
f.write(out.encode("utf-8"))
except (AttributeError, UnicodeDecodeError):
# Write any byte strings straight to log
f.write(out)
_logger.log(LOGGING_LEVELS.get(level, logging.DEBUG), msg)

def create_output_modules(self):
"""
Expand Down

0 comments on commit 4b2ee49

Please sign in to comment.