33
44"""Read and update logging severity from config."""
55
6+ from __future__ import annotations
7+
68import logging
7- from collections .abc import Mapping
89from dataclasses import dataclass , field
9- from typing import Annotated , Any
10+ from typing import Annotated , Sequence
1011
1112import marshmallow
1213import marshmallow .validate
13- from frequenz .channels import Receiver
1414
1515from ..actor import Actor
16- from ._util import load_config
16+ from ._manager import ConfigManager
17+ from ._reconfigurable import Reconfigurable
1718
1819_logger = logging .getLogger (__name__ )
1920
@@ -66,7 +67,7 @@ class LoggingConfig:
6667 """The list of loggers configurations."""
6768
6869
69- class LoggingConfigUpdatingActor (Actor ):
70+ class LoggingConfigUpdatingActor (Actor , Reconfigurable [ LoggingConfig ] ):
7071 """Actor that listens for logging configuration changes and sets them.
7172
7273 Example:
@@ -84,26 +85,12 @@ class LoggingConfigUpdatingActor(Actor):
8485
8586 ```python
8687 import asyncio
87- from collections.abc import Mapping
88- from typing import Any
8988
90- from frequenz.channels import Broadcast
91- from frequenz.sdk.config import LoggingConfigUpdatingActor, ConfigManagingActor
89+ from frequenz.sdk.config import LoggingConfigUpdatingActor
9290 from frequenz.sdk.actor import run as run_actors
9391
9492 async def run() -> None:
95- config_channel = Broadcast[Mapping[str, Any]](name="config", resend_latest=True)
96- actors = [
97- ConfigManagingActor(
98- config_paths=["config.toml"], output=config_channel.new_sender()
99- ),
100- LoggingConfigUpdatingActor(
101- config_recv=config_channel.new_receiver(limit=1)).map(
102- lambda app_config: app_config.get("logging", {}
103- )
104- ),
105- ]
106- await run_actors(*actors)
93+ await run_actors(LoggingConfigUpdatingActor())
10794
10895 asyncio.run(run())
10996 ```
@@ -112,18 +99,24 @@ async def run() -> None:
11299 will be updated as well.
113100 """
114101
102+ # pylint: disable-next=too-many-arguments
115103 def __init__ (
116104 self ,
117105 * ,
118- config_recv : Receiver [Mapping [str , Any ]],
106+ config_key : str | Sequence [str ] = "logging" ,
107+ config_manager : ConfigManager | None = None ,
119108 log_datefmt : str = "%Y-%m-%dT%H:%M:%S%z" ,
120109 log_format : str = "%(asctime)s %(levelname)-8s %(name)s:%(lineno)s: %(message)s" ,
121110 name : str | None = None ,
122111 ):
123112 """Initialize this instance.
124113
125114 Args:
126- config_recv: The receiver to listen for configuration changes.
115+ config_key: The key to use to retrieve the configuration from the
116+ configuration manager. If `None`, the whole configuration will be used.
117+ config_manager: The configuration manager to use. If `None`, the [global
118+ configuration manager][frequenz.sdk.config.get_config_manager] will be
119+ used.
127120 log_datefmt: Use the specified date/time format in logs.
128121 log_format: Use the specified format string in logs.
129122 name: The name of this actor. If `None`, `str(id(self))` will be used. This
@@ -135,15 +128,18 @@ def __init__(
135128 in the application (through a previous `basicConfig()` call), then the format
136129 settings specified here will be ignored.
137130 """
138- self ._config_recv = config_recv
131+ self ._current_config : LoggingConfig = LoggingConfig ()
132+
133+ super ().__init__ (
134+ name = name ,
135+ config_key = config_key ,
136+ config_manager = config_manager ,
137+ config_schema = LoggingConfig ,
138+ )
139139
140140 # Setup default configuration.
141141 # This ensures logging is configured even if actor fails to start or
142142 # if the configuration cannot be loaded.
143- self ._current_config : LoggingConfig = LoggingConfig ()
144-
145- super ().__init__ (name = name )
146-
147143 logging .basicConfig (
148144 format = log_format ,
149145 datefmt = log_datefmt ,
@@ -152,17 +148,11 @@ def __init__(
152148
153149 async def _run (self ) -> None :
154150 """Listen for configuration changes and update logging."""
155- async for message in self ._config_recv :
156- try :
157- new_config = load_config (LoggingConfig , message )
158- except marshmallow .ValidationError :
159- _logger .exception (
160- "Invalid logging configuration received. Skipping config update"
161- )
162- continue
163-
164- if new_config != self ._current_config :
165- self ._update_logging (new_config )
151+ config_receiver = await self .initialize_config (skip_none = False )
152+ async for new_config in config_receiver :
153+ # When we receive None, we want to reset the logging configuration to the
154+ # default
155+ self ._update_logging (new_config or LoggingConfig ())
166156
167157 def _update_logging (self , config : LoggingConfig ) -> None :
168158 """Configure the logging level."""
0 commit comments