จะกำหนดค่าการบันทึกไปยัง syslog ใน Python ได้อย่างไร?


121

ฉันไม่สามารถคาดเดาloggingโมดูลของ Python ได้ ความต้องการของฉันง่ายมากฉันแค่ต้องการบันทึกทุกอย่างลงใน syslog หลังจากอ่านเอกสารแล้วฉันได้พบกับสคริปต์ทดสอบง่ายๆนี้:

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

แต่สคริปต์นี้ไม่สร้างบันทึกบันทึกใด ๆ ใน syslog มีอะไรผิดปกติ


3
คุณกำลังตรวจสอบข้อความ syslog ของคุณอยู่ที่ไหน SysLogHandler () ส่งข้อความเหล่านั้นไปยัง udp socket ในพอร์ต 514 ใน localhost
suzanshakya

คุณพูดถูกจริงๆ และฉันได้เห็นว่า 'localhost-514' ในเอกสาร แต่ยังไม่ได้คิดว่า / dev / บันทึกจะถูกควรจะใช้โดยเริ่มต้น .. เฮ้อ ..
thor

คำตอบ:


140

เปลี่ยนบรรทัดเป็น:

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

สิ่งนี้ใช้ได้กับฉัน

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
โปรดทราบว่าตามที่เอกสารกล่าว'/var/run/syslog'คือสิ่งที่ถูกต้องบน OS X
offby1

คำตอบช่วยชีวิต +1
chachan

3
เราจะระบุบันทึกเหล่านี้ใน syslog ได้อย่างไร เช่นเราสามารถตั้งชื่อแอปพลิเคชันหรือแท็กใด ๆ เช่น syslogtag = django?
Luv33preet

และจำการกำหนดค่าไฟล์ /etc/syslog.d/conf และรีสตาร์ทบริการ syslog / rsyslog
linrongbin

5
@ Luv33preet ฉันได้ทดสอบด้วย (แต่ไม่ใช่ไม่มี) ตัวจัดรูปแบบเช่นlogging.Formatter(fmt='myscriptname[%(process)d]: %(levelname)s: %(message)s', ...)เงื่อนไข rsyslog เหมือนการ $programname == 'myscriptname'ทำงาน
Peter

26

คุณควรเสมอใช้โฮสต์ท้องถิ่นสำหรับการเข้าสู่ระบบไม่ว่าจะเป็น / dev / log หรือ localhost ผ่านสแต็คของ TCP สิ่งนี้ช่วยให้ daemon การบันทึกระบบที่สอดคล้องกับ RFC และคุณลักษณะที่มีคุณลักษณะสามารถจัดการ syslog สิ่งนี้ช่วยลดความจำเป็นในการทำให้รีโมต daemon ทำงานได้และให้ความสามารถที่เพิ่มขึ้นของ syslog daemon เช่น rsyslog และ syslog-ng เป็นต้น ปรัชญาเดียวกันสำหรับ SMTP เพียงส่งมอบให้กับซอฟต์แวร์ SMTP ในเครื่อง ในกรณีนี้ให้ใช้ 'โหมดโปรแกรม' ไม่ใช่ daemon แต่เป็นแนวคิดเดียวกัน ปล่อยให้ซอฟต์แวร์ที่มีความสามารถมากขึ้นจัดการกับมัน การลองใหม่การจัดคิวการสปูลโลคัลโดยใช้ TCP แทน UDP สำหรับ syslog และอื่น ๆ จะเป็นไปได้ คุณยังสามารถ [re-] กำหนดค่าภูตเหล่านั้นแยกจากรหัสของคุณได้ตามที่ควร

บันทึกการเข้ารหัสสำหรับแอปพลิเคชันของคุณปล่อยให้ซอฟต์แวร์อื่นทำงานร่วมกัน


2
คุณยกระดับความยุติธรรม คุณช่วยระบุที่อยู่และพอร์ตทั่วไปที่ใช้โดยภูตบันทึกต่างๆได้ไหม มีกลไกการค้นหามาตรฐานเพื่อตรวจสอบว่า daemon ถูกผูกไว้กับซ็อกเก็ต tcp หรือไม่?
init_js

ฉันเห็นด้วยกับคุณ
daks

20

ฉันพบว่าโมดูล syslogทำให้ง่ายต่อการรับพฤติกรรมการบันทึกพื้นฐานที่คุณอธิบาย:

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

มีสิ่งอื่น ๆ ที่คุณสามารถทำได้เช่นกัน แต่แม้เพียงสองบรรทัดแรกจะทำให้คุณได้รับสิ่งที่คุณขอตามที่ฉันเข้าใจ


ฉันเก็บโมดูลการบันทึกไว้เนื่องจากอนุญาตให้เปลี่ยนการตั้งค่าตัวบันทึกโดยไม่ส่งผลกระทบต่อคำสั่งทั้งหมด ยังอนุญาตให้เปลี่ยนพฤติกรรมในกรณีที่คุณต้องการบันทึกประเภทต่างๆในเวลานั้น
chachan

14

การปะติดปะต่อสิ่งต่างๆจากที่นี่และที่อื่น ๆ นี่คือสิ่งที่ฉันคิดขึ้นมาซึ่งใช้ได้กับ unbuntu 12.04 และ centOS6

สร้างไฟล์/etc/rsyslog.d/ที่ลงท้ายด้วย. config และเพิ่มข้อความต่อไปนี้

local6.*        /var/log/my-logfile

