Comment configurer la journalisation dans syslog en Python?

121

Je ne peux pas comprendre le loggingmodule de Python . Mes besoins sont très simples: je veux juste tout enregistrer dans syslog. Après avoir lu la documentation, j'ai créé ce script de test simple:

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

Mais ce script ne produit aucun enregistrement de journal dans syslog. Qu'est-ce qui ne va pas?

Thor
la source
3
Où vérifiez-vous vos messages syslog? SysLogHandler () émet ces messages sur le socket udp sur le port 514 de localhost.
suzanshakya
Vous avez absolument raison. Et j'ai vu que «localhost-514» dans la documentation, mais je n'ai pas pensé que / dev / log devrait être utilisé par défaut .. Soupir ..
thor

Réponses:

140

Changez la ligne en ceci:

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

Cela fonctionne pour moi

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
la source
12
Notez que, comme le doc dit, '/var/run/syslog'est la bonne chose sur OS X.
offby1
Lifesaver answer +1
chachan
3
comment pouvons-nous identifier ces journaux dans syslog? comme pouvons-nous donner n'importe quel nom d'application OU n'importe quelle balise comme syslogtag = django?
Luv33preet
et souvenez-vous de configurer le fichier /etc/syslog.d/conf, et redémarrez le service syslog / rsyslog
linrongbin
5
@ Luv33preet J'ai testé cela avec (mais pas sans) un formateur comme logging.Formatter(fmt='myscriptname[%(process)d]: %(levelname)s: %(message)s', ...), une condition rsyslog comme $programname == 'myscriptname'works.
Peter
26

Vous devez toujours utiliser l'hôte local pour la journalisation, que ce soit vers / dev / log ou localhost via la pile TCP. Cela permet au démon de journalisation système entièrement compatible RFC et fonctionnel de gérer le syslog. Cela élimine la nécessité pour le démon distant d'être fonctionnel et fournit les capacités améliorées des démons syslog tels que rsyslog et syslog-ng par exemple. La même philosophie vaut pour SMTP. Il suffit de le remettre au logiciel SMTP local. Dans ce cas, utilisez le «mode programme» et non le démon, mais c'est la même idée. Laissez le logiciel le plus performant le gérer. Une nouvelle tentative, une mise en file d'attente, une mise en file d'attente locale, l'utilisation de TCP au lieu d'UDP pour syslog et ainsi de suite deviennent possibles. Vous pouvez également [re] configurer ces démons séparément de votre code comme il se doit.

Enregistrez votre codage pour votre application, laissez d'autres logiciels faire leur travail de concert.

egrep
la source
2
vous soulevez un bon point. pouvez-vous indiquer les adresses et les ports communs utilisés par divers démons de journalisation? existe-t-il un mécanisme de découverte standard pour déterminer si le démon est lié ou non à une socket TCP?
init_js
Je suis totalement d'accord avec vous.
daks
20

J'ai trouvé le module syslog pour faciliter l'obtention du comportement de journalisation de base que vous décrivez:

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

Il y a d'autres choses que vous pourriez faire aussi, mais même les deux premières lignes vous permettront d'obtenir ce que vous avez demandé si je comprends bien.

lindes-hw
la source
Je garde le module de journalisation car il permet de modifier les paramètres de l'enregistreur sans affecter toutes les instructions. Permet également de changer de comportement au cas où vous voudriez avoir différents types de journalisation à la fois
chachan
14

En assemblant des éléments d'ici et d'autres endroits, c'est ce que j'ai trouvé qui fonctionne sur unununtu 12.04 et centOS6

Créez un fichier /etc/rsyslog.d/qui se termine par .conf et ajoutez le texte suivant

local6.*        /var/log/my-logfile

Redémarrez rsyslog, le rechargement ne semble PAS fonctionner pour les nouveaux fichiers journaux. Peut-être qu'il ne recharge que les fichiers de configuration existants?

sudo restart rsyslog

Ensuite, vous pouvez utiliser ce programme de test pour vous assurer qu'il fonctionne réellement.

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")
bateau
la source
1
Pour redémarrer rsyslog sur centOS7,sudo service rsyslog restart
radtek
12

J'ajoute un petit commentaire supplémentaire au cas où cela aiderait quelqu'un parce que j'ai trouvé cet échange utile mais j'avais besoin de ce petit supplément d'informations pour que tout fonctionne.

Pour vous connecter à une installation spécifique à l'aide de SysLogHandler, vous devez spécifier la valeur de la fonction. Disons par exemple que vous avez défini:

local3.* /var/log/mylog

dans syslog, vous voudrez alors utiliser:

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

et vous devez également avoir syslog à l'écoute sur UDP pour utiliser localhost au lieu de / dev / log.

Oliver Henriot
la source
3
il n'est pas nécessaire que syslog écoute sur UDP. Votre exemple fonctionnera parfaitement avec address = '/ dev / log' également.
thor
5
oui, bien sûr, mais avec adresse = ('localhost', 514), le jour où vous avez un serveur de journaux, vous remplacez localhost par l'adresse du serveur et vous avez la journalisation à distance ;-)
Oliver Henriot
5
D'où vient l'installation = 19? pourquoi n'est-ce pas installation = "local3"
boatcoder
4
@ Mark0978 19 est la représentation numérique de local3 tel que défini par RFC3146 (et ultérieurement RFC5424)
Andrew Sledge
3
Je me suis également posé des questions à ce sujet et j'ai constaté que les codes d'installation sont dans la source du SysLogHandler
clebio
11

Votre syslog.conf est-il configuré pour gérer Facility = user?

Vous pouvez définir la fonction utilisée par le logger python avec l'argument facilité, quelque chose comme ceci:

handler = logging.handlers.SysLogHandler(facility=SysLogHandler.LOG_DAEMON)
Bstpierre
la source
Vous devez spécifier ce que LOG_DAEMONvous fournissez comme valeur pour le facilityparamètre.
tzot
4
Ce serait 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...')

le script ci-dessus se connectera à l'installation LOCAL0 avec notre "LOG_IDENTIFIER" personnalisé ... vous pouvez utiliser LOCAL [0-7] à des fins locales.

San
la source
1
votre commentaire n'a rien à voir avec la demande originale
thor
@thor, je conviendrai que c'est pertinent. Je vais deviner que le package syslog est un peu plus efficace que l'implémentation pure Python? (si moins flexible)
Daniel Santos
7

Depuis 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
la source
C'est très intéressant, mais cela ne fonctionne pas sur python 2.6.6 (RHEL 6.4): Traceback (dernier appel le plus récent): Fichier "syslog_bridge.py", ligne 68, dans <module> handlers.append (SysLogLibHandler (logFacilityLocalN )) Fichier "syslog_bridge.py", ligne 29, dans init syslog.openlog (syslog.LOG_PID, self.FACILITY [n]) TypeError: ident string [, logoption [, facilité]]
Steve Cohen
Édité d'après: github.com/luismartingil/scripts/commit/…
luismartingil
3

Voici la méthode yaml dictConfig recommandée pour la version 3.2 et les versions ultérieures.

Dans le journal 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

Chargez la configuration en utilisant:

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

Configuré à la fois syslog et un fichier direct. Notez que le /dev/logest spécifique au système d'exploitation.

Bruce Edge
la source
1

Je le répare sur mon cahier. Le service rsyslog n'a pas écouté sur le service socket.

J'ai configuré cette ligne ci-dessous dans le /etc/rsyslog.conffichier et j'ai résolu le problème:

$SystemLogSocketName /dev/log

Anderson Madureira
la source