#!/usr/bin/python3 import threading import asyncio import os import sys LOG_MESSAGE = 0 LOG_ERROR = 1 LOG_WARNING = 2 LOG_DEBUG = 3 class LOG: class singleton(object): loop = asyncio.new_event_loop() lock = threading.Lock() def __init__(self): t = threading.Thread(daemon=True, target=self.loop.run_forever) t.start() def __call__(self): return self singleton = singleton() loop = singleton().loop lock = singleton().lock def __init__(self, level=None, prefix=None, parent=None): if level != None: self.level = level elif parent: self.level = parent.level else: level = LOG_WARNING self.prefix = ''.join(filter(None, [parent and parent.prefix, prefix])) def MESSAGE(self, *args, level=LOG_MESSAGE): if self.level >= level: with self.lock: buf = ' '.join(map(str, args)) while '\n' in buf: line, buf = buf.split('\n', 1) if self.prefix != None: print(self.prefix, end='', file=sys.stderr) print(line, file=sys.stderr, flush=True) if len(buf): if self.prefix != None: print(self.prefix, end='', file=sys.stderr) print(buf, file=sys.stderr, flush=True) def ERROR(self, *args): self.MESSAGE(*args, level=LOG_ERROR) def WARNING(self, *args): self.MESSAGE(*args, level=LOG_WARNING) def DEBUG(self, *args): self.MESSAGE(*args, level=LOG_DEBUG) def makefile(self, level=LOG_WARNING, encoding=None): loop = self.singleton().loop class Reader: def __init__(self, log, fd): self.log = log self.fd = fd self.buf = bytearray() self.mutex = threading.Lock() def decode(b): if encoding == None: return b else: return b.decode(encoding) self.decode = decode def __call__(self): with self.mutex: buf = os.read(self.fd, 4096) self.buf.extend(buf) while True: i = self.buf.find(b'\n') if i < 0: break self.log.MESSAGE(self.decode(self.buf[0:i]), level=level) self.buf = self.buf[i+1:] def flush(self): with self.mutex: while True: buf = os.read(self.fd, 4096) if len(buf) == 0: break self.buf.extend(buf) while True: i = self.buf.find(b'\n') if i < 0: break self.log.MESSAGE(self.decode(self.buf[0:i]), level=level) self.buf = self.buf[i+1:] if len(self.buf) > 0: self.log.MESSAGE(self.decode(self.buf), level=level) class MakeFile: def __init__(self, log): self.rpipe, self.wpipe = os.pipe() self.reader = Reader(log, self.rpipe) loop.add_reader(self.rpipe, self.reader) def fileno(self): return self.wpipe def __del__(self): loop.remove_reader(self.rpipe) os.close(self.wpipe) self.reader.flush() return MakeFile(self)