def __init__(self, source, name, propagate): """ Initializes the logger """ parent_invoker = inspect.stack()[1] if not __file__.startswith(parent_invoker[1]) or parent_invoker[3] != 'get': raise RuntimeError('Cannot invoke instance from outside this class. Please use LogHandler.get(source, name=None) instead') if name is None: name = 'logger' formatter = OVSFormatter('%(asctime)s - %(hostname)s - %(process)s/%(thread)d - {0}/%(name)s - %(sequence)s - %(levelname)s - %(message)s'.format(source)) target_definition = LogHandler.load_target_definition(source, allow_override=True) if target_definition['type'] == 'redis': from redis import Redis from source.tools.redis_logging import RedisListHandler self.handler = RedisListHandler(queue=target_definition['queue'], client=Redis(host=target_definition['host'], port=target_definition['port'])) elif target_definition['type'] == 'file': self.handler = logging.FileHandler(target_definition['filename']) else: self.handler = logging.StreamHandler(sys.stdout) self.handler.setFormatter(formatter) self.logger = logging.getLogger(name) self.logger.addHandler(self.handler) self.logger.propagate = propagate self.logger.setLevel(getattr(logging, 'DEBUG')) self._key = '{0}_{1}'.format(source, name)
class LogHandler(object): """ Log handler. WARNING: This log handler might be highly unreliable if not used correctly. It can log to redis, but if Redis is not working as expected, it will result in lost log messages. If you want reliable logging, do not use Redis at all or log to files and have a separate process forward them to Redis (so logs can be re-send if Redis is unavailable) """ counter = itertools.count() cache = {} propagate_cache = {} def __init__(self, source, name, propagate): """ Initializes the logger """ parent_invoker = inspect.stack()[1] if not __file__.startswith(parent_invoker[1]) or parent_invoker[3] != 'get': raise RuntimeError('Cannot invoke instance from outside this class. Please use LogHandler.get(source, name=None) instead') if name is None: name = 'logger' formatter = OVSFormatter('%(asctime)s - %(hostname)s - %(process)s/%(thread)d - {0}/%(name)s - %(sequence)s - %(levelname)s - %(message)s'.format(source)) target_definition = LogHandler.load_target_definition(source, allow_override=True) if target_definition['type'] == 'redis': from redis import Redis from source.tools.redis_logging import RedisListHandler self.handler = RedisListHandler(queue=target_definition['queue'], client=Redis(host=target_definition['host'], port=target_definition['port'])) elif target_definition['type'] == 'file': self.handler = logging.FileHandler(target_definition['filename']) else: self.handler = logging.StreamHandler(sys.stdout) self.handler.setFormatter(formatter) self.logger = logging.getLogger(name) self.logger.addHandler(self.handler) self.logger.propagate = propagate self.logger.setLevel(getattr(logging, 'DEBUG')) self._key = '{0}_{1}'.format(source, name) @staticmethod def load_target_definition(source, allow_override=False): logging_target = {'type': 'console'} try: from source.tools.configuration.configuration import Configuration logging_target = Configuration.get('/ovs/framework/logging') except: pass target_type = logging_target.get('type', 'console') if allow_override is True and 'OVS_LOGTYPE_OVERRIDE' in os.environ: target_type = os.environ['OVS_LOGTYPE_OVERRIDE'] if target_type == 'redis': queue = logging_target.get('queue', '/ovs/logging') if '{0}' in queue: queue = queue.format(source) return {'type': 'redis', 'queue': '/{0}'.format(queue.lstrip('/')), 'host': logging_target.get('host', 'localhost'), 'port': logging_target.get('port', 6379)} if target_type == 'file': return {'type': 'file', 'filename': LogHandler.load_path(source)} return {'type': 'console'} @staticmethod def get_sink_path(source, allow_override=False): target_definition = LogHandler.load_target_definition(source, allow_override) if target_definition['type'] == 'redis': sink = 'redis://{0}:{1}{2}'.format(target_definition['host'], target_definition['port'], target_definition['queue']) elif target_definition['type'] == 'file': sink = target_definition['filename'] else: sink = 'console:' return sink @staticmethod def load_path(source): log_path = '/var/log/asd-manager' log_filename = '{0}/{1}.log'.format(log_path, source) if not os.path.exists(log_path): os.mkdir(log_path, 0777) if not os.path.exists(log_filename): open(log_filename, 'a').close() os.chmod(log_filename, 0o666) return log_filename @staticmethod def get(source, name=None, propagate=False): key = '{0}_{1}'.format(source, name) if key not in LogHandler.cache: logger = LogHandler(source, name, propagate) LogHandler.cache[key] = logger if key not in LogHandler.propagate_cache: LogHandler.propagate_cache[key] = propagate return LogHandler.cache[key] def _fix_propagate(self): """ Obey propagate flag as initially called - celery will overwrite it to catch the logging """ propagate = LogHandler.propagate_cache.get(self._key, None) if propagate is not None: self.logger.propagate = propagate def _log(self, msg, severity, *args, **kwargs): """ Log pass-through """ self._fix_propagate() if 'print_msg' in kwargs: del kwargs['print_msg'] print msg extra = kwargs.get('extra', {}) extra['hostname'] = socket.gethostname() extra['sequence'] = LogHandler.counter.next() kwargs['extra'] = extra try: return getattr(self.logger, severity)(msg, *args, **kwargs) except: pass def info(self, msg, *args, **kwargs): """ Info """ return self._log(msg, 'info', *args, **kwargs) def error(self, msg, *args, **kwargs): """ Error """ return self._log(msg, 'error', *args, **kwargs) def debug(self, msg, *args, **kwargs): """ Debug """ return self._log(msg, 'debug', *args, **kwargs) def warning(self, msg, *args, **kwargs): """ Warning """ return self._log(msg, 'warning', *args, **kwargs) def log(self, msg, *args, **kwargs): """ Log """ return self._log(msg, 'log', *args, **kwargs) def critical(self, msg, *args, **kwargs): """ Critical """ return self._log(msg, 'critical', *args, **kwargs) def exception(self, msg, *args, **kwargs): """ Exception """ return self._log(msg, 'exception', *args, **kwargs)