Come configurare la registrazione su syslog in Python?


121

Non riesco a capire il loggingmodulo di Python . Le mie esigenze sono molto semplici: voglio solo registrare tutto su syslog. Dopo aver letto la documentazione, mi è venuto in mente questo semplice script di test:

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

Ma questo script non produce alcun record di log in syslog. Cosa c'è che non va?


3
Dove stai controllando i tuoi messaggi syslog? SysLogHandler () emette questi messaggi al socket udp nella porta 514 in localhost.
suzanshakya

Hai assolutamente ragione. E ho visto che "localhost-514" nella documentazione ma non ho pensato che / dev / log dovrebbe essere usato per impostazione predefinita .. Sigh ..
thor

Risposte:


140

Cambia la linea in questo:

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

Questo funziona per me

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
Nota che, come dice il documento , '/var/run/syslog'è la cosa giusta su OS X.
off dal 1

Lifesaver risposta +1
chachan

3
come possiamo identificare questi log in syslog? come possiamo dare il nome di qualsiasi applicazione O qualsiasi tag come syslogtag = django?
Luv33preet

e ricorda di configurare il file /etc/syslog.d/conf e riavvia il servizio syslog / rsyslog
linrongbin

5
@ Luv33preet L'ho testato con (ma non senza) un formattatore simile logging.Formatter(fmt='myscriptname[%(process)d]: %(levelname)s: %(message)s', ...), una condizione rsyslog come $programname == 'myscriptname'funziona.
Peter,

26

Dovresti sempre usare l'host locale per la registrazione, sia in / dev / log che in localhost tramite lo stack TCP. Ciò consente al demone di registrazione del sistema completamente conforme a RFC e ricco di funzionalità di gestire syslog. Ciò elimina la necessità che il demone remoto sia funzionale e fornisce le capacità avanzate dei demoni syslog come rsyslog e syslog-ng per esempio. La stessa filosofia vale per SMTP. Basta consegnarlo al software SMTP locale. In questo caso usa la 'modalità programma' non il demone, ma è la stessa idea. Lascia che sia il software più capace a gestirlo. Sono possibili nuovi tentativi, accodamento, spooling locale, utilizzo di TCP invece di UDP per syslog e così via. Puoi anche [riconfigurare] quei demoni separatamente dal tuo codice come dovrebbe essere.

Salva il codice per la tua applicazione, lascia che altri software facciano il loro lavoro insieme.


2
sollevi un punto giusto. potresti indicare indirizzi e porte comuni usati da vari demoni di registrazione? esiste un meccanismo di rilevamento standard per determinare se il demone è associato o meno a un socket tcp?
init_js

Sono totalmente d'accordo con te.
daks

20

Ho trovato il modulo syslog per rendere abbastanza facile ottenere il comportamento di registrazione di base che descrivi:

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

Ci sono anche altre cose che potresti fare, ma anche solo le prime due righe ti daranno quello che hai chiesto come ho capito.


Mantengo il modulo di registrazione poiché consente di modificare le impostazioni del logger senza influire su tutte le istruzioni. Consente inoltre di modificare il comportamento nel caso in cui si desideri avere diversi tipi di registrazione al momento
chachan

14

Mettendo insieme le cose da qui e da altri luoghi, questo è ciò che ho escogitato che funziona su unbuntu 12.04 e centOS6

Crea un file /etc/rsyslog.d/che termini con .conf e aggiungi il testo seguente

local6.*        /var/log/my-logfile

Riavvia rsyslog, il ricaricamento NON sembra funzionare per i nuovi file di registro. Forse ricarica solo i file di configurazione esistenti?

sudo restart rsyslog

Quindi puoi utilizzare questo programma di test per assicurarti che funzioni effettivamente.

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
Per riavviare rsyslog su centOS7,sudo service rsyslog restart
radtek

12

Aggiungo un piccolo commento in più nel caso in cui aiuti qualcuno perché ho trovato utile questo scambio ma avevo bisogno di questo po 'di informazioni in più per farlo funzionare.

Per accedere a una struttura specifica utilizzando SysLogHandler è necessario specificare il valore della struttura. Supponi ad esempio di aver definito:

local3.* /var/log/mylog

in syslog, allora ti consigliamo di usare:

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

e devi anche avere syslog in ascolto su UDP per usare localhost invece di / dev / log.


3
non è necessario che syslog sia in ascolto su UDP. Il tuo esempio funzionerà perfettamente anche con address = '/ dev / log'.
thor

5
sì, certo, ma con address = ('localhost', 514), il giorno in cui hai un server di log, sostituisci localhost con l'indirizzo del server e hai il log remoto ;-)
Oliver Henriot

5
Da dove viene la facility = 19? perché non è facility = "local3"
boatcoder

4
@ Mark0978 19 è la rappresentazione numerica di local3 come definito da RFC3146 (e successivamente RFC5424)
Andrew Sledge

3
Mi chiedevo anche questo e ho scoperto che i codici delle strutture sono nel sorgente di SysLogHandler
clebio

11

Il tuo syslog.conf è impostato per gestire facility = user?

Puoi impostare la struttura usata dal logger python con l'argomento facility, qualcosa del genere:

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

È necessario specificare qual è il LOG_DAEMONvalore fornito come valore per il facilityparametro.
tzot

4
Sarebbe 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...')

lo script sopra accederà alla struttura LOCAL0 con il nostro "LOG_IDENTIFIER" personalizzato ... puoi usare LOCAL [0-7] per scopi locali.


1
il tuo commento non ha nulla a che fare con la richiesta originale
thor

@thor sarei d'accordo che questo è rilevante. Io vado a intuire che il pacchetto syslog è un po 'più efficiente rispetto alla pura implementazione di Python? (se meno flessibile)
Daniel Santos

7

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

Questo è molto interessante, ma non funziona su python 2.6.6 (RHEL 6.4): Traceback (ultima chiamata più recente): File "syslog_bridge.py", riga 68, in <module> handlers.append (SysLogLibHandler (logFacilityLocalN )) File "syslog_bridge.py", riga 29, in init syslog.openlog (syslog.LOG_PID, self.FACILITY [n]) TypeError: ident string [, logoption [, facility]]
Steve Cohen


3

Ecco il modo yaml dictConfig consigliato per 3.2 e versioni successive.

Nel registro 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

Carica la configurazione usando:

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

Configurato sia syslog che un file diretto. Nota che /dev/logè specifico del sistema operativo.


1

Lo aggiusto sul mio taccuino. Il servizio rsyslog non è stato in ascolto sul servizio socket.

Ho configurato questa riga sotto nel /etc/rsyslog.conffile e ho risolto il problema:

$SystemLogSocketName /dev/log


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.