【问题标题】:How to configure logging to syslog in Python?如何在 Python 中配置日志记录到 syslog?
【发布时间】:2011-04-27 11:43:40
【问题描述】:

我无法理解 Python 的 logging 模块。我的需求非常简单:我只想将所有内容记录到 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 中产生任何日志记录。怎么了?

【问题讨论】:

  • 您在哪里查看系统日志消息? SysLogHandler() 将这些消息发送到 localhost 中端口 514 中的 udp 套接字。
  • 你说得对。而且我在文档中看到了“localhost-514”,但没有想到应该默认使用 /dev/log .. 叹息..

标签: python logging syslog


【解决方案1】:

将行改为:

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

【讨论】:

  • 请注意,正如the doc 所说,'/var/run/syslog' 在 OS X 上是正确的。
  • 我们如何在 syslog 中识别这些日志?像我们可以给任何应用程序名称或任何标签,如 syslogtag=django 吗?
  • 记得配置/etc/syslog.d/conf文件,重启syslog/rsyslog服务
  • @Luv33preet 我已经使用(但不是没有)像logging.Formatter(fmt='myscriptname[%(process)d]: %(levelname)s: %(message)s', ...) 这样的格式化程序进行了测试,像$programname == 'myscriptname' 这样的rsyslog 条件可以工作。
  • @Peter 谢谢队友,很高兴你在这么长时间后调查这个问题。如果我遇到一些问题,我会回复你。像你这样的人让社区保持运转
【解决方案2】:

您应该始终使用本地主机进行日志记录,无论是通过 TCP 堆栈到 /dev/log 还是本地主机。这允许完全符合 RFC 且功能强大的系统日志记录守护进程来处理 syslog。这消除了远程守护程序正常运行的需要,并提供了 syslog 守护程序的增强功能,例如 rsyslog 和 syslog-ng。同样的理念也适用于 SMTP。只需将其交给本地 SMTP 软件即可。在这种情况下,使用“程序模式”而不是守护程序,但它是相同的想法。让功能更强大的软件来处理它。重试、排队、本地假脱机、使用 TCP 而不是 UDP 用于 syslog 等等成为可能。您还可以按照应有的方式将这些守护程序与您的代码分开[重新]配置。

保存应用程序的编码,让其他软件协同工作。

【讨论】:

  • 你提出了一个公平的观点。您能指出各种日志记录守护程序使用的公共地址和端口吗?是否有标准的发现机制来确定守护进程是否绑定到 tcp 套接字?
【解决方案3】:

我发现the syslog module 可以很容易地获得您描述的基本日志记录行为:

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

你也可以做其他事情,但即使只是前两行,我也能理解你的要求。

【讨论】:

  • 我保留了日志模块,因为它允许在不影响所有语句的情况下更改记录器设置。如果您想同时拥有不同类型的日志记录,还允许更改行为
【解决方案4】:

从这里和其他地方拼凑起来,这就是我想出的适用于 unbuntu 12.04 和 centOS6 的方法

/etc/rsyslog.d/ 中创建一个以.conf 结尾的文件并添加以下文本

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

【讨论】:

  • 在centOS7上重启rsyslog,sudo service rsyslog restart
【解决方案5】:

我添加了一些额外的评论,以防它对任何人有所帮助,因为我发现此交流很有用,但需要这一点额外的信息才能使其全部正常工作。

要使用 SysLogHandler 记录到特定设施,您需要指定设施值。 比如说你已经定义了:

local3.* /var/log/mylog

在系统日志中,然后你会想使用:

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

而且您还需要让 syslog 监听 UDP 以使用 localhost 而不是 /dev/log。

【讨论】:

  • 没有“需要”让 syslog 监听 UDP。您的示例也可以完美地与 address='/dev/log' 一起使用。
  • 是的,当然,但是使用 address = ('localhost',514),在你拥有日志服务器的那一天,你将 localhost 替换为服务器的地址,你就有了远程日志记录;-)
  • 设施=19 来自哪里?为什么不是 facility="local3"
  • @Mark0978 19 是 RFC3146(以及随后的 RFC5424)定义的 local3 的数字表示
  • 我也想知道这个,发现设施代码在Python的SysLogHandler的源代码中
【解决方案6】:

您的 syslog.conf 是否设置为处理 facility=user?

