7 votes

Comment indenter un message multiligne imprimé par un logger python ?

Comportement actuel :

DEBUG:package:123 > message with
multiple lines
foo bar

Comportement recherché :

DEBUG:package:123 > message with
                    multiple lines
                    foo bar

DEBUG:package:123 peuvent avoir des largeurs différentes, de sorte qu'il n'est pas possible d'ajuster le message avant de l'envoyer à l'enregistreur.

5voto

Arvin Points 21

Les réponses existantes ont bien répondu à la question de l'indentation. Mais la nouvelle format n'a pas traité d'autres champs (par ex. exec_info , stack_info ) par rapport à l'original logging.Formatter .

La mise en œuvre ci-dessous est basée sur Réponse de simonzack et réutilise le formateur d'origine pour minimiser les effets secondaires.

class MultiLineFormatter(logging.Formatter):
    """Multi-line formatter."""

    def get_header_length(self, record):
        """Get the header length of a given record."""
        record = copy.copy(record)
        record.msg = ''
        record.exc_info = None
        record.exc_text = None
        record.stack_info = None
        header = super().format(record)
        return len(header)

    def format(self, record):
        """Format a record with added indentation."""
        message = record.msg
        # For now we only indent string typed messages
        # Other message types like list or bytes won't be touched
        if isinstance(message, str):
            msgs = message.splitlines(True)
            if len(msgs) > 1:
                header_len = self.get_header_length(record)
                # Indent lines (except the first line)
                indented_message = msgs[0] + ''.join(map(
                    lambda m: ' ' * header_len + m if m != '\n' else m, msgs[1:]))
                # Use the original formatter since it handles exceptions well
                record.msg = indented_message
                formatted_text = super().format(record)
                # Revert to keep the msg field untouched
                # As other modules may capture the log for further processing
                record.msg = message
                return formatted_text

        return super().format(record)

2voto

Aiven Points 900

On se retrouve avec un formateur personnalisé sans message dans la chaîne fmt :

import textwrap

class Formatter(logging.Formatter):
    def __init__(self):
        super(Formatter, self).__init__(fmt="%(levelname)-8s %(name)20s:%(lineno)-3d > ")

    def format(self, record):
        header = super(Formatter, self).format(record)
        msg = textwrap.indent(record.message, ' ' * len(header)).strip()
        return header + msg

2voto

simonzack Points 2024

Voici la version d'aiven qui est plus moderne et plus flexible.

class MultiLineFormatter(logging.Formatter):
    def format(self, record):
        message = record.msg
        record.msg = ''
        header = super().format(record)
        msg = textwrap.indent(message, ' ' * len(header)).lstrip()
        record.msg = message
        return header + msg

Pour l'utiliser :

formatter = MultiLineFormatter(
    fmt='%(asctime)s %(levelname)-8s %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
)
log_handler = logging.StreamHandler()
log_handler.setFormatter(formatter)

0voto

Manohar Ch Points 1

Modification de la version d'aiven pour qu'elle fonctionne correctement.

class Formatter(logging.Formatter):
    def __init__(self, format_str):
        super(Formatter, self).__init__(fmt=format_str)

    def format(self, record):
        message = record.msg
        record.msg = ''
        header = super(Formatter, self).format(record)
        msg = textwrap.indent(message, ' ' * len(header)).strip()
        record.msg = message
        return header + msg

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X