if record.levelno >= self.level:
self._module._ceph_log(self.format(record))
+class ClusterLogHandler(logging.Handler):
+ def __init__(self, module_inst):
+ super().__init__()
+ self._module = module_inst
+ self.setFormatter(logging.Formatter("%(message)s"))
+
+ def emit(self, record):
+ levelmap = {
+ 'DEBUG': MgrModule.CLUSTER_LOG_PRIO_DEBUG,
+ 'INFO': MgrModule.CLUSTER_LOG_PRIO_INFO,
+ 'WARNING': MgrModule.CLUSTER_LOG_PRIO_WARN,
+ 'ERROR': MgrModule.CLUSTER_LOG_PRIO_ERROR,
+ 'CRITICAL': MgrModule.CLUSTER_LOG_PRIO_ERROR,
+ }
+ level = levelmap[record.levelname]
+ if record.levelno >= self.level:
+ self._module.cluster_log(self._module.module_name,
+ level,
+ self.format(record))
class FileHandler(logging.FileHandler):
def __init__(self, module_inst):
class MgrModuleLoggingMixin(object):
- def _configure_logging(self, mgr_level, module_level, log_to_file):
+ def _configure_logging(self, mgr_level, module_level, cluster_level,
+ log_to_file, log_to_cluster):
self._mgr_level = None
self._module_level = None
self._root_logger = logging.getLogger()
self._unconfigure_logging()
# the ceph log handler is initialized only once
- self._ceph_log_handler = CPlusPlusHandler(self)
+ self._mgr_log_handler = CPlusPlusHandler(self)
+ self._cluster_log_handler = ClusterLogHandler(self)
self._file_log_handler = FileHandler(self)
self.log_to_file = log_to_file
+ self.log_to_cluster = log_to_cluster
+
+ self._root_logger.addHandler(self._mgr_log_handler)
if log_to_file:
self._root_logger.addHandler(self._file_log_handler)
+ if log_to_cluster:
+ self._root_logger.addHandler(self._cluster_log_handler)
self._root_logger.setLevel(logging.NOTSET)
- self._set_log_level(mgr_level, module_level)
+ self._set_log_level(mgr_level, module_level, cluster_level)
+
def _unconfigure_logging(self):
# remove existing handlers:
rm_handlers = [
- h for h in self._root_logger.handlers if isinstance(h, CPlusPlusHandler) or isinstance(h, FileHandler)]
+ h for h in self._root_logger.handlers if isinstance(h, CPlusPlusHandler) or isinstance(h, FileHandler) or isinstance(h, ClusterLogHandler)]
for h in rm_handlers:
self._root_logger.removeHandler(h)
self.log_to_file = False
+ self.log_to_cluster = False
+
+ def _set_log_level(self, mgr_level, module_level, cluster_level):
+ self._cluster_log_handler.setLevel(cluster_level.upper())
- def _set_log_level(self, mgr_level, module_level):
module_level = module_level.upper() if module_level else ''
if not self._module_level:
# using debug_mgr level
if not self._module_level and not module_level:
level = self._ceph_log_level_to_python(mgr_level)
- self.getLogger().warning("setting log level based on debug_mgr: %s (%s)", level, mgr_level)
+ self.getLogger().debug("setting log level based on debug_mgr: %s (%s)", level, mgr_level)
elif self._module_level and not module_level:
level = self._ceph_log_level_to_python(mgr_level)
self.getLogger().warning("unsetting module log level, falling back to "
"debug_mgr level: %s (%s)", level, mgr_level)
elif module_level:
level = module_level
- self.getLogger().warning("setting log level: %s", level)
+ self.getLogger().debug("setting log level: %s", level)
self._module_level = module_level
self._mgr_level = mgr_level
- self._ceph_log_handler.setLevel(level)
+ self._mgr_log_handler.setLevel(level)
self._file_log_handler.setLevel(level)
def _enable_file_log(self):
self.log_to_file = False
self._root_logger.removeHandler(self._file_log_handler)
+ def _enable_cluster_log(self):
+ # enable cluster log
+ self.getLogger().warning("enabling logging to cluster")
+ self.log_to_cluster = True
+ self._root_logger.addHandler(self._cluster_log_handler)
+
+ def _disable_cluster_log(self):
+ # disable cluster log
+ self.getLogger().warning("disabling logging to cluster")
+ self.log_to_cluster = False
+ self._root_logger.removeHandler(self._cluster_log_handler)
+
def _ceph_log_level_to_python(self, ceph_log_level):
if ceph_log_level:
try:
super(MgrStandbyModule, self).__init__(capsule)
self.module_name = module_name
- mgr_level = self.get_ceph_option("debug_mgr")
- log_level = self.get_module_option("log_level")
- self._configure_logging(mgr_level, log_level, False)
-
- # for backwards compatibility
- self._logger = self.getLogger()
-
# see also MgrModule.__init__()
for o in self.MODULE_OPTIONS:
if 'default' in o:
else:
self.MODULE_OPTION_DEFAULTS[o['name']] = str(o['default'])
+ mgr_level = self.get_ceph_option("debug_mgr")
+ log_level = self.get_module_option("log_level")
+ cluster_level = self.get_module_option('log_to_cluster_level')
+ self._configure_logging(mgr_level, log_level, cluster_level,
+ False, False)
+
+ # for backwards compatibility
+ self._logger = self.getLogger()
+
def __del__(self):
self._unconfigure_logging()
self.module_name = module_name
super(MgrModule, self).__init__(py_modules_ptr, this_ptr)
+ for o in self.MODULE_OPTIONS:
+ if 'default' in o:
+ if 'type' in o:
+ # we'll assume the declared type matches the
+ # supplied default value's type.
+ self.MODULE_OPTION_DEFAULTS[o['name']] = o['default']
+ else:
+ # module not declaring it's type, so normalize the
+ # default value to be a string for consistent behavior
+ # with default and user-supplied option values.
+ self.MODULE_OPTION_DEFAULTS[o['name']] = str(o['default'])
+
mgr_level = self.get_ceph_option("debug_mgr")
log_level = self.get_module_option("log_level")
- self._configure_logging(mgr_level, log_level,
- self.get_module_option("log_to_file", False))
+ cluster_level = self.get_module_option('log_to_cluster_level')
+ log_to_file = self.get_module_option("log_to_file")
+ log_to_cluster = self.get_module_option("log_to_cluster")
+ self._configure_logging(mgr_level, log_level, cluster_level,
+ log_to_file, log_to_cluster)
# for backwards compatibility
self._logger = self.getLogger()
# Keep a librados instance for those that need it.
self._rados = None
- for o in self.MODULE_OPTIONS:
- if 'default' in o:
- if 'type' in o:
- # we'll assume the declared type matches the
- # supplied default value's type.
- self.MODULE_OPTION_DEFAULTS[o['name']] = o['default']
- else:
- # module not declaring it's type, so normalize the
- # default value to be a string for consistent behavior
- # with default and user-supplied option values.
- self.MODULE_OPTION_DEFAULTS[o['name']] = str(o['default'])
def __del__(self):
self._unconfigure_logging()
@classmethod
def _register_commands(cls, module_name):
- cls.MODULE_OPTIONS.append(Option(name='log_level', type='str', default="", runtime=True,
- enum_allowed=['info', 'debug', 'critical', 'error', 'warning', '']))
- cls.MODULE_OPTIONS.append(Option(name='log_to_file', type='bool', default=False, runtime=True))
+ cls.MODULE_OPTIONS.append(
+ Option(name='log_level', type='str', default="", runtime=True,
+ enum_allowed=['info', 'debug', 'critical', 'error',
+ 'warning', '']))
+ cls.MODULE_OPTIONS.append(
+ Option(name='log_to_file', type='bool', default=False, runtime=True))
+ if not [x for x in cls.MODULE_OPTIONS if x['name'] == 'log_to_cluster']:
+ cls.MODULE_OPTIONS.append(
+ Option(name='log_to_cluster', type='bool', default=False,
+ runtime=True))
+ cls.MODULE_OPTIONS.append(
+ Option(name='log_to_cluster_level', type='str', default='info',
+ runtime=True,
+ enum_allowed=['info', 'debug', 'critical', 'error',
+ 'warning', '']))
cls.COMMANDS.extend(CLICommand.dump_cmd_list())
# check logging options for changes
mgr_level = self.get_ceph_option("debug_mgr")
module_level = self.get_module_option("log_level")
+ cluster_level = self.get_module_option("log_to_cluster_level")
log_to_file = self.get_module_option("log_to_file", False)
+ log_to_cluster = self.get_module_option("log_to_cluster", False)
- self._set_log_level(mgr_level, module_level)
+ self._set_log_level(mgr_level, module_level, cluster_level)
if log_to_file != self.log_to_file:
if log_to_file:
self._enable_file_log()
else:
self._disable_file_log()
+ if log_to_cluster != self.log_to_cluster:
+ if log_to_cluster:
+ self._enable_cluster_log()
+ else:
+ self._disable_cluster_log()
# call module subclass implementations
self.config_notify()