Bagaimana cara mengkonfigurasi logging ke syslog dengan Python?


121

Saya tidak bisa memahami loggingmodul Python . Kebutuhan saya sangat sederhana: Saya hanya ingin memasukkan semuanya ke syslog. Setelah membaca dokumentasi, saya mendapatkan skrip tes sederhana ini:

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

Tetapi skrip ini tidak menghasilkan catatan log apa pun di syslog. Apa yang salah?


3
Di mana Anda memeriksa pesan syslog Anda? SysLogHandler () memancarkan pesan tersebut ke soket udp di port 514 di localhost.
suzanshakya

Anda benar sekali. Dan saya telah melihat bahwa 'localhost-514' dalam dokumentasi tetapi belum berpikir bahwa / dev / log harus digunakan secara default .. Sigh ..
thor

Jawaban:


140

Ubah baris menjadi ini:

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

Ini berhasil untuk saya

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
Perhatikan bahwa, seperti yang dikatakan dokter , '/var/run/syslog'adalah Hal yang Benar di OS X.
offby1

Jawaban penyelamat +1
chachan

3
bagaimana kita bisa mengidentifikasi log ini di syslog? seperti bisakah kita memberikan nama aplikasi ATAU tag apapun seperti syslogtag = django?
Luv33preet

dan ingat konfigurasi file /etc/syslog.d/conf, dan restart layanan syslog / rsyslog
linrongbin

5
@ Luv33preet Saya telah mengujinya dengan (tetapi bukan tanpa) formatter seperti logging.Formatter(fmt='myscriptname[%(process)d]: %(levelname)s: %(message)s', ...), kondisi rsyslog seperti $programname == 'myscriptname'karya.
Peter

26

Anda harus selalu menggunakan host lokal untuk pencatatan, apakah ke / dev / log atau localhost melalui tumpukan TCP. Hal ini memungkinkan daemon pencatatan sistem yang sesuai dengan RFC dan berfitur lengkap untuk menangani syslog. Ini menghilangkan kebutuhan akan daemon jarak jauh untuk berfungsi dan menyediakan kapabilitas yang ditingkatkan dari daemon syslog seperti rsyslog dan syslog-ng misalnya. Filosofi yang sama berlaku untuk SMTP. Serahkan saja ke perangkat lunak SMTP lokal. Dalam kasus ini gunakan 'mode program' bukan daemon, tapi idenya sama. Biarkan perangkat lunak yang lebih mampu menanganinya. Mencoba kembali, mengantri, spooling lokal, menggunakan TCP bukan UDP untuk syslog dan sebagainya menjadi mungkin. Anda juga dapat [kembali] mengkonfigurasi daemon tersebut secara terpisah dari kode Anda sebagaimana mestinya.

Simpan pengkodean Anda untuk aplikasi Anda, biarkan perangkat lunak lain melakukan tugasnya secara bersamaan.


2
Anda mengangkat poin yang adil. dapatkah Anda menunjukkan alamat dan port umum yang digunakan oleh berbagai daemon logging? apakah ada mekanisme penemuan standar untuk menentukan apakah daemon terikat ke soket tcp atau tidak?
init_js

Saya sangat setuju dengan anda.
daks

20

Saya menemukan modul syslog untuk mempermudah mendapatkan perilaku logging dasar yang Anda gambarkan:

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

Ada hal-hal lain yang dapat Anda lakukan juga, tetapi bahkan hanya dua baris pertama saja yang akan memberi Anda apa yang Anda minta seperti yang saya pahami.


Saya menyimpan modul logging karena memungkinkan untuk mengubah pengaturan logger tanpa mempengaruhi semua pernyataan. Juga memungkinkan untuk mengubah perilaku jika Anda ingin memiliki jenis logging yang berbeda pada saat itu
chachan

14

Menyatukan semuanya dari sini dan tempat lain, inilah yang saya dapatkan yang berfungsi pada unbuntu 12.04 dan centOS6

