""" Context ====== The purpose of Context is to provide a message-level context. For each message taken from the queue, a Context should be created with the correlation_id in that message. Context also provides a LoggerAdapter, which automatically includes the correlation_id in logs. Example: context.reset() # always reset context.set('correlation_id', 'test_fp_correlation_id') context.logger.info("test fp log message") """ import json import logging import sys from fpcapture import config from fpcapture.connectors.logger import DSNHandler logger = logging.getLogger(config.SERVICE_NAME) logger.setLevel(config.LOGGER_LEVEL) if config.environment in (config.TEST_ENVIRONMENT, config.DEV_ENVIRONMENT): # in TEST and DEV environments, log to STDOUT ch = logging.StreamHandler(sys.stdout) # console handler payload = { 'level': '%(levelname)s', 'correlation_id': '%(correlation_id)s', 'message': '%(message)s', } formatter = logging.Formatter(json.dumps(payload)) ch.setFormatter(formatter) logger.addHandler(ch) else: # in QA and Prod environments, log to DSN logger.addHandler(DSNHandler(config.LOGGER_DSN)) class Context(): def set(self, name, value): """Set an attribute of the context Args: name (str): name of attribute to set value: value to set attribute to """ setattr(self, name, value) def reset(self): """Reset all attributes of the context """ variables = vars(self) for i in variables.keys(): variables[i] = None def get_correlation_id(self): """Get the Correlation ID. Raise an AttributeError if context has no correlation_id set """ cid = getattr(self, 'correlation_id', None) if cid is not None: return cid else: raise AttributeError("Context has no correlation_id") @property def logger(self): """Get a logger with a context. The context provides additional information (such as the correlation_id) """ extra = dict(correlation_id=self.get_correlation_id()) return logging.LoggerAdapter(logger=logger, extra=extra) context = Context()