"""Application Logger. ====================== Creates application logger instance, that will send the logs to Loggly. If config.LOGGER_DSN value is not set, the logs will be sent to stdout. """ import threading import uuid from contextlib import contextmanager from owslogger import logger as ows_logger from notifications_delivery import config app_logger = ows_logger.setup( config.ENVIRONMENT, config.APP_NAME, config.LOGGER_LEVEL, config.APP_NAME, config.APP_VERSION ) # Create a thread-local data space _thread_local = threading.local() def _init_logger(correlation_id=None): """Initialize logger with correlation_id. Args: correlation_id: correlation_id that will be sent along with log record. Returns: logger.OwsLoggingAdapter: instance of OwsLoggingAdapter with correlation_id attached. """ if not correlation_id: correlation_id = str(uuid.uuid1()) message = f'correlation_id ({correlation_id}) created.' else: message = f'correlation_id ({correlation_id}) received.' logger_ = ows_logger.OwsLoggingAdapter(app_logger, { 'correlation_id': correlation_id }) logger_.debug(message) return logger_ class _ProxyLogger: """Proxy class that provide logger with proper correlation id.""" @staticmethod def __get_logger(): if hasattr(_thread_local, 'logger'): logger_ = _thread_local.logger else: logger_ = _init_logger() return logger_ def __getattr__(self, item): return getattr(self.__get_logger(), item) def __dir__(self): return dir(self.__get_logger()) _proxy_logger = _ProxyLogger() @contextmanager def set_correlation_id(correlation_id): """Context manager to set and clear the correlation_id and logger in thread-local storage. Args: correlation_id: correlation_id that will be sent along with log record. """ # Set the correlation_id and logger for the current thread _thread_local.correlation_id = correlation_id _thread_local.logger = _init_logger(correlation_id) try: yield finally: # Clear the correlation_id and logger from thread-local storage delattr(_thread_local, 'correlation_id') delattr(_thread_local, 'logger') def get_current_logger(): """Get logger with a correlation_id attached. Returns: logger.OwsLoggingAdapter: instance of OwsLoggingAdapter with correlation_id attached. """ return _proxy_logger