Buat file /etc/rsyslog.d/yang diakhiri dengan .conf dan tambahkan teks berikut

local6.*        /var/log/my-logfile

Mulai ulang rsyslog, memuat ulang sepertinya TIDAK berfungsi untuk file log baru. Mungkin hanya memuat ulang file conf yang ada?

sudo restart rsyslog

Kemudian Anda dapat menggunakan program uji ini untuk memastikan program itu benar-benar berfungsi.

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
Untuk memulai ulang rsyslog di centOS7,sudo service rsyslog restart
radtek

12

Saya menambahkan sedikit komentar ekstra untuk berjaga-jaga jika itu membantu siapa pun karena saya menemukan pertukaran ini berguna tetapi membutuhkan sedikit info tambahan ini untuk membuat semuanya berfungsi.

Untuk masuk ke fasilitas tertentu menggunakan SysLogHandler, Anda perlu menentukan nilai fasilitas. Katakanlah misalnya yang telah Anda tentukan:

local3.* /var/log/mylog

di syslog, maka Anda ingin menggunakan:

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

dan Anda juga perlu memiliki syslog yang mendengarkan di UDP untuk menggunakan localhost daripada / dev / log.


3
tidak perlu ada syslog untuk mendengarkan UDP. Contoh Anda akan bekerja dengan sempurna dengan address = '/ dev / log' juga.
thor

5
ya, tentu, tetapi dengan address = ('localhost', 514), pada hari Anda memiliki server log, Anda mengganti localhost dengan alamat server dan Anda mendapatkan pencatatan jarak jauh ;-)
Oliver Henriot

5
Dari mana fasilitas = 19 berasal? kenapa tidak fasilitas = "local3"
boatcoder

4
@ Mark0978 19 adalah representasi numerik dari local3 seperti yang didefinisikan oleh RFC3146 (dan selanjutnya RFC5424)
Andrew Sledge

3
Saya juga bertanya-tanya tentang ini, dan menemukan bahwa kode fasilitas ada di sumber untuk SysLogHandler
clebio

11

Apakah syslog.conf Anda diatur untuk menangani fasilitas = pengguna?

Anda dapat mengatur fasilitas yang digunakan oleh python logger dengan argumen fasilitas, seperti ini:

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

Anda perlu menentukan apa yang LOG_DAEMONAnda berikan sebagai nilai untuk facilityparameter.
tzot

4
Itu akan menjadi 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...')

skrip di atas akan masuk ke fasilitas LOCAL0 dengan "LOG_IDENTIFIER" kustom kami ... Anda dapat menggunakan LOCAL [0-7] untuk tujuan lokal.


1
komentar Anda tidak ada hubungannya dengan permintaan asli
thor

@ atau saya setuju bahwa ini relevan. Saya akan menebak bahwa paket syslog sedikit lebih efisien daripada implementasi Python murni? (jika kurang fleksibel)
Daniel Santos

7

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

Ini sangat menarik, tetapi tidak berfungsi pada python 2.6.6 (RHEL 6.4): Traceback (panggilan terakhir terakhir): File "syslog_bridge.py", baris 68, di <module> handlers.append (SysLogLibHandler (logFacilityLocalN )) File "syslog_bridge.py", baris 29, di init syslog.openlog (syslog.LOG_PID, self.FACILITY [n]) TypeError: ident string [, logoption [, fasilitas]]
Steve Cohen


3

Berikut adalah cara diktConfig yaml yang direkomendasikan untuk versi 3.2 & yang lebih baru.

Masuk 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

Muat konfigurasi menggunakan:

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

Mengkonfigurasi syslog & file langsung. Perhatikan bahwa /dev/logspesifik OS.


1

Saya memperbaikinya di buku catatan saya. Layanan rsyslog tidak mendengarkan layanan soket.

Saya mengonfigurasi baris ini di bawah dalam /etc/rsyslog.conffile dan memecahkan masalah:

$SystemLogSocketName /dev/log


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.