Как настроить ведение журнала в системный журнал в Python?


121

Я не могу разобраться в loggingмодуле Python . Мои потребности очень просты: я просто хочу записывать все в системный журнал. Прочитав документацию, я придумал этот простой тестовый сценарий:

import logging
import logging.handlers

my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)

handler = logging.handlers.SysLogHandler()

my_logger.addHandler(handler)

my_logger.debug('this is debug')
my_logger.critical('this is critical')

Но этот сценарий не производит никаких записей журнала в системном журнале. В чем дело?


3
Где вы проверяете сообщения системного журнала? SysLogHandler () отправляет эти сообщения в сокет udp через порт 514 на localhost.
suzanshakya

Ты совершенно прав. И я видел, что "localhost-514" в документации, но не думал, что / dev / log должен использоваться по умолчанию .. Вздох ..
Тор

Ответы:


140

Измените строку на эту:

handler = SysLogHandler(address='/dev/log')

Это работает для меня

import logging
import logging.handlers

my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)

handler = logging.handlers.SysLogHandler(address = '/dev/log')

my_logger.addHandler(handler)

my_logger.debug('this is debug')
my_logger.critical('this is critical')

12
Обратите внимание, что, как говорится в документе , '/var/run/syslog'это правильная вещь для OS X.
offby1

Lifesaver answer +1
chachan

3
как мы можем идентифицировать эти журналы в системном журнале? например, можем ли мы указать любое имя приложения ИЛИ любой тег, например syslogtag = django?
Luv33preet

и запомните конфигурацию файла /etc/syslog.d/conf и перезапустите службу syslog / rsyslog
linrongbin

5
@ Luv33preet Я тестировал это с (но не без) форматировщиком вроде logging.Formatter(fmt='myscriptname[%(process)d]: %(levelname)s: %(message)s', ...), условие rsyslog вроде $programname == 'myscriptname'работает.
Питер

26

Вы всегда должны использовать локальный хост для ведения журнала, будь то / dev / log или localhost через стек TCP. Это позволяет полностью совместимому с RFC и функциональному демону ведения системного журнала обрабатывать системный журнал. Это устраняет необходимость в работоспособности удаленного демона и обеспечивает расширенные возможности демона syslog, например, rsyslog и syslog-ng. Та же философия применяется к SMTP. Просто передайте его в локальное программное обеспечение SMTP. В этом случае используйте «программный режим», а не демон, но это та же идея. Пусть с этим справится более способное программное обеспечение. Возможны повторные попытки, постановка в очередь, локальная буферизация, использование TCP вместо UDP для системного журнала и т. Д. Вы также можете [перенастроить] эти демоны отдельно от вашего кода, как это должно быть.

Сохраните код для своего приложения, пусть другое программное обеспечение выполняет свою работу согласованно.


2
вы поднимаете справедливый вопрос. не могли бы вы указать общие адреса и порты, используемые различными демонами журналирования? есть ли стандартный механизм обнаружения, чтобы определить, привязан ли демон к tcp-сокету?
init_js

Я полностью согласен с тобой.
daks

20

Я обнаружил, что модуль syslog упрощает получение описанного вами базового поведения ведения журнала:

import syslog
syslog.syslog("This is a test message")
syslog.syslog(syslog.LOG_INFO, "Test message at INFO priority")

Есть и другие вещи, которые вы могли бы сделать, но даже первые две строчки из них дадут вам то, о чем вы просили, насколько я понимаю.


Я сохраняю модуль регистрации, поскольку он позволяет изменять настройки регистратора, не затрагивая все операторы. Также позволяет изменить поведение, если вы хотите одновременно вести разные типы журналов
chachan

14

Собирая вещи здесь и из других мест, я придумал, что работает на unbuntu 12.04 и centOS6.

Создайте файл с расширением /etc/rsyslog.d/.conf и добавьте следующий текст

local6.*        /var/log/my-logfile

Перезагрузка rsyslog, перезагрузка не работает для новых файлов журнала. Может быть, он только перезагружает существующие файлы conf?

