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)