簡體   English   中英

python:日志記錄:我們可以向記錄器添加多個過濾器,考慮哪一個

[英]python: logging: can we added multiple filters to the logger and which one is considered

我試圖了解 Python 日志記錄中的多個過濾器(一個在配置中定義,另一個在代碼中定義)是如何工作的。

我正在處理一個 Django 項目,下面是我在 settings.py 中的記錄器配置

我的目標是隨時switch onswitch off記錄器。 因此,使用過濾器,我試圖通過返回 False (0) 來關閉記錄器

1)在開始時關閉記錄器

class StartFilter(object):
    def filter(self, record):
        """
        Determine if the specified record is to be logged.

        Is the specified record to be logged? Returns 0 for no, nonzero for
        yes. If deemed appropriate, the record may be modified in-place.
        """
        return 0

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(funcName)s() %(pathname)s[:%(lineno)s] %(name)s \n%(message)s'
        }
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'formatter': 'verbose',
            'class': 'logging.StreamHandler',
        },
    },
    'filters': {
        'myfilter': {
            '()': StartFilter,
        }
    },
    'loggers': {
        'log_testing': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
            'filters': ['myfilter']
        },
    }
}

我已將過濾器添加到記錄器中。 'filters': ['myfilter']

2)在我希望看到日志記錄的 views.py 文件中打開和關閉記錄器

# to switch on logger
class LoggerGateStart(object):
    def filter(self, record):
        """
        Determine if the specified record is to be logged.

        Is the specified record to be logged? Returns 0 for no, nonzero for
        yes. If deemed appropriate, the record may be modified in-place.
        """
        return 1

# to switch off logger
class LoggerGateStop(object):
    def filter(self, record):
        """
        Determine if the specified record is to be logged.

        Is the specified record to be logged? Returns 0 for no, nonzero for
        yes. If deemed appropriate, the record may be modified in-place.
        """
        return 0

import logging
logger = logging.getLogger("log_testing")


...
logging.debug("Some text Before)  # i dont want this to be logged
...



gatestart = LoggerGateStart()
logger_database.addFilter(gatestart)

...
logging.debug("Some text)  # i want this to be logged
...

gatestop = LoggerGateStop()
logger_database.addFilter(gatestop)

...
logging.debug("Some text after")  # i dont want this to be logged even 
if it exist
...

我發現它不是這樣工作的。 它只考慮 StartFilter,不考慮 LoggerGateStart 或 LoggerGateStop,不打印任何日志到控制台

我怎樣才能做到這一點

我使用的答案基於 Gabriel C 的答案

我的目標是使用 django django.db.backends記錄 sql。 但它的問題在於它會記錄所有的 sql。 我只想在代碼的特定部分或我想查看 sql 的任何地方記錄 sql。 所以下面的方式我可以做到。

在 settings.py 中記錄配置:

# Filter class to stop or start logging for "django.db.backends"
class LoggerGate:
    def __init__(self, state='closed'):
        # We found that the settings.py runs twice and the filters are created twice. So we have to keep only one. So we delete all the previous filters before we create the new one
        import logging
        logger_database = logging.getLogger("django.db.backends")
        try:
            for filter in logger_database.filters:
                logger_database.removeFilter(filter)
        except Exception as e:
            pass
        self.state = state

    def open(self):
        self.state = 'open'

    def close(self):
        self.state = 'closed'

    def filter(self, record):
        """
        Determine if the specified record is to be logged.

        Is the specified record to be logged? Returns 0/False for no, nonzero/True for
        yes. If deemed appropriate, the record may be modified in-place.
        """
        return self.state == 'open'

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'sql': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
        }
    },
    'filters': {
        'myfilter': {
            '()': LoggerGate,
        }
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['sql'],
            'level': 'DEBUG',
            'propagate': False,
            'filters': ['myfilter']
        }
    }
}

然后在views.py中

