Como configurar o log para syslog no Python?

121

Não consigo entender o loggingmódulo do Python . Minhas necessidades são muito simples: eu só quero registrar tudo no syslog. Depois de ler a documentação, criei este script de teste simples:

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

Mas esse script não produz nenhum registro de log no syslog. O que há de errado?

thor
fonte
3
Onde você está verificando suas mensagens syslog? SysLogHandler () emite essas mensagens para o soquete UDP na porta 514 no host local.
suzanshakya
Você está absolutamente correto. E eu vi que 'localhost-514' na documentação, mas não pensei que / dev / log é deve ser usado por padrão .. Sigh ..
thor

Respostas:

140

Mude a linha para isto:

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

Isso funciona para mim

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
fonte
12
Note que, como o doc diz, '/var/run/syslog'é a coisa certa no OS X.
offby1
Resposta de
lifesaver
3
como podemos identificar esses logs no syslog? como podemos dar o nome de qualquer aplicativo ou qualquer tag como syslogtag = django?
Luv33preet
e lembre-config arquivo /etc/syslog.d/conf, e reiniciar syslog / rsyslog serviço
linrongbin
5
@ Luv33preet Eu testei isso com (mas não sem) um formatador como logging.Formatter(fmt='myscriptname[%(process)d]: %(levelname)s: %(message)s', ...), uma condição rsyslog como $programname == 'myscriptname'funciona.
Peter Peter
26

Você sempre deve usar o host local para o log, seja para / dev / log ou localhost através da pilha TCP. Isso permite que o daemon de log do sistema totalmente compatível com RFC e com recursos processe o syslog. Isso elimina a necessidade do daemon remoto ser funcional e fornece os recursos aprimorados dos daemon syslog, como rsyslog e syslog-ng, por exemplo. A mesma filosofia vale para o SMTP. Basta entregá-lo ao software SMTP local. Nesse caso, use o 'modo de programa' não o daemon, mas é a mesma ideia. Deixe o software mais capaz lidar com isso. Repetir, enfileirar, colocar em spool local, usando TCP em vez de UDP para syslog e assim por diante tornam-se possíveis. Você também pode [re] configurar esses daemons separadamente do seu código, como deveria ser.

Salve sua codificação para a sua aplicação, deixe que outros softwares façam seu trabalho em conjunto.

egrep
fonte
2
você levanta um ponto justo. você poderia indicar endereços e portas comuns usados ​​por vários daemons de log? existe um mecanismo de descoberta padrão para determinar se o daemon está ou não vinculado a um soquete tcp?
init_js 26/02
Eu concordo totalmente com você.
Dakid #
20

Encontrei o módulo syslog para facilitar o comportamento básico de registro que você descreve:

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

Também há outras coisas que você poderia fazer, mas mesmo as duas primeiras linhas receberão o que você pediu, como eu o entendo.

lindes-hw
fonte
Eu mantenho o módulo de registro, pois ele permite alterar as configurações do registrador sem afetar todas as instruções. Também permite alterar o comportamento no caso de você querer ter diferentes tipos de exploração madeireira no momento
chachan
14

Reunindo as coisas daqui e de outros lugares, é isso que eu criei que funciona no unbuntu 12.04 e centOS6

Crie um arquivo /etc/rsyslog.d/que termine em .conf e adicione o seguinte texto

local6.*        /var/log/my-logfile

Reinicie rsyslog, recarregar NÃO parecia funcionar para os novos arquivos de log. Talvez ele apenas recarregue os arquivos conf existentes?

sudo restart rsyslog

Em seguida, você pode usar este programa de teste para garantir que ele 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")
boatcoder
fonte
1
Para reiniciar o rsyslog no centOS7,sudo service rsyslog restart
radtek
12

Acrescento um pequeno comentário extra, caso ajude alguém, porque achei essa troca útil, mas precisava desse pouco de informação extra para fazer tudo funcionar.

Para efetuar logon em um recurso específico usando o SysLogHandler, é necessário especificar o valor do recurso. Digamos, por exemplo, que você definiu:

local3.* /var/log/mylog

no syslog, convém usar:

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

e você também precisa ter o syslog escutando no UDP para usar o host local em vez de / dev / log.

Oliver Henriot
fonte
3
não há 'necessidade' de o syslog escutar no UDP. Seu exemplo também funcionará perfeitamente com o endereço = '/ dev / log'.
thor
5
Sim, claro, mas com endereço = ( 'localhost', 514), o dia que você tem um servidor de log, você substituir localhost pelo endereço do servidor e você tem registro remoto ;-)
Oliver Henriot
5
De onde vem a instalação = 19? por que não é instalação = "local3"
boatcoder 14/10
4
@ Mark0978 19 é a representação numérica de local3 como definido por RFC3146 (e, subsequentemente, RFC5424)
Andrew Sledge
3
Gostaria de saber sobre isso também, e descobrir que os códigos de instalação estão na fonte para Python SysLogHandler
clebio
11

Seu syslog.conf está configurado para manipular facilidade = usuário?

Você pode definir o recurso usado pelo criador de logs python com o argumento do recurso, algo como isto:

handler = logging.handlers.SysLogHandler(facility=SysLogHandler.LOG_DAEMON)
bstpierre
fonte
Você precisa especificar o que LOG_DAEMONvocê fornece como um valor para o facilityparâmetro
Tbot 19/10/10
4
Isso seria 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...')

o script acima registrará na instalação LOCAL0 com nosso "LOG_IDENTIFIER" personalizado ... você pode usar LOCAL [0-7] para fins locais.

San
fonte
1
seu comentário não tem nada a ver com solicitação original
thor 28/06
@thor Concordo que isso é relevante. Vou adivinhar que o pacote syslog é um pouco mais eficiente que a implementação pura do Python? (se menos flexível)
Daniel Santos
7

Em 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
fonte
Isso é muito interessante, mas não funciona no python 2.6.6 (RHEL 6.4): Traceback (última chamada mais recente): Arquivo "syslog_bridge.py", linha 68, em <module> handlers.append (SysLogLibHandler (logFacilityLocalN )) Arquivo "syslog_bridge.py", linha 29, em init syslog.openlog (syslog.LOG_PID, self.FACILITY [n]) TypeError: ident string [, logoption [, facilidade]]
Steve Cohen
Editado com base em: github.com/luismartingil/scripts/commit/…
luismartingil
3

Aqui está a maneira yaml dictConfig recomendada para 3.2 e posterior.

No log 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

Carregue a configuração usando:

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

Configurou o syslog e um arquivo direto. Observe que o /dev/logsistema operacional é específico.

Bruce Edge
fonte
1

Eu conserto no meu notebook. O serviço rsyslog não ouviu no serviço de soquete.

Eu configurei esta linha abaixo no /etc/rsyslog.confarquivo e resolvi o problema:

$SystemLogSocketName /dev/log

Anderson Madureira
fonte