sudo restart rsyslog

Затем вы можете использовать эту тестовую программу, чтобы убедиться, что она действительно работает.

import logging, sys
from logging import config

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(module)s P%(process)d T%(thread)d %(message)s'
            },
        },
    'handlers': {
        'stdout': {
            'class': 'logging.StreamHandler',
            'stream': sys.stdout,
            'formatter': 'verbose',
            },
        'sys-logger6': {
            'class': 'logging.handlers.SysLogHandler',
            'address': '/dev/log',
            'facility': "local6",
            'formatter': 'verbose',
            },
        },
    'loggers': {
        'my-logger': {
            'handlers': ['sys-logger6','stdout'],
            'level': logging.DEBUG,
            'propagate': True,
            },
        }
    }

config.dictConfig(LOGGING)


logger = logging.getLogger("my-logger")

logger.debug("Debug")
logger.info("Info")
logger.warn("Warn")
logger.error("Error")
logger.critical("Critical")

1
Чтобы перезапустить rsyslog на CentOS7,sudo service rsyslog restart
radtek

12

Я добавляю небольшой дополнительный комментарий на тот случай, если он кому-то поможет, потому что я нашел этот обмен полезным, но мне нужна была небольшая дополнительная информация, чтобы все заработало.

Чтобы войти в определенное средство с помощью SysLogHandler, вам необходимо указать значение средства. Скажем, например, что вы определили:

local3.* /var/log/mylog

в системном журнале вы захотите использовать:

handler = logging.handlers.SysLogHandler(address = ('localhost',514), facility=19)

и вам также необходимо, чтобы syslog прослушивал UDP, чтобы использовать localhost вместо / dev / log.


3
Нет необходимости в том, чтобы системный журнал прослушивал UDP. Ваш пример также будет отлично работать с адресом = '/ dev / log'.
Thor

5
да, конечно, но с address = ('localhost', 514), в тот день, когда у вас будет сервер журнала, вы замените localhost адресом сервера и получите удаленное ведение журнала ;-)
Оливер Генриот

5
Откуда предприятие = 19? почему это не объект = "local3"
боткодер

4
@ Mark0978 19 - это числовое представление local3, как определено в RFC3146 (и впоследствии в RFC5424)
Эндрю Следж

3
Я подумал об этом тоже, и найти , что коды объекта в источнике для Пайтона SysLogHandler
clebio

11

Настроен ли ваш syslog.conf для обработки объекта property = user?

Вы можете установить средство, используемое регистратором Python, с аргументом объекта, примерно так:

handler = logging.handlers.SysLogHandler(facility=SysLogHandler.LOG_DAEMON)

Вам необходимо указать, что LOG_DAEMONвы указываете в качестве значения facilityпараметра.
tzot

4
Это было бы SysLogHandler.LOG_DAEMON.
Craig Trader

7
import syslog
syslog.openlog(ident="LOG_IDENTIFIER",logoption=syslog.LOG_PID, facility=syslog.LOG_LOCAL0)
syslog.syslog('Log processing initiated...')

приведенный выше сценарий будет регистрироваться в LOCAL0 с нашим пользовательским "LOG_IDENTIFIER" ... вы можете использовать LOCAL [0-7] для локальных целей.


1
Ваш комментарий не имеет ничего общего с исходным запросом
Тор

@thor Согласен, что это актуально. Я собираюсь предположить, что пакет syslog немного более эффективен, чем реализация на чистом Python? (если менее гибок)
Даниэль Сантос

7

Из https://github.com/luismartingil/per.scripts/tree/master/python_syslog

#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
Implements a new handler for the logging module which uses the pure syslog python module.

