Jak skonfigurować logowanie do syslog w Pythonie?


121

Nie mogę pojąć loggingmodułu Pythona . Moje potrzeby są bardzo proste: chcę tylko rejestrować wszystko w syslogu. Po przeczytaniu dokumentacji wymyśliłem prosty skrypt testowy:

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

Ale ten skrypt nie tworzy żadnych rekordów dziennika w syslog. Co jest nie tak?


3
Gdzie sprawdzasz swoje wiadomości syslog? SysLogHandler () wysyła te komunikaty do gniazda udp w porcie 514 na hoście lokalnym.
suzanshakya

Masz całkowitą rację. Widziałem w dokumentacji napis „localhost-514”, ale nie pomyślałem, że / dev / log powinien być używany domyślnie .. Ech ...
thor

Odpowiedzi:


140

Zmień wiersz na ten:

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

To działa dla mnie

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
Zauważ, że, jak mówi dokument , '/var/run/syslog'jest
właściwa

Odpowiedź ratownika +1
chachan

3
jak możemy zidentyfikować te dzienniki w syslog? na przykład, czy możemy podać nazwę aplikacji LUB dowolny tag, taki jak syslogtag = django?
Luv33preet

i pamiętaj o skonfigurowaniu pliku /etc/syslog.d/conf i zrestartowaniu usługi syslog / rsyslog
linrongbin

5
@ Luv33preet Przetestowałem to z (ale nie bez) programu formatującego logging.Formatter(fmt='myscriptname[%(process)d]: %(levelname)s: %(message)s', ...), takiego jak warunek rsyslog, taki jak $programname == 'myscriptname'działa.
Peter,

26

Do rejestrowania należy zawsze używać lokalnego hosta, czy to / dev / log, czy localhost przez stos TCP. Pozwala to w pełni zgodnemu z RFC i funkcjonalnemu demonowi rejestrowania systemu obsługiwać syslog. Eliminuje to potrzebę działania zdalnego demona i zapewnia rozszerzone możliwości demonów syslog, takich jak na przykład rsyslog i syslog-ng. Ta sama filozofia dotyczy SMTP. Po prostu przekaż go do lokalnego oprogramowania SMTP. W tym przypadku użyj „trybu programu”, a nie demona, ale to ten sam pomysł. Niech obsłuży to bardziej wydajne oprogramowanie. Ponowne próby, kolejkowanie, buforowanie lokalne, używanie protokołu TCP zamiast UDP dla syslog i tak dalej stają się możliwe. Możesz także [re-] skonfigurować te demony niezależnie od kodu, tak jak powinno.

Zapisz kod swojej aplikacji, pozwól innym oprogramowaniu wykonać swoją pracę w porozumieniu.


2
podnosisz słuszną kwestię. czy możesz wskazać popularne adresy i porty używane przez różne demony rejestrujące? czy istnieje standardowy mechanizm wykrywania, który określa, czy demon jest powiązany z gniazdem TCP?
init_js

Całkowicie się z tobą zgadzam.
daks

20

Znalazłem moduł syslog, który ułatwia uzyskanie podstawowego zachowania logowania, które opisujesz:

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

Są też inne rzeczy, które możesz zrobić, ale nawet pierwsze dwie linijki tego tekstu zapewnią Ci to, o co prosiłeś, tak jak rozumiem.


Zachowuję moduł logowania, ponieważ pozwala on na zmianę ustawień rejestratora bez wpływu na wszystkie instrukcje. Pozwala również na zmianę zachowania w przypadku, gdy chcesz mieć różne typy logowania w tym czasie
chachan

14

Składając rzeczy tutaj i innych miejsc, oto co wymyśliłem, że działa na unbuntu 12.04 i centOS6

Utwórz plik w, /etc/rsyslog.d/który kończy się na .conf i dodaj następujący tekst

local6.*        /var/log/my-logfile

Uruchom ponownie rsyslog, ponowne ładowanie NIE działało dla nowych plików dziennika. Może tylko przeładowuje istniejące pliki konfiguracyjne?

sudo restart rsyslog

Następnie możesz użyć tego programu testowego, aby upewnić się, że faktycznie działa.

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
Aby ponownie uruchomić rsyslog na centOS7,sudo service rsyslog restart
radtek

12

Dodaję trochę dodatkowego komentarza na wypadek, gdyby to komuś pomogło, ponieważ uznałem tę wymianę za przydatną, ale potrzebowałem tej trochę dodatkowej informacji, aby wszystko działało.

Aby zalogować się do określonego obiektu za pomocą SysLogHandler, musisz określić wartość obiektu. Powiedz na przykład, że zdefiniowałeś:

local3.* /var/log/mylog

w syslog, będziesz chciał użyć:

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

a także musisz mieć syslog nasłuchujący na UDP, aby używać localhost zamiast / dev / log.


3
nie ma „potrzeby” nasłuchiwania syslog na UDP. Twój przykład będzie również doskonale działał z address = '/ dev / log'.
thor

5
tak, oczywiście, ale z address = ('localhost', 514), w dniu, w którym masz serwer logów, zastępujesz localhost adresem serwera i masz zdalne logowanie ;-)
Oliver Henriot

5
Skąd pochodzi placówka = 19? dlaczego nie jest to obiekt = "local3"
boatcoder

4
@ Mark0978 19 to numeryczna reprezentacja local3 zgodnie z definicją w RFC3146 (a następnie RFC5424)
Andrew Sledge

3
Też się nad tym zastanawiałem i stwierdziłem, że kody obiektów znajdują się w źródle Pythona SysLogHandler
clebio

11

Czy Twój syslog.conf jest skonfigurowany do obsługi obiektu = użytkownik?

Możesz ustawić narzędzie używane przez program rejestrujący Pythona za pomocą argumentu Facility, coś takiego:

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

Musisz określić, jaką wartość LOG_DAEMONpodajesz jako wartość facilityparametru.
tzot

4
To byłoby 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...')

powyższy skrypt zaloguje się do narzędzia LOCAL0 z naszym niestandardowym "LOG_IDENTIFIER" ... możesz użyć LOCAL [0-7] do celów lokalnych.


1
Twój komentarz nie ma nic wspólnego z pierwotną prośbą
thor

@thor Zgodzę się, że jest to istotne. Idę do odgadnięcia , że pakiet syslog jest nieco bardziej wydajny niż czysta implementacji Pythona? (jeśli mniej elastyczny)
Daniel Santos,

7

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

Jest to bardzo interesujące, ale nie działa na Pythonie 2.6.6 (RHEL 6.4): Traceback (ostatnie wywołanie ostatnie): Plik "syslog_bridge.py", wiersz 68, w <module> handlers.append (SysLogLibHandler (logFacilityLocalN )) Plik „syslog_bridge.py”, wiersz 29, init syslog.openlog (syslog.LOG_PID, self.FACILITY [n]) TypeError: ident string [, logoption [, obiekt]]
Steve Cohen


3

Oto sposób yaml dictConfig zalecany dla wersji 3.2 i nowszych.

W logu 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

Załaduj konfigurację za pomocą:

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

Skonfigurowano zarówno syslog, jak i plik bezpośredni. Zauważ, że /dev/logjest to specyficzne dla systemu operacyjnego.


1

Naprawiam to na moim notebooku. Usługa rsyslog nie nasłuchiwała usługi gniazda.

Konfiguruję tę linię poniżej w /etc/rsyslog.confpliku i rozwiązałem problem:

$SystemLogSocketName /dev/log


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.