Як налаштувати ведення журналу до syslog в Python?


121

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

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')

Але цей скрипт не створює жодних записів журналу в syslog. Що не так?


3
Де ви перевіряєте ваші повідомлення системного журналу? SysLogHandler () посилає ці повідомлення в сокет udp в порту 514 в localhost.
suzanshakya

Ви абсолютно праві. І я бачив, що "localhost-514" в документації, але не думав, що / dev / log слід використовувати за замовчуванням .. Зітхніть ..
thor

Відповіді:


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

Відповідь рятівника +1
чачан

3
як ми можемо ідентифікувати ці журнали в syslog? як ми можемо дати ім’я будь-якої програми АБО будь-який тег, як 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 і функціональний демон системи реєстрації системного журналу для управління системою. Це виключає необхідність віддаленого демона бути функціональним і забезпечує розширені можливості таких системних демонів, як rsyslog і syslog-ng, наприклад. Ця ж філософія стосується і SMTP. Просто передайте його місцевому програмному забезпеченню SMTP. У цьому випадку використовуйте "програмний режим" не демон, але це та сама ідея. Нехай з цим справляється більш здібне програмне забезпечення Стають можливими повторні спроби, черга, локальна спулінг, використання TCP замість UDP для syslog тощо. Ви також можете [повторно] налаштувати ці демони окремо від коду, як це має бути.

Збережіть кодування для вашої програми, нехай інше програмне забезпечення виконує свою роботу узгоджено.


2
ви піднімаєте справедливу точку. Ви могли б вказати загальні адреси та порти, які використовуються різними демонами реєстрації? чи є стандартний механізм виявлення, щоб визначити, чи прив'язується демон до розетки tcp?
init_js

Я повністю з вами згоден.
дакс

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, перезавантаження НЕ здається, працює для нових файлів журналу. Може бути, він лише перезавантажує наявні файли конф?

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

в syslog, тоді ви хочете використовувати:

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

і вам також потрібно мати прослуховування syslog на UDP, щоб використовувати localhost замість / dev / log.


3
немає ніякої "необхідності" в тому, щоб систематичне прослуховування UDP не було. Ваш приклад прекрасно працюватиме і з адресою = '/ dev / log'.
Thor

5
так, звичайно, але з адресою = ('localhost', 514), у день, коли у вас є сервер журналу, ви замінюєте localhost за адресою сервера, і у вас є віддалений журнал ;-)
Олівер Генріот

5
Звідки береться заклад = 19? чому це не об'єкт = "local3"
boatcoder

4
@ Mark0978 19 - числове представлення local3, як визначено RFC3146 (а згодом RFC5424)
Andrew Sledge

3
Я теж задумався про це, і виявив, що коди об'єктів є джерелом для SysLogHandler
clebio

11

Чи налаштовано ваш syslog.conf для обробки об'єкта = користувач?

Ви можете встановити об'єкт, використовуваний реєстратором python, аргументом об'єкта, приблизно таким:

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

Вам потрібно вказати, що саме LOG_DAEMONви надаєте як значення для facilityпараметра.
tzot

4
Це було б SysLogHandler.LOG_DAEMON.
Крейг Трейдер

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

@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: ідентифікаційний рядок [, логотип [, об'єкт]]
Стів Коен

Відредаговано на основі: 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)

Налаштовано як syslog, так і прямий файл. Зауважте, що /dev/logце специфічно для ОС.


1

Я фіксую це на своєму блокноті. Служба rsyslog не слухала служби socket.

Я налаштував цей рядок нижче у /etc/rsyslog.confфайлі та вирішив проблему:

$SystemLogSocketName /dev/log


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.