Skip to content

pybind/mgr/mgr_module: isolate logging per mgr module#67327

Open
NitzanMordhai wants to merge 3 commits intoceph:mainfrom
NitzanMordhai:wip-nitzan-mgr-module-logger-with-main-interpreter
Open

pybind/mgr/mgr_module: isolate logging per mgr module#67327
NitzanMordhai wants to merge 3 commits intoceph:mainfrom
NitzanMordhai:wip-nitzan-mgr-module-logger-with-main-interpreter

Conversation

@NitzanMordhai
Copy link
Contributor

@NitzanMordhai NitzanMordhai commented Feb 12, 2026

After PR #66244, all mgr modules run inside the same Python interpreter.
That means they also share the same logging subsystem.
Previously, each module attached its handlers to the root logger. In practice,
whichever module initialized logging last effectively “owned” the root logger,
and log messages from other modules could end up attributed incorrectly.

This change scopes logging per module. Each module now registers its handlers
on a dedicated logger named after the module itself, with propagate=False to avoid
leaking messages into the root logger.

Now, the getLogger() default (no args) returns the module's named logger
rather than the root logger. This ensures self.log routes correctly.

Fixes: https://tracker.ceph.com/issues/74848

Contribution Guidelines

  • To sign and title your commits, please refer to Submitting Patches to Ceph.

  • If you are submitting a fix for a stable branch (e.g. "quincy"), please refer to Submitting Patches to Ceph - Backports for the proper workflow.

  • When filling out the below checklist, you may click boxes directly in the GitHub web UI. When entering or editing the entire PR message in the GitHub web UI editor, you may also select a checklist item by adding an x between the brackets: [x]. Spaces and capitalization matter when checking off items this way.

Checklist

  • Tracker (select at least one)
    • References tracker ticket
    • Very recent bug; references commit where it was introduced
    • New feature (ticket optional)
    • Doc update (no ticket needed)
    • Code cleanup (no ticket needed)
  • Component impact
    • Affects Dashboard, opened tracker ticket
    • Affects Orchestrator, opened tracker ticket
    • No impact that needs to be tracked
  • Documentation (select at least one)
    • Updates relevant documentation
    • No doc update is appropriate
  • Tests (select at least one)
Show available Jenkins commands

You must only issue one Jenkins command per-comment. Jenkins does not understand
comments with more than one command.

@NitzanMordhai NitzanMordhai force-pushed the wip-nitzan-mgr-module-logger-with-main-interpreter branch from d9c9e68 to 8583df5 Compare February 12, 2026 10:56
Copy link
Contributor

@athanatos athanatos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The larger problem is that there's a ton of code across multiple modules that doesn't actually use MgrModule.getLogger() to get a logger instance. They directly call logger.getLogger(name) to get a logger named based on the file in which they are defined. This worked before because each module init set a filter on the root logger which in turn applied to every logger.

To make matters worse, those callers don't necessarily have references to the module itself, so there's really no way to call MgrModule.getLogger. I think the solution needs to be generating a logger attached to each MgrModule subclass (type, not instance), which can then be referenced at import time in the other files in the same package.

See below, this should work.

self._root_logger.addHandler(self._mgr_log_handler)
root = logging.getLogger()
if not any(isinstance(h, CPlusPlusHandler) for h in root.handlers):
root.addHandler(CPlusPlusHandler(self))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will cause anything logged to the root logger to be formatted with the name of the first module to start up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@athanatos, now I'm using MgrRootHandler, so the first module name won't show. It will show instead 'mgr' at the beginning, for example:

2026-02-15T12:29:35.770+0000 7eff29af1640  0 [prometheus ERROR prometheus] Failed to get SMB metadata: No orchestrator configured (try `ceph orch set backend`)
2026-02-15T12:29:35.770+0000 7eff29af1640  0 [prometheus ERROR prometheus] Failed to collect cephadm daemon status: No orchestrator configured (try `ceph orch set backend`)
2026-02-15T12:29:35.781+0000 7eff1820e640  0 [mgr INFO mgr] scanning for idle connections..
2026-02-15T12:29:35.781+0000 7eff1820e640  0 [mgr INFO mgr] cleaning up connections: []
2026-02-15T12:29:35.781+0000 7eff17a0d640  0 [mgr INFO mgr] scanning for idle connections..