@author:  Luis Martin Gil
@year: 2013
'''
import logging
import syslog

class SysLogLibHandler(logging.Handler):
    """A logging handler that emits messages to syslog.syslog."""
    FACILITY = [syslog.LOG_LOCAL0,
                syslog.LOG_LOCAL1,
                syslog.LOG_LOCAL2,
                syslog.LOG_LOCAL3,
                syslog.LOG_LOCAL4,
                syslog.LOG_LOCAL5,
                syslog.LOG_LOCAL6,
                syslog.LOG_LOCAL7]
    def __init__(self, n):
        """ Pre. (0 <= n <= 7) """
        try:
            syslog.openlog(logoption=syslog.LOG_PID, facility=self.FACILITY[n])
        except Exception , err:
            try:
                syslog.openlog(syslog.LOG_PID, self.FACILITY[n])
            except Exception, err:
                try:
                    syslog.openlog('my_ident', syslog.LOG_PID, self.FACILITY[n])
                except:
                    raise
        # We got it
        logging.Handler.__init__(self)

    def emit(self, record):
        syslog.syslog(self.format(record))

if __name__ == '__main__':
    """ Lets play with the log class. """
    # Some variables we need
    _id = 'myproj_v2.0'
    logStr = 'debug'
    logFacilityLocalN = 1

    # Defines a logging level and logging format based on a given string key.
    LOG_ATTR = {'debug': (logging.DEBUG,
                          _id + ' %(levelname)-9s %(name)-15s %(threadName)-14s +%(lineno)-4d %(message)s'),
                'info': (logging.INFO,
                         _id + ' %(levelname)-9s %(message)s'),
                'warning': (logging.WARNING,
                            _id + ' %(levelname)-9s %(message)s'),
                'error': (logging.ERROR,
                          _id + ' %(levelname)-9s %(message)s'),
                'critical': (logging.CRITICAL,
                             _id + ' %(levelname)-9s %(message)s')}
    loglevel, logformat = LOG_ATTR[logStr]

    # Configuring the logger
    logger = logging.getLogger()
    logger.setLevel(loglevel)

    # Clearing previous logs
    logger.handlers = []

    # Setting formaters and adding handlers.
    formatter = logging.Formatter(logformat)
    handlers = []
    handlers.append(SysLogLibHandler(logFacilityLocalN))
    for h in handlers:
        h.setFormatter(formatter)
        logger.addHandler(h)

    # Yep!
    logging.debug('test debug')
    logging.info('test info')
    logging.warning('test warning')
    logging.error('test error')
    logging.critical('test critical')

Это очень интересно, но не работает на python 2.6.6 (RHEL 6.4): Traceback (последний вызов последним): файл «syslog_bridge.py», строка 68, в <module> handlers.append (SysLogLibHandler (logFacilityLocalN )) Файл "syslog_bridge.py", строка 29, в init syslog.openlog (syslog.LOG_PID, self.FACILITY [n]) TypeError: identifier string [, logoption [, средство]]
Стив Коэн

Отредактировано на основе: github.com/luismartingil/scripts/commit/…
luismartingil

3

Вот способ yaml dictConfig, рекомендованный для версии 3.2 и новее.

В журнале cfg.yml:

version: 1
disable_existing_loggers: true

formatters:
    default:
        format: "[%(process)d] %(name)s(%(funcName)s:%(lineno)s) - %(levelname)s: %(message)s"

handlers:
    syslog:
        class: logging.handlers.SysLogHandler
        level: DEBUG
        formatter: default
        address: /dev/log
        facility: local0

    rotating_file:
        class: logging.handlers.RotatingFileHandler
        level: DEBUG
        formatter: default
        filename: rotating.log
        maxBytes: 10485760 # 10MB
        backupCount: 20
        encoding: utf8

root:
    level: DEBUG
    handlers: [syslog, rotating_file]
    propogate: yes

loggers:
    main:
        level: DEBUG
        handlers: [syslog, rotating_file]
        propogate: yes

Загрузите конфигурацию, используя:

log_config = yaml.safe_load(open('cfg.yml'))
logging.config.dictConfig(log_config)

Настроил как системный журнал, так и прямой файл. Обратите внимание, что это /dev/logзависит от ОС.


1

Исправляю на блокноте. Служба rsyslog не прослушивает службу сокетов.

Я настроил эту строку ниже в /etc/rsyslog.confфайле и решил проблему:

$SystemLogSocketName /dev/log


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.