Làm cách nào để định cấu hình ghi nhật ký vào nhật ký hệ thống bằng Python?


121

Tôi không thể hiểu được loggingmô-đun của Python . Nhu cầu của tôi rất đơn giản: tôi chỉ muốn ghi mọi thứ vào nhật ký hệ thống. Sau khi đọc tài liệu, tôi đã nghĩ ra kịch bản thử nghiệm đơn giản này:

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

Nhưng tập lệnh này không tạo ra bất kỳ bản ghi nhật ký nào trong nhật ký hệ thống. Chuyện gì vậy?


3
Bạn đang kiểm tra thông báo nhật ký hệ thống của mình ở đâu? SysLogHandler () phát các thông báo đó tới udp socket ở cổng 514 trong localhost.
suzanshakya

Bạn hoàn toàn đúng. Và tôi đã thấy 'localhost-514' trong tài liệu nhưng không nghĩ rằng / dev / log nên được sử dụng theo mặc định .. Thở dài ..
thor 19/10/10

Câu trả lời:


140

Thay đổi dòng này:

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

Điều này phù hợp với tôi

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
Lưu ý rằng, như tài liệu nói, '/var/run/syslog'là Điều đúng đắn trên OS X.
offby1

Câu trả lời cứu sinh +1
chachan

3
làm thế nào chúng ta có thể xác định các nhật ký này trong nhật ký hệ thống? như chúng ta có thể cung cấp bất kỳ tên ứng dụng HOẶC bất kỳ thẻ nào như syslogtag = django?
Luv33preet

và ghi nhớ cấu hình các tập tin /etc/syslog.d/conf, và khởi động lại syslog / rsyslog dịch vụ
linrongbin

5
@ Luv33preet Tôi đã thử nghiệm điều đó với (nhưng không phải không có) một định dạng như logging.Formatter(fmt='myscriptname[%(process)d]: %(levelname)s: %(message)s', ...), một điều kiện rsyslog như $programname == 'myscriptname'hoạt động.
Peter

26

Bạn nên luôn sử dụng máy chủ cục bộ để ghi nhật ký, cho dù là / dev / log hay localhost thông qua ngăn xếp TCP. Điều này cho phép daemon ghi nhật ký hệ thống hoàn toàn tuân thủ RFC và có tính năng để xử lý nhật ký hệ thống. Điều này giúp loại bỏ nhu cầu về chức năng của daemon từ xa và cung cấp các khả năng nâng cao của daemon syslog như rsyslog và syslog-ng chẳng hạn. Triết lý tương tự cũng áp dụng cho SMTP. Chỉ cần giao nó cho phần mềm SMTP cục bộ. Trong trường hợp này, hãy sử dụng 'chế độ chương trình' không phải là daemon, nhưng đó là cùng một ý tưởng. Hãy để phần mềm có năng lực hơn xử lý nó. Thử lại, xếp hàng đợi, lưu đệm cục bộ, sử dụng TCP thay vì UDP cho nhật ký hệ thống, v.v. trở nên khả thi. Bạn cũng có thể [lại] định cấu hình các daemon đó riêng biệt với mã của bạn như nó phải như vậy.

Lưu mã hóa cho ứng dụng của bạn, để phần mềm khác thực hiện công việc đó cùng lúc.


2
bạn nêu ra một điểm công bằng. bạn có thể chỉ ra các địa chỉ và cổng phổ biến được sử dụng bởi các daemon đăng nhập khác nhau không? có một cơ chế khám phá tiêu chuẩn để xác định xem daemon có bị ràng buộc với ổ cắm tcp không?
init_js

Tôi hoàn toàn đồng ý với bạn.
daks

20

Tôi nhận thấy mô-đun nhật ký hệ thống giúp dễ dàng thực hiện hành vi ghi nhật ký cơ bản như bạn mô tả:

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

Bạn cũng có thể làm những thứ khác, nhưng ngay cả chỉ hai dòng đầu tiên của nó cũng sẽ giúp bạn có được những gì bạn đã yêu cầu như tôi hiểu.


Tôi giữ mô-đun ghi nhật ký vì nó cho phép thay đổi cài đặt ghi nhật ký mà không ảnh hưởng đến tất cả các câu lệnh. Cũng cho phép thay đổi hành vi trong trường hợp bạn muốn có các loại khác nhau của khai thác gỗ vào thời điểm đó
chachan

14

Ghép mọi thứ lại với nhau từ đây và những nơi khác, đây là những gì tôi đã nghĩ ra hoạt động trên Ubuntu 12.04 và centOS6