import logging
logger = logging.getLogger(__name__)
logger_database = logging.getLogger("django.db.backends")

def test1(request):


    logger_database.filters[0].open()
    #Will allow priting of sql satatements from here

    from django import db
    user_set = User.objects.all()

    for user in user_set: # Here sql is executed and is printed to console
        pass
    #Will stop priting of sql satatements after this
    logger_database.filters[0].close()

    from django import db
    user_set = User.objects.all()

    for user in user_set:  # Here sql is executed and is not printed to console
        pass

    now = datetime.datetime.now()
    html = "<html><body>Internal purpose</body></html>"
    return HttpResponse(html)

如果想以格式化和豐富多彩的方式打印 sql,請在 settings.py 中使用它

# SQL formatter to be used for the handler used in logging "django.db.backends"
class SQLFormatter(logging.Formatter):
    def format(self, record):

        # Check if Pygments is available for coloring 
        try:
            import pygments
            from pygments.lexers import SqlLexer
            from pygments.formatters import TerminalTrueColorFormatter
        except ImportError:
            pygments = None

        # Check if sqlparse is available for indentation
        try:
            import sqlparse
        except ImportError:
            sqlparse = None

        # Remove leading and trailing whitespaces
        sql = record.sql.strip()

        if sqlparse:
            # Indent the SQL query
            sql = sqlparse.format(sql, reindent=True)

        if pygments:
            # Highlight the SQL query
            sql = pygments.highlight(
                sql,
                SqlLexer(),
                #TerminalTrueColorFormatter(style='monokai')
                TerminalTrueColorFormatter()
            )

        # Set the record's statement to the formatted query
        record.statement = sql
        return super(SQLFormatter, self).format(record)




# Filter class to stop or start logging for "django.db.backends"
class LoggerGate:
    def __init__(self, state='closed'):
        # We found that the settings.py runs twice and the filters are created twice. So we have to keep only one. So we delete all the previous filters before we create the new one
        import logging
        logger_database = logging.getLogger("django.db.backends")
        try:
            for filter in logger_database.filters:
                logger_database.removeFilter(filter)
        except Exception as e:
            pass
        self.state = state

    def open(self):
        self.state = 'open'

    def close(self):
        self.state = 'closed'

    def filter(self, record):
        """
        Determine if the specified record is to be logged.

        Is the specified record to be logged? Returns 0/False for no, nonzero/True for
        yes. If deemed appropriate, the record may be modified in-place.
        """
        return self.state == 'open'

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'sql': {
            '()': SQLFormatter,
            'format': '[%(duration).3f] %(statement)s',
        }
    },
    'handlers': {
        'sql': {
            'class': 'logging.StreamHandler',
            'formatter': 'sql',
            'level': 'DEBUG',
        }
    },
    'filters': {
        'myfilter': {
            '()': LoggerGate,
        }
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['sql'],
            'level': 'DEBUG',
            'propagate': False,
            'filters': ['myfilter']
        }
    }
}

只創建一個過濾器並使用它的實例來控制是否應該接受日志。

from logging import getLogger

class LoggerGate(object):

    def __init__(self):
        self.started = False

    def start(self):
        self.started = True

    def stop(self):
        self.started = False

    def filter(self, record):
        """
        Determine if the specified record is to be logged.

        Returns True is this LoggerGate is started, False otherwise.
        """
        return self.started


logger_database = getLogger("log_testing")
logger_gate = LoggerGate()
logger_database.addFilter(logger_gate)

logger_database.critical('this is not logged')
logger_gate.start()
logger_database.critical('this is logged')
logger_gate.stop()
logger_database.critical('this is not logged')

Gabriel C 給出了一個很好的解決方案。 再解釋一下, filter是按順序工作的,這意味着記錄會一一傳遞給每個過濾器。 並會停在一個返回零。 因此,當您的StartFilter返回0 ,它將直接刪除所有記錄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM