Last active
April 23, 2020 18:14
-
-
Save mikhail/6850926b76b6fc1a26d4bd3e61876177 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from logging import Handler | |
import logging | |
""" | |
Usage: | |
@log_handler.on_error() | |
def main_function(): | |
log.debug("You won't see this until later") | |
log.info("You'll see this immediately") | |
raise Exeption() | |
""" | |
def on_error(logger=None, target_handler=None, capacity=None, level_override=None): | |
if target_handler is None: | |
target_handler = logging.StreamHandler() | |
if capacity is None: | |
capacity = 100 | |
if level_override is None: | |
level_override = logging.DEBUG | |
target_handler.setLevel(level_override) | |
logger = logging.getLogger('') | |
logger.setLevel(level_override) | |
handler = RecentHandler(capacity, target=target_handler) | |
def decorator(fn): | |
def wrapper(*args, **kwargs): | |
logger.addHandler(handler) | |
caught_exception = False | |
try: | |
return fn(*args, **kwargs) | |
except Exception: | |
caught_exception = True | |
raise | |
finally: | |
if caught_exception: | |
logger.info('', extra={'skip_in_recent': True}) | |
logger.info('### Log Handler caught exception. Flushing logs:', extra={'skip_in_recent': True}) | |
logger.info('', extra={'skip_in_recent': True}) | |
handler.flush() | |
else: | |
handler.close() | |
logger.removeHandler(handler) | |
return wrapper | |
return decorator | |
class RecentHandler(Handler): | |
""" | |
Keeps track of most recent `capacity` number of logs. Only emits them when flush() is called. | |
""" | |
def __init__(self, capacity: int, target: Handler): | |
""" | |
Initialize the handler with the buffer size and a target. | |
""" | |
Handler.__init__(self) | |
self.capacity = capacity | |
self.target = target | |
self.buffer = [] | |
def emit(self, record): | |
"""Append the record instead of emitting it.""" | |
if getattr(record, "skip_in_recent", False): | |
return | |
self.buffer.append(record) | |
if len(self.buffer) > self.capacity: | |
self.buffer.pop(0) | |
def setTarget(self, target: Handler): | |
self.target = target | |
def flush(self): | |
""" | |
Flushing means just sending the buffered records to the target, if there is one. This should be called | |
externally due to some event. | |
The record buffer is also cleared by this operation. | |
""" | |
self.acquire() | |
try: | |
if self.target: | |
for record in self.buffer: | |
self.target.handle(record) | |
self.buffer = [] | |
finally: | |
self.release() | |
def close(self): | |
self.target = None | |
self.buffer = [] | |
self.acquire() | |
try: | |
Handler.close(self) | |
finally: | |
self.release() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment