Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/keylabeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ labelMappings:
"part:collections": "part:collections"
"part:datetime": "part:datetime"
"part:docs": "part:docs"
"part:logging": "part:logging"
"part:math": "part:math"
"part:tests": "part:tests"
"part:tooling": "part:tooling"
Expand Down
8 changes: 8 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@
- "examples/**"
- LICENSE

"part:logging":
- changed-files:
- any-glob-to-any-file:
- "src/frequenz/core/logging.py"
- "src/frequenz/core/logging/**"
- "tests/test_logging.py"
- "tests/logging/**"

"part:math":
- changed-files:
- any-glob-to-any-file:
Expand Down
38 changes: 38 additions & 0 deletions src/frequenz/core/logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# License: MIT
# Copyright © 2023 Frequenz Energy-as-a-Service GmbH
Copy link
Contributor

Choose a reason for hiding this comment

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

2024!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should probably remove these copyright years, from the legal perspective they seem to be useless and we always get them wrong, and it makes testing templates harder, as we need to make the test change every year...


"""Logging tools."""

import logging


def get_public_logger(module_name: str) -> logging.Logger:
"""Get a logger for the public module containing the given module name.

* Modules are considered private if they start with `_`.
* All modules inside a private module are also considered private, even if they
don't start with `_`.
* If there is no leading public part, the root logger is returned.

Example:
Here are a few examples of how this function will resolve module names:

* `some.pub` -> `some.pub`
* `some.pub._some._priv` -> `some.pub`
* `some.pub._some._priv.public` -> `some.pub`
* `some.pub._some._priv.public._private` -> `some.pub`
* `_priv` -> `root`

Args:
module_name: The fully qualified name of the module to get the logger for
(normally the `__name__` built-in variable).

Returns:
The logger for the public module containing the given module name.
"""
public_parts: list[str] = []
for part in module_name.split("."):
if part.startswith("_"):
break
public_parts.append(part)
return logging.getLogger(".".join(public_parts))
29 changes: 29 additions & 0 deletions tests/test_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# License: MIT
# Copyright © 2024 Frequenz Energy-as-a-Service GmbH

"""Tests for the log module."""


import pytest

from frequenz.core.logging import get_public_logger


@pytest.mark.parametrize(
"module_name, expected_logger_name",
[
("some.pub", "some.pub"),
("some.pub._some._priv", "some.pub"),
("some.pub._some._priv.public", "some.pub"),
("some.pub._some._priv.public._private", "some.pub"),
("some._priv.pub", "some"),
("_priv.some.pub", "root"),
("some", "some"),
("some._priv", "some"),
("_priv", "root"),
],
)
def test_get_public_logger(module_name: str, expected_logger_name: str) -> None:
"""Test that the logger name is as expected."""
logger = get_public_logger(module_name)
assert logger.name == expected_logger_name