您可以使用设施参数设置 python 记录器使用的设施,如下所示:

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

【讨论】:

  • 您需要指定您提供的LOG_DAEMON 是什么,作为facility 参数的值。
  • 那就是SysLogHandler.LOG_DAEMON
【解决方案7】:
import syslog
syslog.openlog(ident="LOG_IDENTIFIER",logoption=syslog.LOG_PID, facility=syslog.LOG_LOCAL0)
syslog.syslog('Log processing initiated...')

上述脚本将使用我们自定义的“LOG_IDENTIFIER”登录到 LOCAL0 设施... 您可以将 LOCAL[0-7] 用于本地目的。

【讨论】:

  • 您的评论与原始请求无关
  • @thor 我同意这是相关的。我要猜测 syslog 包比纯Python 实现更高效一点? (如果不太灵活)
【解决方案8】:

来自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 行,在 handlers.append(SysLogLibHandler(logFacilityLocalN)) 文件“syslog_bridge.py”,第 29 行,在 init syslog.openlog(syslog.LOG_PID, self.FACILITY[n]) TypeError: ident string [,登录选项 [, 设施]]
【解决方案9】:

这是 3.2 及更高版本推荐的 yaml dictConfig 方式。

登录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)

同时配置系统日志和直接文件。请注意,/dev/log 是特定于操作系统的。

【讨论】:

    【解决方案10】:

    我把它固定在我的笔记本上。 rsyslog 服务未侦听套接字服务。

    我在/etc/rsyslog.conf 文件中配置下面这行并解决了问题:

    $SystemLogSocketName /dev/log

    【讨论】:

      【解决方案11】:

      我使用 JSON 日志记录并希望将 SysLogHandler 与 UDP 端口 514 一起使用。最终让 JSON 处理程序配置工作。在处理程序部分,我有:

      {
          "syslog": {
              "class": "logging.handlers.SysLogHandler",
              "address": ["127.0.0.1", 514],
              "facility": "local6",
              "formatter": "syslog_fmt"
      }
      

      在其他任何地方都没有找到这个。

      [编辑] 为了更清楚地了解这里发生了什么:这仅适用于 python 代码,并使用 python 的内置日志记录模块。该模块允许配置日志消息的格式和目的地。配置日志格式和目标的一种方法是使用用于配置日志记录的 JSON 文件。

      上面的示例允许我将日志消息发送到 syslog 守护进程。

      下面包含此类文件的完整示例。

      {
          "version": 1,
          "disable_existing_loggers": "False",
          "formatters": {
              "verbose": {
                  "format": "%(asctime)s:%(levelname)s:%(process)d:%(filename)s:%(funcName)s:L%(lineno)d:%(message)s"
              },
              "syslog": {
                  "format": "%(levelname)s:%(process)d:%(filename)s:%(funcName)s:L%(lineno)d:%(message)s"
              }
          },
          "handlers": {
              "console": {
                  "class":"logging.StreamHandler",
                  "formatter": "standard"
              },
              "syslog": {
              "class": "logging.handlers.SysLogHandler",
              "address": ["127.0.0.1", 514],
              "facility": "local6",
              "formatter": "syslog_fmt"
              }
          },
          "loggers": {
              "": {
                  "handlers": ["console","syslog"],
                  "level": "DEBUG",
                  "propagate": "True"
              }
          }
      }
      

      上面的示例将 python 日志消息发送到 syslog 和控制台。目的地的消息格式不同(syslog 已经为每条消息添加了时间戳)。对于 syslog 目标,日志使用设施 LOCAL6。

      【讨论】:

      • 整个配置是什么样的,我如何从 python 中读取?
      • JSON 日志记录的确切含义是什么?你的系统日志配置是 json 格式的,对吧?你不登录json格式? @ahnkle
      • JSON 日志记录正在使用 JSON 文件格式配置 python 日志记录。使用 logging.config.dictConfig() 读取 JSON。
      【解决方案12】:

      您还可以添加文件处理程序或旋转文件处理程序以将日志发送到本地文件: http://docs.python.org/2/library/logging.handlers.html

      【讨论】:

      • 如果你想运行多个进程,这不是很有用。
      • 使用文件处理程序不能回答问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-27
      • 2011-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-15
      相关资源
      最近更新 更多