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?

thor
źródło
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')
dr jimbob
źródło
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.

egrep
źródło
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.

lindes-hw
źródło
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")
boatcoder
źródło
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.

Oliver Henriot
źródło
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)
bstpierre
źródło
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.

San
źródło
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')
luismartingil
źródło
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
Edytowano na podstawie: github.com/luismartingil/scripts/commit/…
luismartingil.
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.

Bruce Edge
źródło
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

Anderson Madureira
źródło