¿Cómo configurar el registro en syslog en Python?

121

No puedo entender el loggingmódulo de Python . Mis necesidades son muy simples: solo quiero registrar todo en syslog. Después de leer la documentación, se me ocurrió este sencillo script de prueba:

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

Pero este script no genera ningún registro en syslog. ¿Qué pasa?

Thor
fuente
3
¿Dónde está revisando sus mensajes de syslog? SysLogHandler () emite esos mensajes al socket udp en el puerto 514 en localhost.
suzanshakya
Estás absolutamente en lo correcto. Y he visto que 'localhost-514' en la documentación, pero no he pensado que / dev / log debería usarse por defecto .. Suspiro ..
thor

Respuestas:

140

Cambie la línea a esto:

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

Esto funciona para mi

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
fuente
12
Tenga en cuenta que, como dice el documento , '/var/run/syslog'es lo correcto en OS X.
offby1
Lifesaver answer +1
chachan
3
¿Cómo podemos identificar estos registros en syslog? ¿Podemos dar cualquier nombre de aplicación O cualquier etiqueta como syslogtag = django?
Luv33preet
y recuerde configurar el archivo /etc/syslog.d/conf, y reinicie el servicio syslog / rsyslog
linrongbin
5
@ Luv33preet Lo he probado con (pero no sin) un formateador como logging.Formatter(fmt='myscriptname[%(process)d]: %(levelname)s: %(message)s', ...), una condición rsyslog como $programname == 'myscriptname'funciona.
Peter
26

Usted debe siempre utilizar la máquina local para el registro, ya sea a / dev / log o host local a través de la pila TCP. Esto permite que el demonio de registro del sistema, totalmente compatible con RFC y con funciones, maneje syslog. Esto elimina la necesidad de que el demonio remoto sea funcional y proporciona las capacidades mejoradas de los demonios syslog como rsyslog y syslog-ng, por ejemplo. La misma filosofía se aplica a SMTP. Simplemente entréguelo al software SMTP local. En este caso, use el 'modo de programa', no el demonio, pero es la misma idea. Deje que el software más capaz lo maneje. Es posible reintentar, poner en cola, poner en cola local, usar TCP en lugar de UDP para syslog, etc. También puede [volver a] configurar esos demonios por separado de su código, como debería ser.

Guarde su codificación para su aplicación, deje que otro software haga su trabajo en conjunto.

garza
fuente
2
planteas un punto justo. ¿Podría indicar direcciones y puertos comunes utilizados por varios demonios de registro? ¿Existe un mecanismo de descubrimiento estándar para determinar si el daemon está vinculado a un socket tcp?
init_js
Estoy totalmente de acuerdo contigo.
2018
20

Encontré el módulo syslog para que sea bastante fácil obtener el comportamiento de registro básico que describe:

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

También hay otras cosas que podría hacer, pero incluso las dos primeras líneas le darán lo que ha pedido, según tengo entendido.

lindes-hw
fuente
Conservo el módulo de registro ya que permite cambiar la configuración del registrador sin afectar todas las declaraciones. También permite cambiar el comportamiento en caso de que desee tener diferentes tipos de registro en ese momento
chachan
14

Uniendo las cosas desde aquí y otros lugares, esto es lo que se me ocurrió que funciona en unbuntu 12.04 y centOS6

Cree un archivo /etc/rsyslog.d/que termine en .conf y agregue el siguiente texto

local6.*        /var/log/my-logfile

Reinicie rsyslog, la recarga NO pareció funcionar para los nuevos archivos de registro. ¿Quizás solo recarga archivos conf existentes?

sudo restart rsyslog

Luego, puede usar este programa de prueba para asegurarse de que realmente funcione.

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")
codificador de barco
fuente
1
Para rsyslog reinicio en centOS7,sudo service rsyslog restart
radtek
12

Agrego un pequeño comentario adicional en caso de que ayude a alguien porque encontré este intercambio útil pero necesitaba esta pequeña información adicional para que todo funcione.

Para iniciar sesión en una instalación específica utilizando SysLogHandler, debe especificar el valor de la instalación. Digamos, por ejemplo, que ha definido:

local3.* /var/log/mylog

en syslog, entonces querrás usar:

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

y también necesita tener syslog escuchando en UDP para usar localhost en lugar de / dev / log.

Oliver Henriot
fuente
3
no hay "necesidad" de que syslog escuche en UDP. Su ejemplo también funcionará perfectamente con address = '/ dev / log'.
Thor
5
sí, claro, pero con la dirección = ('localhost', 514), el día que tiene un servidor de registro, reemplaza localhost por la dirección del servidor y tiene un registro remoto ;-)
Oliver Henriot
5
¿De dónde viene la instalación = 19? ¿por qué no es facilidad = "local3"
boatcoder
4
@ Mark0978 19 es la representación numérica de local3 según lo definido por RFC3146 (y posteriormente RFC5424)
Andrew Sledge
3
También me pregunté sobre esto, y descubrí que los códigos de instalación están en la fuente de SysLogHandler
clebio
11

¿Su syslog.conf está configurado para manejar facilidad = usuario?

Puede configurar la instalación utilizada por el registrador de Python con el argumento de instalación, algo como esto:

handler = logging.handlers.SysLogHandler(facility=SysLogHandler.LOG_DAEMON)
bstpierre
fuente
Debe especificar qué es lo LOG_DAEMONque proporciona como valor para el facilityparámetro.
tzot
4
Eso sería 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...')

la secuencia de comandos anterior se registrará en la instalación LOCAL0 con nuestro "LOG_IDENTIFIER" personalizado ... puede utilizar LOCAL [0-7] para fines locales.

San
fuente
1
su comentario no tiene nada que ver con la solicitud original
Thor
@thor estoy de acuerdo en que esto es relevante. Voy a suponer que el paquete syslog es un poco más eficiente que la implementación pura de Python. (si es menos flexible)
Daniel Santos
7

De 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
fuente
Esto es muy interesante, pero no funciona en Python 2.6.6 (RHEL 6.4): Traceback (última llamada más reciente): Archivo "syslog_bridge.py", línea 68, en <module> handlers.append (SysLogLibHandler (logFacilityLocalN )) Archivo "syslog_bridge.py", línea 29, en init syslog.openlog (syslog.LOG_PID, self.FACILITY [n]) TypeError: ident string [, logoption [, installation]]
Steve Cohen
Editado en base a: github.com/luismartingil/scripts/commit/…
luismartingil
3

Aquí está la forma yaml dictConfig recomendada para 3.2 y posteriores.

En 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

Cargue la configuración usando:

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

Configurado tanto syslog como un archivo directo. Tenga en cuenta que /dev/loges específico del sistema operativo.

Bruce Edge
fuente
1

Lo arreglo en mi cuaderno. El servicio rsyslog no escuchó en el servicio de socket.

Configuré esta línea a continuación en el /etc/rsyslog.confarchivo y resolví el problema:

$SystemLogSocketName /dev/log

Anderson Madureira
fuente