logstash的tcp input 和 python logging 模块
logstash的 tcp和 syslog input plugin 都是把tcp流直接当做日志数据的; 而 logging模块里的SocketHandler输出的是经过pickle 序列化的,可以参考官方的接收端代码例子:
import pickle import logging import logging.handlers import SocketServer import struct class LogRecordStreamHandler(SocketServer.StreamRequestHandler): """Handler for a streaming logging request. This basically logs the record using whatever logging policy is configured locally. """ def handle(self): """ Handle multiple requests - each expected to be a 4-byte length, followed by the LogRecord in pickle format. Logs the record according to whatever policy is configured locally. """ while True: chunk = self.connection.recv(4) if len(chunk) < 4: break slen = struct.unpack('>L', chunk)[0] chunk = self.connection.recv(slen) while len(chunk) < slen: chunk = chunk + self.connection.recv(slen - len(chunk)) obj = self.unPickle(chunk) record = logging.makeLogRecord(obj) self.handleLogRecord(record) def unPickle(self, data): return pickle.loads(data) def handleLogRecord(self, record): # if a name is specified, we use the named logger rather than the one # implied by the record. if self.server.logname is not None: name = self.server.logname else: name = record.name logger = logging.getLogger(name) # N.B. EVERY record gets logged. This is because Logger.handle # is normally called AFTER logger-level filtering. If you want # to do filtering, do it at the client end to save wasting # cycles and network bandwidth! logger.handle(record) class LogRecordSocketReceiver(SocketServer.ThreadingTCPServer): """ Simple TCP socket-based logging receiver suitable for testing. """ allow_reuse_address = 1 def __init__(self, host='localhost', port=logging.handlers.DEFAULT_TCP_LOGGING_PORT, handler=LogRecordStreamHandler): SocketServer.ThreadingTCPServer.__init__(self, (host, port), handler) self.abort = 0 self.timeout = 1 self.logname = None def serve_until_stopped(self): import select abort = 0 while not abort: rd, wr, ex = select.select([self.socket.fileno()], [], [], self.timeout) if rd: self.handle_request() abort = self.abort def main(): logging.basicConfig( format='%(relativeCreated)5d %(name)-15s %(levelname)-8s %(message)s') tcpserver = LogRecordSocketReceiver() print('About to start TCP server...') tcpserver.serve_until_stopped() if __name__ == '__main__': main()
不过还是可以用logging.StreamHandler直接输出日志数据:
class logging.StreamHandler(stream=None)
Returns a new instance of the StreamHandler class. If stream is specified, the instance will use it for logging output; otherwise, sys.stderr will be used.
import logging,socket from logging.handlers import RotatingFileHandler, SysLogHandler, SocketHandler # StreamHandler直接在logging模块里 #logging.basicConfig(level=logging.DEBUG, # format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', # datefmt='%a, %d %b %Y %H:%M:%S', # filename='/home/ubuntu/zhenghai.tan/pylog/myapp.log', # filemode='w') logging.getLogger('').setLevel(logging.DEBUG) mylogger = logging.getLogger('mylog') host = '172.19.1.143' port = 2015 bufsize = 10240 addr = (host,port) client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(addr) tcplog = logging.StreamHandler(client.makefile()) formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') tcplog.setFormatter(formatter) tcplog.setLevel(logging.DEBUG) mylogger.addHandler(tcplog) mylogger.debug('This is a debug message') mylogger.info('This is a info message') mylogger.warning('This is a warn message')