首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >python3 3/ syslog :多个syslog流?

python3 3/ syslog :多个syslog流?
EN

Stack Overflow用户
提问于 2017-11-11 18:25:20
回答 3查看 1.1K关注 0票数 2

我的python3程序有许多子模块,我希望每个子模块用不同的syslog ident值发送syslog消息。例如,其中一个可能发送到myprogram/submod0,另一个可能发送到myprogram/submod1。我使用syslog-ng将这些消息路由到不同的日志文件。

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

代码语言:javascript
复制
syslog0 = syslog.openlog('myprogram/submod0', 
                         syslog.LOG_PID, syslog.LOG_MAIL)
syslog1 = syslog.openlog('myprogram/submod1',
                         syslog.LOG_PID, syslog.LOG_MAIL)

..。然后,在submod0内部,我想发送这样的syslog消息.

代码语言:javascript
复制
syslog0.syslog('some sort of message')

..。在submod1 ..。

代码语言:javascript
复制
syslog1.syslog('another message')

但是,当然,syslog.openlog不会以这种方式返回我可以用作句柄的任何类型的对象。

是否有任何方法可以使用syslog的python3工具实现我想要的?

我想我可以为我想发送的每个syslog消息发出一个新的openlog。例如..。

代码语言:javascript
复制
def mysyslog(ident, message):
    syslog.openlog('myprogram/{}'.format(ident),
                   syslog.LOG_PID, syslog.LOG_MAIL)
    syslog.syslog(message)

..。然后在我的submod0中使用submod0,在submod1中使用mysyslog('submod1', message)。这是我唯一能完成我想做的事的方法吗?

提前谢谢你。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-11-14 18:13:02

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

使用单个日志方法调用级别上的所有参数,可以将该类包装在更高级别,以提供句柄,例如,通过program提供唯一连接,这正是我在这里的最初问题中所指定的。

我只在python3.6和/dev/log的情况下测试了以下代码。它对我有用,但你要冒着风险使用它。

代码语言:javascript
复制
#!/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
票数 0
EN

Stack Overflow用户

发布于 2017-11-11 19:01:53

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

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

这是对我的问题的回答,但这并不理想,因为如果可能的话,我会尽量避免使用logging模块。

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

票数 1
EN

Stack Overflow用户

发布于 2020-06-30 21:09:43

这在Python的syslog中是不可能的。

唯一的选择是

  1. 使用syslog,调用openlog(ident)来切换标识符

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

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

  1. 使用logging.handlers.SysLogHandler

SysLogHandler很不错。您可以使用自己的ident值制作不同的处理程序。它处理格式化。它设置您希望通过它发送消息的任何套接字(UDP、TCP或unix域)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47241356

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档