Tạo một tệp có đuôi /etc/rsyslog.d/.conf và thêm văn bản sau

local6.*        /var/log/my-logfile

Khởi động lại rsyslog, tải lại dường như KHÔNG hoạt động đối với các tệp nhật ký mới. Có lẽ nó chỉ tải lại các tệp conf hiện có?

sudo restart rsyslog

Sau đó, bạn có thể sử dụng chương trình thử nghiệm này để đảm bảo rằng nó thực sự hoạt động.

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
Để khởi động lại rsyslog trên centOS7,sudo service rsyslog restart
radtek

12

Tôi thêm một chút bình luận bổ sung trong trường hợp nó giúp ích cho bất kỳ ai vì tôi thấy cuộc trao đổi này hữu ích nhưng cần thêm một chút thông tin này để mọi thứ hoạt động.

Để đăng nhập vào một cơ sở cụ thể bằng SysLogHandler, bạn cần chỉ định giá trị cơ sở. Ví dụ như bạn đã xác định:

local3.* /var/log/mylog

trong nhật ký hệ thống, sau đó bạn sẽ muốn sử dụng:

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

và bạn cũng cần phải nghe nhật ký hệ thống trên UDP để sử dụng localhost thay vì / dev / log.


3
không cần thiết phải nghe nhật ký hệ thống trên UDP. Ví dụ của bạn cũng sẽ hoạt động hoàn hảo với address = '/ dev / log'.
thor

5
vâng, chắc chắn rồi, nhưng với address = ('localhost', 514), vào ngày bạn có máy chủ ghi nhật ký, bạn thay thế localhost bằng địa chỉ của máy chủ và bạn đã ghi nhật ký từ xa ;-)
Oliver Henriot

5
Cơ sở = 19 đến từ đâu? tại sao nó không phải là cơ sở = "local3"
boatcoder

4
@ Mark0978 19 là đại diện số của local3 như được định nghĩa bởi RFC3146 (và sau đó là RFC5424)
Andrew Sledge

3
Tôi băn khoăn về vấn đề này quá, và thấy rằng các mã cơ sở đang trong nguồn cho Python của SysLogHandler
clebio

11

Syslog.conf của bạn có được thiết lập để xử lý cơ sở = người dùng không?

Bạn có thể đặt cơ sở được sử dụng bởi trình ghi python với đối số cơ sở, giống như sau:

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

Bạn cần chỉ định những gì LOG_DAEMONbạn cung cấp làm giá trị cho facilitytham số.
tzot 19/10/10

4
Đó sẽ là 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...')

tập lệnh trên sẽ đăng nhập vào cơ sở LOCAL0 với "LOG_IDENTIFIER" tùy chỉnh của chúng tôi ... bạn có thể sử dụng LOCAL [0-7] cho mục đích cục bộ.


1
bình luận của bạn không liên quan gì đến yêu cầu ban đầu
thor

@thor Tôi đồng ý rằng điều này có liên quan. Tôi sẽ đoán rằng gói nhật ký hệ thống hiệu quả hơn một chút so với việc triển khai Python thuần túy? (nếu ít linh hoạt)
Daniel Santos

7

Từ https://github.com/luismartil/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')

Điều này rất thú vị, nhưng nó không hoạt động trên python 2.6.6 (RHEL 6.4): Traceback (lần gọi gần đây nhất): Tệp "syslog_bridge.py", dòng 68, trong <module> handlers.append (SysLogLibHandler (logFacilityLocalN) )) Tệp "syslog_bridge.py", dòng 29, trong init syslog.openlog (syslog.LOG_PID, self.FACILITY [n]) TypeError: Id string [, logoption [, cơ sở]]
Steve Cohen

Được chỉnh sửa dựa trên: github.com/luismartil/scripts/commit/…
luismartil

3

Đây là cách yaml dictConfig được đề xuất cho 3.2 trở lên.

Trong nhật ký 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

Tải cấu hình bằng:

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

Đã định cấu hình cả nhật ký hệ thống và một tệp trực tiếp. Lưu ý rằng đó /dev/loglà hệ điều hành cụ thể.


1

Tôi sửa nó vào sổ tay của tôi. Dịch vụ nhật ký rsyslog không nghe trên dịch vụ ổ cắm.

Tôi định cấu hình dòng này dưới đây trong /etc/rsyslog.conftệp và giải quyết được sự cố:

$SystemLogSocketName /dev/log


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.