python3 / syslog:多个syslog流?

时间:2017-11-11 18:25:20

标签: python-3.x syslog

我的python3程序有许多子模块,我希望它们各自发送具有不同syslog Information:Gradle tasks [:app:assembleDebug] C:\Users\Amey\AndroidStudioProjects\DevAttendance\FaceRecognitionApp\app\src\main\cpp\face-lib.cpp Error:(20, 10) fatal error: 'Eigen/Dense' file not found Information:BUILD FAILED Information:Total time: 2.354 secs Information:1 error Information:0 warnings Information:See complete output in console 值的syslog消息。例如,其中一个可能会发送到ident,另一个可能会发送到myprogram/submod0。我使用myprogram/submod1将这些消息路由到不同的日志文件。

我想做的是这样的事情,我知道目前在这里写作的方式是不可能的:

syslog-ng

...然后,在syslog0 = syslog.openlog('myprogram/submod0', syslog.LOG_PID, syslog.LOG_MAIL) syslog1 = syslog.openlog('myprogram/submod1', syslog.LOG_PID, syslog.LOG_MAIL) 内,我想发送像这样的系统日志消息......

submod0

...这样在syslog0.syslog('some sort of message') ...

submod1

但是,当然,syslog1.syslog('another message') 并没有以这种方式返回任何我可以用作句柄的对象。

有没有办法可以使用python3的syslog.openlog工具完成我想要的工作?

我想我可以为每个要发送的系统日志消息发出新的syslog。例如......

openlog

...然后在def mysyslog(ident, message): syslog.openlog('myprogram/{}'.format(ident), syslog.LOG_PID, syslog.LOG_MAIL) syslog.syslog(message) 内的mysyslog('submod0', message)submod0mysyslog('submod1', message)使用submod1。这是我能完成我想做的唯一方法吗?

提前谢谢。

3 个答案:

答案 0 :(得分:0)

行。我看到我可以通过logging.handlers.SysLogHandler ...

执行此操作

https://docs.python.org/3/library/logging.handlers.html#sysloghandler

这是我的问题的答案,但它并不理想,因为我试图避免使用logging模块,如果可能的话。

我将继续寻找另一种方法来做到这一点。

答案 1 :(得分:0)

我找不到任何现有的python模块,它做了我想要的,所以我决定编写自己的syslog包装器。编写它是为了打开基于host:port或套接字文件(如/dev/log)的syslog连接,然后接受所有其他参数,如facilityseverityprogram等在每次调用时发送系统日志消息。

使用单个日志记录方法调用级别的所有参数,可以将此类包装在更高级别以提供句柄,例如,通过program提供的唯一连接,这是我在我原来的问题在这里。

我只使用python3.6和/dev/log案例测试了以下代码。它适用于我,但使用它需要您自担风险。

#!/usr/bin/python3.6

import os
import sys
import socket
import datetime

# Only imported for the syslog.LOG_INFO and syslog.LOG_USER constants.
import syslog

# Appends a newline in all cases.
def _log_stderr(message):
    if message:
        sys.stderr.write(message)
    sys.stderr.write('\n')
    sys.stderr.flush()

# XSyslog: a syslog wrapper class.
#
# This module allows the facility (such as LOG_USER), the
# severity (such as LOG_INFO), and other syslog parameters
# to be set on a message-by-message basis via one, single
# syslog connection.
#
# Usage:
#
#   slog = XSyslog([server=server], [port=port], [proto=proto],
#                  [clientname=clientname], [maxlen=maxlen])
#
# This allows three  cases:
# (1) Connect to syslog via UDP to a host and port:
#     Specify host, port, and proto='UDP'.
# (2) Connect to syslog via TCP to a host and port:
#     Specify host, port, and proto='TCP'.
# (3) Connect to syslog via a socket file such as /dev/log.
#     Specify proto=filename (e.g., proto='/dev/log').
#     In this case, host and port are ignored.
#
# clientname is an optional field for the syslog message.
# maxlen is the maximum message length.
#
# Once the XSyslog object is created, the message can be sent as follows:
#
#   slog = XSyslog([... parameters ...])
#   slog.log(message, [facility=facility], [severity=severity],
#                     [timestamp=timestamp], [hostame=hostname],
#                     [program=program], [pid=pid])
#     facility  defaults to LOG_USER
#     severity  defaults to LOG_INFO
#     timestamp defaults to now
#     hostname  if None, use clientname if it exists; if '', no hostname.
#     program   defaults to "logger"
#     pid       defaults to os.getpid()