รีสตาร์ทrsyslogดูเหมือนว่าการโหลดซ้ำจะใช้ไม่ได้กับไฟล์บันทึกใหม่ บางทีมันอาจจะรีโหลดไฟล์ conf ที่มีอยู่เท่านั้น?

sudo restart rsyslog

จากนั้นคุณสามารถใช้โปรแกรมทดสอบนี้เพื่อให้แน่ใจว่าใช้งานได้จริง

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
ในการรีสตาร์ท rsyslog บน centOS7,sudo service rsyslog restart
radtek

12

ฉันเพิ่มความคิดเห็นเพิ่มเติมเล็กน้อยเผื่อว่าจะช่วยใครได้เพราะฉันพบว่าการแลกเปลี่ยนนี้มีประโยชน์ แต่ต้องการข้อมูลเพิ่มเติมเล็กน้อยเพื่อให้ทุกอย่างใช้งานได้

ในการเข้าสู่ระบบสถานที่เฉพาะโดยใช้ SysLogHandler คุณต้องระบุค่าสิ่งอำนวยความสะดวก ตัวอย่างเช่นที่คุณได้กำหนดไว้:

local3.* /var/log/mylog

ใน syslog คุณจะต้องใช้:

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

และคุณต้องมีการฟัง syslog บน UDP เพื่อใช้ localhost แทน / dev / log


3
ไม่มี 'ความจำเป็น' ที่จะต้องมี syslog ฟังบน UDP ตัวอย่างของคุณจะทำงานร่วมกับ address = '/ dev / log' ได้อย่างสมบูรณ์แบบ
ธ อร์

5
ใช่แน่นอน แต่ด้วย address = ('localhost', 514) วันที่คุณมีเซิร์ฟเวอร์บันทึกคุณแทนที่ localhost ด้วยที่อยู่ของเซิร์ฟเวอร์และคุณมีการบันทึกระยะไกล ;-)
Oliver Henriot

5
สิ่งอำนวยความสะดวก = 19 มาจากไหน? ทำไมมันไม่อำนวย = "local3"
boatcoder

4
@ Mark0978 19 เป็นการแสดงตัวเลขของ local3 ตามที่กำหนดโดย RFC3146 (และต่อมาคือ RFC5424)
Andrew Sledge

3
ฉันสงสัยเกี่ยวกับเรื่องนี้เช่นกันและพบว่ารหัสสิ่งอำนวยความสะดวกอยู่ในแหล่งที่มาของSysLogHandler
clebio

11

syslog.conf ของคุณได้รับการตั้งค่าเพื่อจัดการสิ่งอำนวยความสะดวก = ผู้ใช้หรือไม่

คุณสามารถตั้งค่าสิ่งอำนวยความสะดวกที่ใช้โดย python logger ด้วยอาร์กิวเมนต์สิ่งอำนวยความสะดวกดังนี้

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

คุณต้องระบุสิ่งที่LOG_DAEMONคุณระบุเป็นค่าสำหรับfacilityพารามิเตอร์
tzot

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

สคริปต์ด้านบนจะเข้าสู่ระบบ LOCAL0 ด้วย "LOG_IDENTIFIER" ที่กำหนดเองของเรา ... คุณสามารถใช้ LOCAL [0-7] เพื่อวัตถุประสงค์ในท้องถิ่น


1
ความคิดเห็นของคุณมีอะไรจะทำอย่างไรกับคำขอเดิม
ธ อร์

@ ฉันยอมรับว่าสิ่งนี้เกี่ยวข้อง ฉันจะเดาว่าแพ็คเกจ syslog นั้นมีประสิทธิภาพมากกว่าการใช้งาน Python แท้เล็กน้อย? (ถ้ามีความยืดหยุ่นน้อยกว่า)
Daniel Santos

7

จาก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')

สิ่งนี้น่าสนใจมาก แต่ใช้ไม่ได้กับ python 2.6.6 (RHEL 6.4): Traceback (โทรล่าสุดล่าสุด): ไฟล์ "syslog_bridge.py" บรรทัด 68 ใน <module> handlers.append (SysLogLibHandler (logFacilityLocalN )) ไฟล์ "syslog_bridge.py" บรรทัดที่ 29 ในinit syslog.openlog (syslog.LOG_PID, self.FACILITY [n]) TypeError: สตริงรหัส [, logoption [, สิ่งอำนวยความสะดวก]]
Steve Cohen

แก้ไขโดยอ้างอิงจาก: github.com/luismartingil/scripts/commit/…
luismartingil

3

นี่คือวิธี yaml dictConfig ที่แนะนำสำหรับ 3.2 และใหม่กว่า

ในบันทึก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

โหลดการกำหนดค่าโดยใช้:

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

กำหนดค่าทั้ง syslog และไฟล์โดยตรง โปรดทราบว่า/dev/logระบบปฏิบัติการเฉพาะ


1

ฉันซ่อมมันในโน๊ตบุ๊ค บริการ rsyslog ไม่รับฟังบริการซ็อกเก็ต

ฉันกำหนดค่าบรรทัดนี้ร้องใน /etc/rsyslog.confไฟล์และแก้ไขปัญหา:

$SystemLogSocketName /dev/log


-1

คุณยังสามารถเพิ่มตัวจัดการไฟล์หรือหมุนตัวจัดการไฟล์เพื่อส่งบันทึกของคุณไปยังไฟล์ในเครื่อง: http://docs.python.org/2/library/logging.handlers.html


3
ไม่มีประโยชน์มากหากคุณต้องการเรียกใช้มากกว่าหนึ่งกระบวนการ
dalore
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.