def getLogger(self, name: Optional[str] = None) -> logging.Logger:
if name is None:
return logging.getLogger(self.module_name)
return logging.getLogger(name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, if name is not None, getLogger(name) will return a logger nested under the root logger, but not necessarily under this module's logger. I'd suggest returning either self._module_logger or self._module_logger.getChild(name).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@NitzanMordhai
Copy link
Contributor Author

@athanatos i'm using propagate=false and logging.getLogger(name) should propagate to the correct logger that was created during _configure_logging for the specific module.
did you mean that the problem is with logging.getLogger() ?

@athanatos
Copy link
Contributor

athanatos commented Feb 12, 2026

@athanatos i'm using propagate=false and logging.getLogger(name) should propagate to the correct logger that was created during _configure_logging for the specific module. did you mean that the problem is with logging.getLogger() ?

Oh! __name__ is the fully qualified name. Yeah, this should work. Apologies, your solution is much simpler and more elegant than what I'd been considering.

@NitzanMordhai NitzanMordhai force-pushed the wip-nitzan-mgr-module-logger-with-main-interpreter branch from 8583df5 to fd8b2b7 Compare February 15, 2026 12:23
@NitzanMordhai
Copy link
Contributor Author

jenkins test make check

@NitzanMordhai
Copy link
Contributor Author

jenkins test make check arm64

@nizamial09
Copy link
Member

@NitzanMordhai i was testing the latest image and i seee

Feb 27 03:28:02 ceph-node-00 ceph-mgr[2264]: [mgr DEBUG mgr] [192.168.100.1:39790] [GET] [admin] /api/multi-cluster/get_config

which is wrong. its a dashboard log and not a DEBUG one either (probably INFO) but its coming as mgr..

@NitzanMordhai
Copy link
Contributor Author

which is wrong. its a dashboard log and not a DEBUG one either (probably INFO) but its coming as mgr..

We are going to have an issue with getlogger like:
logger = logging.getLogger('controllers.multi_cluster')

Since we are now depending on a logger per module, we need to know from which module that logger was requested, and we didn't specify any, so we will route to the root logger (which is mgr logger)

@NitzanMordhai NitzanMordhai force-pushed the wip-nitzan-mgr-module-logger-with-main-interpreter branch from fd8b2b7 to ac02bbb Compare March 1, 2026 15:21
@nizamial09
Copy link
Member

we need to know from which module that logger was requested

we do like logger = logging.getLogger(__name__) in most of our controller/ files and maybe other places too. should we have to do something else in the modules to make it log the name properly?

@NitzanMordhai
Copy link
Contributor Author

@nizamial09 since we are using propagate=true, you can add the module name to the beginning of the name, it will then route to the correct logger https://docs.python.org/3/library/logging.html#logging.Logger.propagate

@nizamial09
Copy link
Member

okay, so you mean something like logger = logging.getLogger(f"dashboard.{__name__}")?

@NitzanMordhai
Copy link
Contributor Author

okay, so you mean something like logger = logging.getLogger(f"dashboard.{__name__}")?

name already have dashboard if i understand correctly, but if you want to keep:
logger = logging.getLogger('controllers.multi_cluster')

then something like:
logger = logging.getLogger('dashboard.controllers.multi_cluster')

After PR ceph#66244, all mgr modules run inside the same Python interpreter.
That means they also share the same logging subsystem.
Previously, each module attached its handlers to the root logger. In practice,
whichever module initialized logging last effectively “owned” the root logger,
and log messages from other modules could end up attributed incorrectly.

This change scopes logging per module. Each module now registers its handlers
on a dedicated logger named after the module itself, with propagate=False to avoid
leaking messages into the root logger.

Now, the getLogger() default (no args) returns the module's named logger
rather than the root logger. This ensures self.log routes correctly.

Fixes: https://tracker.ceph.com/issues/74848
Signed-off-by: Nitzan Mordechai <nmordech@ibm.com>
Fixes: https://tracker.ceph.com/issues/74848
Signed-off-by: Nitzan Mordechai <nmordech@ibm.com>
Previously, using a hard-coded logger name like 'rgw_client' created
a top-level logger that bypassed the 'mgr.dashboard' hierarchy.
By switching to __name__, we ensure the logger identity follows the
package structure (e.g., 'mgr.dashboard.services.rgw_client').

Since propagate=True is enabled, this allows log records to flow
upward through the 'mgr' parent loggers, ensuring they are correctly
captured, formatted, and attributed to the dashboard module rather than
falling back to the root logger.

Fixes: https://tracker.ceph.com/issues/74848
Signed-off-by: Nitzan Mordechai <nmordech@ibm.com>
@NitzanMordhai NitzanMordhai force-pushed the wip-nitzan-mgr-module-logger-with-main-interpreter branch from ac02bbb to 8c0f0d5 Compare March 3, 2026 12:27
@NitzanMordhai NitzanMordhai requested a review from a team as a code owner March 3, 2026 12:27
@github-project-automation github-project-automation bot moved this from New to Review in progress in Ceph-Dashboard Mar 3, 2026
@NitzanMordhai NitzanMordhai requested a review from nizamial09 March 3, 2026 12:28
@NitzanMordhai
Copy link
Contributor Author

@nizamial09 please check the new commit for changing the dashboard logging

Copy link
Member

@nizamial09 nizamial09 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woah! I honestly thought we were using __name__ across the dashboard getLogger() but i was wrong then. Thanks for taking care of that @NitzanMordhai

@batrick
Copy link
Member

batrick commented Mar 6, 2026

This PR is under test in https://tracker.ceph.com/issues/75377.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Review in progress

Development

Successfully merging this pull request may close these issues.

4 participants