python регистрация с использованием имени файла и номера строки - PullRequest
0 голосов
/ 17 января 2020

Я использую модуль basi c logging python для добавления журнала.

Я решил создать класс журнала следующим образом с именем Log.py:

class Log:
    def __init__(self, path):
        self.LOGGER = logging.getLogger('Open-Capture')
        if self.LOGGER.hasHandlers():
            self.LOGGER.handlers.clear() # Clear the handlers to avoid double logs
        logFile = RotatingFileHandler(path, mode='a', maxBytes=5 * 1024 * 1024,
                            backupCount=2, encoding=None, delay=0)
        formatter = logging.Formatter('[%(threadName)-14s] [%(filename)s:%(lineno)-15s] %(asctime)s %(levelname)s %(message)s', datefmt='%d-%m-%Y %H:%M:%S')
        logFile.setFormatter(formatter)
        self.LOGGER.addHandler(logFile)
        self.LOGGER.setLevel(logging.DEBUG)

    def info(self, msg):
        self.LOGGER.info(msg)

    def error(self, msg):
        self.LOGGER.error(msg)

Как видите, у меня есть %(filename)s:%(lineno) переменные, чтобы добавить больше правдоподобия. Но в моем файле журнала у меня есть Log.py:34 вместо имени файла и номера строки исходного файла, потому что, когда я регистрируюсь, я называю это так:

Log = Log(Config.cfg['GLOBAL']['logfile'])
Log.info('test log')

Есть ли способ иметь исходный файл на моем файл журнала вместо Log.py?

Заранее спасибо

1 Ответ

1 голос
/ 17 января 2020

Да, это возможно, хотя я вполне уверен, что реализация, которую я публикую здесь, не на 100% безопасна, и уверен, что есть лучшая / более элегантная реализация, воспринимайте это как подсказку.

получить имя файла и номер строки вызывающего абонента, вы можете использовать модуль inspect, чтобы добавить эту пользовательскую информацию в ваши журналы, вы можете добавить пользовательскую Filter:

log.py

import logging
from logging.handlers import RotatingFileHandler
from inspect import getframeinfo, stack


class CallerFilter(logging.Filter):
    """ This class adds some context to the log record instance """
    file = ''
    line_n = ''

    def filter(self, record):
        record.file = self.file
        record.line_n = self.line_n
        return True

def caller_reader(f):
    """This wrapper updates the context with the callor infos"""
    def wrapper(self, *args):
        caller = getframeinfo(stack()[1][0])
        self._filter.file = caller.filename
        self._filter.line_n = caller.lineno
        return f(self, *args)
    return wrapper

class Log:

    def __init__(self, path):
        self.LOGGER = logging.getLogger('Open-Capture')
        if self.LOGGER.hasHandlers():
            self.LOGGER.handlers.clear() # Clear the handlers to avoid double logs
        logFile = RotatingFileHandler(path, mode='a', maxBytes=5 * 1024 * 1024,
                            backupCount=2, encoding=None, delay=0)
        formatter = logging.Formatter('[%(threadName)-14s] [%(file)s:%(line_n)-15s] %(asctime)s %(levelname)s %(message)s', datefmt='%d-%m-%Y %H:%M:%S')
        logFile.setFormatter(formatter)
        self.LOGGER.addHandler(logFile)
        # Here we add the Filter, think of it as a context
        self._filter = CallerFilter()
        self.LOGGER.addFilter(self._filter)
        self.LOGGER.setLevel(logging.DEBUG)

    @caller_reader
    def info(self, msg):
        self.LOGGER.info(msg)

    @caller_reader
    def error(self, msg):
        self.LOGGER.error(msg)

script_file.py

from log import Log

log = Log('l.log')
log.info('LOG MESSAGE')
log.error('LOG MESSAGE 2 ')
log.info('LOG MESSAGE 2 ')

вывод:

[MainThread    ] [script_file.py:4              ] 17-01-2020 16:34:36 INFO LOG MESSAGE
[MainThread    ] [script_file.py:5              ] 17-01-2020 16:34:36 ERROR LOG MESSAGE 2
[MainThread    ] [script_file.py:6              ] 17-01-2020 16:34:36 INFO LOG MESSAGE 2
...