From: Sage Weil Date: Tue, 25 Feb 2020 19:23:06 +0000 (-0600) Subject: pybind/mgr_module: infrastructure to allow logging to cluster log X-Git-Tag: v15.1.1~212^2~7 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=8ec3b3d3cc7d4c2d2678f460de27ecc8cb07d8fe;p=ceph.git pybind/mgr_module: infrastructure to allow logging to cluster log This is incomplete--a module that wants to opt-in needs to call _enable_cluster_log() and manage the level themselves. Signed-off-by: Sage Weil --- diff --git a/src/pybind/mgr/mgr_module.py b/src/pybind/mgr/mgr_module.py index 05fb74df6a81..6235b67fc7a9 100644 --- a/src/pybind/mgr/mgr_module.py +++ b/src/pybind/mgr/mgr_module.py @@ -420,6 +420,25 @@ class CPlusPlusHandler(logging.Handler): 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): @@ -434,7 +453,8 @@ class FileHandler(logging.FileHandler): 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() @@ -442,25 +462,35 @@ class MgrModuleLoggingMixin(object): 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 @@ -474,19 +504,19 @@ class MgrModuleLoggingMixin(object): 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): @@ -501,6 +531,18 @@ class MgrModuleLoggingMixin(object): 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: @@ -540,13 +582,6 @@ class MgrStandbyModule(ceph_module.BaseMgrStandbyModule, MgrModuleLoggingMixin): 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: @@ -555,6 +590,15 @@ class MgrStandbyModule(ceph_module.BaseMgrStandbyModule, MgrModuleLoggingMixin): 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() @@ -646,10 +690,25 @@ class MgrModule(ceph_module.BaseMgrModule, MgrModuleLoggingMixin): 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() @@ -661,26 +720,27 @@ class MgrModule(ceph_module.BaseMgrModule, MgrModuleLoggingMixin): # 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()) @@ -740,15 +800,22 @@ class MgrModule(ceph_module.BaseMgrModule, MgrModuleLoggingMixin): # 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()