class XSyslog(object):

    def __init__(self, server=None, port=None, proto='udp', clientname=None, maxlen=1024):
        self.server       = server
        self.port         = port
        self.proto        = socket.SOCK_DGRAM
        self.clientname   = None
        self.maxlen       = maxlen
        self._protoname   = ''
        self._socket      = None
        self._sockfile    = None
        self._connectargs = ()
        self._me          = os.path.splitext(self.__class__.__name__)[1][1:]

        if proto:
            if proto.lower() == 'udp':
                self._protoname  = proto.lower()
                self.proto       = socket.SOCK_DGRAM
                self._socketargs = (self.server, self.port, socket.AF_UNSPEC, self.proto)
            elif proto.lower() == 'tcp':
                self._protoname  = proto.lower()
                self.proto       = socket.SOCK_STREAM
                self._socketargs = (self.server, self.port, socket.AF_UNSPEC, self.proto)
            elif len(proto) > 0:
                self._sockfile   = proto
                self._protoname  = self._sockfile
                self.proto       = socket.SOCK_DGRAM
                self._socketargs = (socket.AF_UNIX, self.proto)

        badargs = False
        if self._sockfile:
            pass
        elif self.server and self.port:
            pass
        else:
            badargs = True
        if not self.proto:
            badargs = True
        if badargs:
            raise ValueError("'proto' must be 'udp' or 'tcp' with 'server' and 'port', or else a socket filename like '/dev/log'")

        if not self.clientname:
            try:
                self.clientname = socket.getfqdn()
                if not self.clientname:
                    self.clientname = socket.gethostname()
            except:
                self.clientname = None

    def _connect(self):
        if self._socket is None:
            if self._sockfile:
                self._socket = socket.socket(*self._socketargs)
                if not self._socket:
                    _log_stderr(':::::::: {}: unable to open socket file {}'.format(self._me, self._sockfile))
                    return False
                try:
                    self._socket.connect(self._sockfile)
                    return True
                except socket.timeout as e:
                    _log_stderr(':::::::: {}: sockfile timeout e={}'.format(self._me, e))
                    # Force-close the socket and its contained fd, to avoid fd leaks.
                    self.close()
                except socket.error as e:
                    _log_stderr(':::::::: {}: sockfile error f={}, e={}'.format(self._me, self._sockfile, e))
                    # Force-close the socket and its contained fd, to avoid fd leaks.
                    self.close()
                except Exception as e:
                    # Any other exception which might occur ...
                    _log_stderr(':::::::: {}: sockfile exception f={}, e={}'.format(self._me, self._sockfile, e))
                    # Force-close the socket and its contained fd, to avoid fd leaks.
                    self.close()
                return False
            else:
                addrinfo = socket.getaddrinfo(*self._socketargs)
                if addrinfo is None:
                    return False
                # Check each socket family member until we find one we can connect to.
                for (addr_fam, sock_kind, proto, ca_name, sock_addr) in addrinfo:
                    self._socket = socket.socket(addr_fam, self.proto)
                    if not self._socket:
                        _log_stderr(':::::::: {}: unable to get a {} socket'.format(self._me, self._protoname))
                        return False
                    try:
                        self._socket.connect(sock_addr)
                        return True
                    except socket.timeout as e:
                        _log_stderr(':::::::: {}: {} timeout e={}'.format(self.me, self._protoname, e))
                        # Force-close the socket and its contained fd, to avoid fd leaks.
                        self.close()
                        continue
                    except socket.error as e:
                        _log_stderr(':::::::: {}: {} error e={}'.format(self._me, self._protoname, e))
                        # Force-close the socket and its contained fd, to avoid fd leaks.
                        self.close()
                        continue
                    except Exception as e:
                        # Any other exception which might occur ...
                        _log_stderr(':::::::: {}: {} exception e={}'.format(self._me, self._protoname, e))
                        # Force-close the socket and its contained fd, to avoid fd leaks.
                        self.close()
                        continue
                # Force-close the socket and its contained fd, to avoid fd leaks.
                self.close()
                return False
        else:
            return True

    def close(self):
        try:
            self._socket.close()
        except:
            pass
        self._socket = None

    def log(self, message, facility=None, severity=None, timestamp=None, hostname=None, program=None, pid=None):

        if message is None:
            return

        if not facility:
            facility = syslog.LOG_USER

        if not severity:
            severity = syslog.LOG_INFO

        pri = facility + severity

        data = '<{}>'.format(pri)

        if timestamp:
            t = timestamp
        else:
            t = datetime.datetime.now()
        data = '{}{}'.format(data, t.strftime('%Y-%m-%dT%H:%M:%S.%f'))

        if hostname is None:
            if self.clientname:
                data = '{} {}'.format(data, self.clientname)
        elif not hostname:
            # For hostname == '', leave out the hostname, altogether.
            pass
        else:
            data = '{} {}'.format(data, hostname)

        if program:
            data = '{} {}'.format(data, program)
        else:
            data = '{} logger'.format(data)

        if not pid:
            pid = os.getpid()

        data = '{}[{}]: {}'.format(data, pid, message).encode('ascii', 'ignore')

        if not self._socket:
            self._connect()

        if not self._socket:
            raise Exception('{}: unable to connect to {} syslog via {}'.format(self._me, self._protoname, self._socketargs))
        try:
            if self.maxlen:
                self._socket.sendall(data[:self.maxlen])
            else:
                self._socket.sendall(data)
        except IOError as e:
            _log_stderr(':::::::: {}: {} syslog io error {} via {}'.format(self._me, self._protoname, e, self._socketargs))
            self.close()
            raise
        except Exception as e:
            # Any other exception which might occur ...
            _log_stderr(':::::::: {}: {} syslog exception {} via {}'.format(self._me, self._protoname, e, self._socketargs))
            self.close()
            raise

答案 2 :(得分:0)

这对于Python的0.5是不可能的。

唯一的选择是

  1. 使用syslog,调用syslog切换标识符

CPython的openlog(ident)包装了unix库syslogsyslog)。那里存在相同的限制...您可以将#include <syslog.h>设置为ident,但使用openlog(ident)发送消息时则不能。也许unix lib允许多个“记录器”用于不同的标识符,我不知道...但绝对不是Python的syslog()

您可以在此处查看CPython的所有实现:https://github.com/python/cpython/blob/92a98ed/Modules/syslogmodule.c

  1. 使用syslog

logging.handlers.SysLogHandler很好。您可以使用自己的SysLogHandler值来创建不同的处理程序。它处理格式。并设置您要通过其发送消息的任何套接字(UDP,TCP或Unix域)。