mirror of
https://github.com/iKarith/cppo-ng.git
synced 2024-06-15 05:29:28 +00:00
894225d1fa
The actual logging configuration belongs in the application, not a module. In a module, it's always going to do what the module says to do. And that's fine for cppo which is a script that works the way it does, but we have bigger plans for this code. It's now in the cppo module. We've stopped using log from blocksfree.logging, favoring LOG instead, so we have removed it.
108 lines
4.0 KiB
Python
108 lines
4.0 KiB
Python
# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=python:
|
|
|
|
# Copyright (C) 2017 T. Joseph Carter
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License as published by the
|
|
# Free Software Foundation; either version 2 of the License, or (at your
|
|
# option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
# for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
"""BlocksFree LoggingAdapter using str.format and textwrap.dedent
|
|
|
|
Traditionally Python has used a % operator on strings to perform a somewhat
|
|
printf-like string formatting operation. It has limitations and str.format was
|
|
made to replace it. The old way isn't deprecated yet, and it won't be removed
|
|
any time soon, but str.format is how new code should work.
|
|
|
|
The issue is that Python's logging module is used by old and new code alike,
|
|
and so calls to the basic logger require the use of %-style format strings in
|
|
order to work with new and old code alike, forcing you to use the less flexible
|
|
"old way".
|
|
|
|
There isn't a perfectly clean solution to this--either you need ugliness in
|
|
each logging call, or you need a bit different ugliness up front to hide the
|
|
mess.
|
|
|
|
Details are at the bottom of this section of the Logging Cookbook:
|
|
|
|
https://docs.python.org/howto/logging-cookbook.html\
|
|
#use-of-alternative-formatting-styles
|
|
|
|
The next issue was that multi-line strings either break code indentation flow,
|
|
or they have to deal with indentation. If you don't have a special case for
|
|
the first line, textwrap.dedent works great for that. In order to avoid the
|
|
special case, just use a line continuation immediately after your opening
|
|
quotes. Another imperfect solution, but it does the job.
|
|
"""
|
|
|
|
import textwrap
|
|
import logging
|
|
# pylint: disable=unused-import
|
|
from logging import (
|
|
CRITICAL, DEBUG, ERROR, FATAL, INFO, WARNING,
|
|
Formatter,
|
|
StreamHandler
|
|
) # For export
|
|
# pylint: enable=unused-import
|
|
from typing import List, Dict
|
|
|
|
# pylint: disable=too-few-public-methods,missing-docstring
|
|
class Message(object):
|
|
def __init__(self, fmt: str, args: List) -> None:
|
|
self.fmt = fmt
|
|
self.args = args
|
|
|
|
def __str__(self) -> str:
|
|
return self.fmt.format(*self.args)
|
|
# pylint: enable=too-few-public-methods,missing-docstring
|
|
|
|
class StyleAdapter(logging.LoggerAdapter):
|
|
"""Return a LoggerAdapter that uses str.format expansions in log messages
|
|
|
|
StyleAdapter wraps the standard logger (e.g. logging.getLogger) so that it
|
|
appears to take str.format strings rather than the classic str % tuple
|
|
strings.
|
|
|
|
Args:
|
|
logger: A logging.Logger instance/logging channel
|
|
extra: A context object (see the Python logging cookbook)
|
|
"""
|
|
|
|
def __init__(self, logger: logging.Logger, extra=None) -> None:
|
|
super(StyleAdapter, self).__init__(logger, extra or {})
|
|
|
|
def log(self, level: int, msg: str, *args: List, **kwargs: Dict) -> None:
|
|
"""Logs msg.format(*args) at the given level
|
|
|
|
Effectively functions as if we were subclassing logging.Logger's log
|
|
method to change arg convention from msg % args to msg.format(*args).
|
|
See the documentation for the standard logging module for more info.
|
|
|
|
Additionally can perform textwrap.dedent() on msg before logging if
|
|
dedent=True.
|
|
|
|
Args:
|
|
level: Integer logging level
|
|
msg: A log message in the form of a str.format format string
|
|
dedent: Whether to dedent format string
|
|
args/kwargs: Positional and keyword arguments passed to _log
|
|
"""
|
|
if self.isEnabledFor(level):
|
|
if kwargs.get('dedent', False):
|
|
msg = textwrap.dedent(msg)
|
|
msg, kwargs = self.process(msg, kwargs)
|
|
# pylint: disable=protected-access
|
|
self.logger._log(level, Message(str(msg), args), (), **kwargs)
|
|
# pylint: enable=protected-access
|
|
|
|
LOG = StyleAdapter(logging.getLogger('blocksfree'))
|