Skip to content

Commit

Permalink
WIP: Allow configuring logging via ConfigManager
Browse files Browse the repository at this point in the history
  • Loading branch information
llucax committed Dec 9, 2024
1 parent 9820e71 commit 3b29594
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 6 deletions.
18 changes: 15 additions & 3 deletions src/frequenz/sdk/config/_global.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def initialize_config_manager( # pylint: disable=too-many-arguments
/,
*,
force_polling: bool = True,
logging_config_key: str | Sequence[str] | None = "logging",
name: str = "global",
polling_interval: timedelta = timedelta(seconds=5),
wait_for_first_timeout: timedelta = timedelta(seconds=5),
Expand All @@ -37,6 +38,10 @@ def initialize_config_manager( # pylint: disable=too-many-arguments
Args:
config_paths: Paths to the TOML configuration files.
force_polling: Whether to force file polling to check for changes.
logging_config_key: The key to use for the logging configuration. If `None`,
logging configuration will not be managed. If a key is provided, the
manager update the logging configuration whenever the configuration
changes.
name: The name of the config manager.
polling_interval: The interval to poll for changes. Only relevant if
polling is enabled.
Expand All @@ -53,10 +58,11 @@ def initialize_config_manager( # pylint: disable=too-many-arguments
"""
_logger.info(
"Initializing config manager %s for %s with force_polling=%s, "
"polling_interval=%s, wait_for_first_timeout=%s",
"logging_config_key=%s, polling_interval=%s, wait_for_first_timeout=%s",
name,
config_paths,
force_polling,
logging_config_key,
polling_interval,
wait_for_first_timeout,
)
Expand All @@ -69,6 +75,7 @@ def initialize_config_manager( # pylint: disable=too-many-arguments
config_paths,
name=name,
force_polling=force_polling,
logging_config_key=logging_config_key,
polling_interval=polling_interval,
wait_for_first_timeout=wait_for_first_timeout,
auto_start=True,
Expand Down Expand Up @@ -108,14 +115,19 @@ async def shutdown_config_manager(
raise RuntimeError("Config not initialized")

if timeout is None:
_CONFIG_MANAGER.actor.cancel(msg)
_CONFIG_MANAGER.config_actor.cancel(msg)
if _CONFIG_MANAGER.logging_actor:
_CONFIG_MANAGER.logging_actor.cancel(msg)
_logger.info(
"Config manager cancelled, stopping might continue in the background."
)
else:
to_stop = [_CONFIG_MANAGER.config_actor.stop(msg)]
if _CONFIG_MANAGER.logging_actor:
to_stop.append(_CONFIG_MANAGER.logging_actor.stop(msg))
try:
async with asyncio.timeout(timeout.total_seconds()):
await _CONFIG_MANAGER.actor.stop(msg)
await asyncio.gather(*to_stop)
_logger.info("Config manager stopped.")
except asyncio.TimeoutError:
_logger.warning(
Expand Down
21 changes: 18 additions & 3 deletions src/frequenz/sdk/config/_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def __init__( # pylint: disable=too-many-arguments
*,
auto_start: bool = True,
force_polling: bool = True,
logging_config_key: str | Sequence[str] | None = "logging",
name: str | None = None,
polling_interval: timedelta = timedelta(seconds=5),
wait_for_first_timeout: timedelta = timedelta(seconds=5),
Expand All @@ -49,6 +50,10 @@ def __init__( # pylint: disable=too-many-arguments
auto_start: Whether to start the actor automatically. If `False`, the actor
will need to be started manually by calling `start()` on the actor.
force_polling: Whether to force file polling to check for changes.
logging_config_key: The key to use for the logging configuration. If `None`,
logging configuration will not be managed. If a key is provided, the
manager update the logging configuration whenever the configuration
changes.
name: A name to use when creating actors. If `None`, `str(id(self))` will
be used. This is used mostly for debugging purposes.
polling_interval: The interval to poll for changes. Only relevant if
Expand All @@ -66,7 +71,7 @@ def __init__( # pylint: disable=too-many-arguments
)
"""The broadcast channel for the configuration."""

self.actor: Final[ConfigManagingActor] = ConfigManagingActor(
self.config_actor: Final[ConfigManagingActor] = ConfigManagingActor(
config_paths,
self.config_channel.new_sender(),
name=str(self),
Expand All @@ -83,8 +88,17 @@ def __init__( # pylint: disable=too-many-arguments
will be used to wait for the first configuration to be received.
"""

# pylint: disable-next=import-outside-toplevel
from ._logging_actor import LoggingConfigUpdatingActor

self.logging_actor: Final[LoggingConfigUpdatingActor | None] = (
None if logging_config_key is None else LoggingConfigUpdatingActor()
)

if auto_start:
self.actor.start()
self.config_actor.start()
if self.logging_actor:
self.logging_actor.start()

def __repr__(self) -> str:
"""Return a string representation of this config manager."""
Expand All @@ -93,7 +107,8 @@ def __repr__(self) -> str:
f"name={self.name!r}, "
f"wait_for_first_timeout={self.wait_for_first_timeout!r}, "
f"config_channel={self.config_channel!r}, "
f"actor={self.actor!r}>"
f"logging_actor={self.logging_actor!r}, "
f"config_actor={self.config_actor!r}>"
)

def __str__(self) -> str:
Expand Down

0 comments on commit 3b29594

Please sign in to comment.