Ich habe versucht, einen Formatierer zu entwickeln, der Python-Protokolle in JSON ausgibt

Normalerweise verwende ich hauptsächlich Python, aber strukturelle Daten sind bequemer, wenn eine Plattform zur Protokollsammlung / -analyse mit einem Cloud-Dienst entwickelt wird, nicht wahr? Wenn Sie jedoch den normalen Formatierer von Logging verwenden, bei dem es sich um eine Standard-Python-Bibliothek handelt, müssen Sie ihn einmal in Strukturdaten konvertieren. Es ist nicht gut, eine andere Anwendung nur für die Konvertierung zu erstellen. Daher habe ich einen Formatierer entwickelt, der Protokolle in JSON ausgibt.

Umgebung

--OS (garantierter Betrieb) - MacOS Catalina - Ubuntu 18.04 --Sprache - Python ^3.7

--Paket-Manager - Poetry

Ergebnisse

Der entwickelte Formatierer ist unter homoluctus / json-pyformatter zu finden. Es wird auch auf PyPI-> [json-pyformatter 0.1.0] veröffentlicht (https://pypi.org/project/json-pyformatter/).

wie benutzt man

1. Installation

pip install json-pyformatter

2. Beispiel

Das Feld, das ausgegeben werden kann, ist logrecord-attribute der Standardbibliothek Logging. Die vom entwickelten Formatierer ausgegebenen Standardfelder sind "asctime", "levelname" und "message".

import logging
from json_pyformmatter import JsonFormatter

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
fields = ('levelname', 'filename', 'message')
formatter = JsonFormatter(fields=fields)
handler.setFormatter(formatter)
logger.addHandler(hander)

logger.info('hello')

Wenn dies ausgeführt wird, wird das JSON-Protokoll wie unten gezeigt ausgegeben.

{"levelname": "INFO", "filename": "test_formatter.py", "message": "hello"}

Außerdem ist es einfacher zu erkennen, ob Sie als Argument von JsonFormatter "indent = 2" angeben.

{
  "levelname": "INFO",
  "filename": "test_formatter.py",
  "message": "hello"
}

Natürlich können Sie auch Traceback ausgeben. Da es schwierig ist zu erkennen, ob es sich um eine Zeile handelt, ist sie in einem Array angeordnet.

{
  'asctime': '2019-12-01 13:58:34',
  'levelname': 'ERROR',
  'message': 'error occurred !!',
  'traceback': [
    'Traceback (most rec...ll last):',
    'File "/example/test..._exc_info',
    'raise TypeError(message)',
    'TypeError: error occurred !!'
  ]
}

Erklärung des Quellcodes

Von hier aus werde ich den Quellcode erklären.

Alle Quellcode

Ich werde vorerst den gesamten Quellcode schreiben.

import json
from collections import OrderedDict
from logging import Formatter


class JsonFormatter(Formatter):
    default_fields = ('asctime', 'levelname', 'message')

    def __init__(self, fields=None, datefmt=None, indent=None):
        """
        Args:
            fields (tuple, list)
            datefmt (str)
            indent (str, int)
        """

        self.fields = (
            self.get_or_none(fields, (list, tuple)) or self.default_fields
        )
        # default time format is %Y-%m-%d %H:%M:%S
        self.datefmt = (
            self.get_or_none(datefmt, str) or self.default_time_format
        )
        self._indent = self.get_or_none(indent, (str, int))

    def get_or_none(self, target, types):
        """Check whether target value is expected type.
        If target type does not match expected type, returns None.

        Args:
            target (any)
            types (class, tuple)

        Returns:
            target or None
        """

        if isinstance(target, types):
            return target
        return None

    def getMessage(self, record):
        if isinstance(record.msg, (list, tuple, dict)):
            return record.msg
        return record.getMessage()

    def _format_json(self, record):
        return json.dumps(record, ensure_ascii=False, indent=self._indent)

    def _format(self, record):
        log = OrderedDict()

        try:
            for field in self.fields:
                log[field] = getattr(record, field)
            return log
        except AttributeError as err:
            raise ValueError(f'Formatting field not found in log record {err}')

    def format(self, record):
        record.message = self.getMessage(record)
        record.asctime = self.formatTime(record, self.datefmt)
        formatted_record = self._format(record)
        if record.exc_info:
            if not record.exc_text:
                record.exc_text = self.formatException(record.exc_info)
        if record.exc_text:
            formatted_record['traceback'] = [
                msg.strip() for msg in record.exc_text.strip().split('\n')
            ]
        if record.stack_info:
            formatted_record['stack'] = record.stack_info.strip()

        return self._format_json(formatted_record)

get_or_none Diese Methode wird beim Erstellen einer Instanz verwendet. Wenn dies nicht der erwartete Typ ist, verwenden Sie den Standardwert oder weisen Sie None so zu, wie er ist.

def get_or_none(self, target, types):
    """Check whether target value is expected type.
    If target type does not match expected type, returns None.

    Args:
       target (any)
       types (class, tuple)

    Returns:
        target or None
    """

    if isinstance(target, types):
        return target
    return None

getMessage Diese Methode wird verwendet, um die Nachricht des Arguments von logger.info () abzurufen. Der Rückgabewert dieser getMessage wird im JSON-Feld message festgelegt. Wenn der Instanztyp von record.msg einer von (list, tuple, dict) ist, wird er so zurückgegeben, wie er ist, andernfalls wird der Rückgabewert der getMessage-Methode der Datensatzinstanz zurückgegeben. Auf diese Weise kann das Protokoll als JSON-Array / -Objekt ausgegeben werden, wenn eines von (Liste, Tupel, Diktat) übergeben wird.

def getMessage(self, record):
    if isinstance(record.msg, (list, tuple, dict)):
        return record.msg
    return record.getMessage()

_format_json Diese Methode gibt den Argumentdatensatz als JSON aus.

def _format_json(self, record):
    return json.dumps(record, ensure_ascii=False, indent=self._indent)

_format Eine Methode zum Konvertieren von Datensätzen in ein Python-Wörterbuch. Das vom Benutzer angegebene Feld muss nicht unbedingt im Attribut record enthalten sein, daher handelt es sich um "try-exception". Das Rückgabeprotokoll wird auf "OrderedDict" gesetzt, um die Bestellung zu garantieren.

def _format(self, record):
    log = OrderedDict()

    try:
        for field in self.fields:
            log[field] = getattr(record, field)
        return log
    except AttributeError as err:
        raise ValueError(f'Formatting field not found in log record {err}')

format Diese Methode wird von logging.Handler aufgerufen. Ich glaube nicht, dass Sie Ihren eigenen Formatierer erstellen und das Format der übergeordneten Klasse (logging.Formatter) verwenden werden. Überschreiben Sie diese Methode daher unbedingt. Ich formatiere record.exc_text, um Traceback als Array auszugeben. Nach dem Entfernen zusätzlicher Leerzeichen usw. wird es mit einem Zeilenumbruch geteilt, um ein Array zu erstellen. Schließlich entleere ich das Python-Diktat als JSON.

def format(self, record):
    record.message = self.getMessage(record)
    record.asctime = self.formatTime(record, self.datefmt)
    formatted_record = self._format(record)
    if record.exc_info:
        if not record.exc_text:
            record.exc_text = self.formatException(record.exc_info)
    if record.exc_text:
        formatted_record['traceback'] = [
            msg.strip() for msg in record.exc_text.strip().split('\n')
        ]
    if record.stack_info:
        formatted_record['stack'] = record.stack_info.strip()

    return self._format_json(formatted_record)

Referenzmaterial

Recommended Posts

Ich habe versucht, einen Formatierer zu entwickeln, der Python-Protokolle in JSON ausgibt
Ich habe versucht, einen Pseudo-Pachislot in Python zu implementieren
Ich habe versucht, einen eindimensionalen Zellautomaten in Python zu implementieren
Ich habe versucht, "ein Programm, das doppelte Anweisungen in Python entfernt"
Ich habe versucht "Wie man eine Methode in Python dekoriert"
Ich habe eine Stoppuhr mit tkinter mit Python gemacht
Ich habe versucht, PLSA in Python zu implementieren
Ich habe versucht, Permutation in Python zu implementieren
Ich habe versucht, ADALINE in Python zu implementieren
Ich habe versucht, PPO in Python zu implementieren
[Python] Ein Memo, das ich versucht habe, mit Asyncio zu beginnen
Ich habe versucht, ein missverstandenes Gefangenendilemma in Python zu implementieren
Ein Memo, das ich schnell in Python geschrieben habe
Ich möchte mit Python ein Fenster erstellen
Ich habe versucht, mit Python ein Tippspiel zu spielen
So erstellen Sie eine JSON-Datei in Python
Ich habe versucht, TOPIC MODEL in Python zu implementieren
Ich habe versucht, ein Python 3-Modul in C hinzuzufügen
Eine Geschichte, die nicht funktioniert hat, als ich versucht habe, mich mit dem Python-Anforderungsmodul anzumelden
Ich habe versucht, eine selektive Sortierung in Python zu implementieren
Ich habe versucht, Trumps Kartenspiel in Python zu implementieren
Ich möchte eine Prioritätswarteschlange erstellen, die mit Python (2.7) aktualisiert werden kann.
[Python] Ich habe versucht, eine Shiritori-KI zu erstellen, die den Wortschatz durch Schlachten verbessert
Ich habe versucht, ein scheinbar Windows-Snipper-Tool mit Python zu implementieren
Ich habe versucht, die in Python installierten Pakete grafisch darzustellen
Analysieren Sie eine JSON-Zeichenfolge, die in eine Datei in Python geschrieben wurde
Ich möchte Timeout einfach in Python implementieren
Ich möchte in Python schreiben! (2) Schreiben wir einen Test
Ich möchte eine Datei mit Python zufällig testen
Ich habe versucht, Drakues Poker in Python zu implementieren
Ich möchte mit einem Roboter in Python arbeiten.
Ich habe versucht, GA (genetischer Algorithmus) in Python zu implementieren
Ich habe versucht zusammenzufassen, wie man Pandas von Python benutzt
[Python] Ich habe versucht, Json von Tintenfischring 2 zu bekommen
Wie man in Python entwickelt
[Python + Flasche] Ich habe einen Webdienst veröffentlicht, der die positionierten Tweets von Twitter visualisiert.
Ich habe versucht, API list.csv mit Python aus swagger.yaml zu erstellen
Eine Standardmethode zum Entwickeln und Verteilen von Paketen in Python
So entwickeln Sie in einer virtuellen Python-Umgebung [Memo]
Erstellen Sie den Code, der in Python "A und vorgeben B" ausgibt
Ich habe eine Klasse in Python erstellt und versucht, Enten zu tippen
Ich habe versucht, die Mail-Sendefunktion in Python zu implementieren
Ich möchte eine schöne Ergänzung zu input () in Python hinzufügen
Ich habe versucht, das Blackjack of Trump-Spiel mit Python zu implementieren
Ich habe versucht, Python zu berühren (Installation)
Ich habe ein Skript in Python erstellt, um eine Textdatei für JSON zu konvertieren (für das vscode-Benutzer-Snippet).
[1 Stunde Herausforderung] Ich habe versucht, eine Wahrsagerseite zu erstellen, die für Python zu geeignet ist
Ich habe versucht, "ein Herz, auch wenn es getrennt ist" mithilfe eines genetischen Algorithmus in Python zu automatisieren
Ich habe versucht, einen Generator zu erstellen, der mit Python eine C # -Containerklasse aus CSV generiert
Ich habe auch versucht, die Funktionsmonade und die Zustandsmonade mit dem Generator in Python nachzuahmen
Ich schrieb einen Test in "Ich habe versucht, die Wahrscheinlichkeit eines Bingospiels mit Python zu simulieren".
Ich habe Line Benachrichtigung in Python versucht
[5.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
Ich habe versucht, eine Serverumgebung zu erstellen, die unter Windows 10 ausgeführt wird
Ich möchte einen Platzhalter verwenden, den ich mit Python entfernen möchte