1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- import contextlib
- import logging
- IS_A_HOOK = False
- PAYLOAD_TRUNCATION_INDICATOR = '...\n'
- class Forgetful_buffering_handler(logging.Handler):
- '''
- A buffering log handler that stores log messages in memory, and throws away messages (oldest
- first) once a particular capacity in bytes is reached. But if the given byte capacity is zero,
- don't throw away any messages.
- The given identifier is used to distinguish the instance of this handler used for one monitoring
- hook from those instances used for other monitoring hooks.
- '''
- def __init__(self, identifier, byte_capacity, log_level):
- super().__init__()
- self.identifier = identifier
- self.byte_capacity = byte_capacity
- self.byte_count = 0
- self.buffer = []
- self.forgot = False
- self.setLevel(log_level)
- def emit(self, record):
- message = record.getMessage() + '\n'
- self.byte_count += len(message)
- self.buffer.append(message)
- if not self.byte_capacity:
- return
- while self.byte_count > self.byte_capacity and self.buffer:
- self.byte_count -= len(self.buffer[0])
- self.buffer.pop(0)
- self.forgot = True
- def add_handler(handler):
- '''
- Add the given handler to the global logger.
- '''
- logger = logging.getLogger()
- logger.addHandler(handler)
- logger.setLevel(min(handler.level for handler in logger.handlers))
- def get_handler(identifier):
- '''
- Given the identifier for an existing Forgetful_buffering_handler instance, return the handler.
- Raise ValueError if the handler isn't found.
- '''
- try:
- return next(
- handler
- for handler in logging.getLogger().handlers
- if isinstance(handler, Forgetful_buffering_handler) and handler.identifier == identifier
- )
- except StopIteration:
- raise ValueError(f'A buffering handler for {identifier} was not found')
- def format_buffered_logs_for_payload(identifier):
- '''
- Get the handler previously added to the root logger, and slurp buffered logs out of it to
- send to the monitoring service.
- '''
- try:
- buffering_handler = get_handler(identifier)
- except ValueError:
- # No handler means no payload.
- return ''
- payload = ''.join(message for message in buffering_handler.buffer)
- if buffering_handler.forgot:
- return PAYLOAD_TRUNCATION_INDICATOR + payload
- return payload
- def remove_handler(identifier):
- '''
- Given the identifier for an existing Forgetful_buffering_handler instance, remove it.
- '''
- logger = logging.getLogger()
- with contextlib.suppress(ValueError):
- logger.removeHandler(get_handler(identifier))
- logger.setLevel(min(handler.level for handler in logger.handlers))
|