Skip to content

Problem with Custom Subclass of logging.Formatter #3338

Closed
@Olllom

Description

@Olllom

Hey,

I had problems with a custom logging.Formatter that allows to include styles into the log message via record.args, like

mylogger.info("Red bold text", red, bold)

Sure, this is a slight abuse of record.args, but anyway...

With

log_cli=false
log_level=10

pytest tries to redirect message and arguments to the standard formatter and fails with a lengthy error message (not all arguments converted during string formatting in logging.LogRecord.getMessage()).


>       assert err == expected
E       assert '\x1b[31mtest...yle: Red>,)\n' == '\x1b[31mtest\x1b[39m\n'
E           test
E         - --- Logging error ---
E         - Traceback (most recent call last):
E         -   File "/Users/akraemer/Software/anaconda3/anaconda/lib/python3.6/logging/__init__.py", line 992, in emit
E         -     msg = self.format(record)
E         -   File "/Users/akraemer/Software/anaconda3/anaconda/lib/python3.6/logging/__init__.py", line 838, in format
E         -     return fmt.format(record)
E         -   File "/Users/akraemer/Software/anaconda3/anaconda/lib/python3.6/logging/__init__.py", line 575, in format
E         -     record.message = record.getMessage()
E         -   File "/Users/akraemer/Software/anaconda3/anaconda/lib/python3.6/logging/__init__.py", line 338, in getMessage
E         -     msg = msg % self.args
E         - TypeError: not all arguments converted during string formatting
E         - Call stack:
E        ...

E         -   File "/Users/akraemer/Software/anaconda3/anaconda/lib/python3.6/site-packages/_pytest/logging.py", line 177, in emit
E         -     logging.StreamHandler.emit(self, record)
E         - Message: 'test'
E         - Arguments: (<ANSIStyle: Red>,)


E         -   File "/Users/akraemer/Software/anaconda3/anaconda/lib/python3.6/logging/__init__.py", line 338, in getMessage
E         -     msg = msg % self.args
  • [platform darwin -- Python 3.6.4, pytest-3.4.2, py-1.5.2, pluggy-0.6.0]
  • Minimal example below (plumbum was version 1.6.6, but I don't think it matters)

With

log_cli=false
log_level=100

in the config file, everything works, so it does not bother me too much at the moment. I just wanted to let you know.

Minimal Example:

minex.py

import logging
import copy
from plumbum import colors
from plumbum.colorlib.styles import ANSIStyle

def apply_styles(msg, *styleargs, **kwargs):
    """Format message with styles.
    """
    if styleargs:
        for a in styleargs:
            msg = msg | a
    return msg

class ColorFormatter(logging.Formatter):
    def __init__(self, *args, **kwargs):
        super(ColorFormatter, self).__init__(*args, **kwargs)

    def format(self, record):
        r = copy.copy(record)
        styleargs = [a for a in r.args if isinstance(a, ANSIStyle)]
        otherargs = [a for a in r.args if not isinstance(a, ANSIStyle)]
        r.msg = apply_styles(str(r.msg), *styleargs)
        r.args = otherargs
        return super(ColorFormatter, self).format(r)

def setup_logger():
    logger = logging.getLogger("SomeLogger")
    console_handler = logging.StreamHandler()
    console_formatter = ColorFormatter('%(message)s')
    console_handler.setFormatter(console_formatter)
    logger.setLevel(logging.DEBUG)
    logger.addHandler(console_handler)
    return logger


test_minex.py

import minex
import plumbum
from plumbum.colors import red, bold

def test_color(capsys):
    #print(plumbum.__version__)
    logger = minex.setup_logger()
    logger.warning("test", red, bold)
    out, err = capsys.readouterr()
    expected = ("test" | red | bold) + "\n"
    assert err == expected

Metadata

Metadata

Assignees

No one assigned

    Labels

    plugin: loggingrelated to the logging builtin plugin

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions