55
66import  logging 
77from  collections .abc  import  Mapping 
8- from  dataclasses  import  field 
9- from  typing  import  Annotated , Any ,  Self ,  cast 
8+ from  dataclasses  import  dataclass ,  field 
9+ from  typing  import  Annotated , Any 
1010
1111import  marshmallow 
1212import  marshmallow .validate 
1313from  frequenz .channels  import  Receiver 
14- from  marshmallow  import  RAISE 
15- from  marshmallow_dataclass  import  class_schema , dataclass 
1614
17- from  frequenz .sdk .actor  import  Actor 
15+ from  ..actor  import  Actor 
16+ from  ._util  import  load_config 
1817
1918_logger  =  logging .getLogger (__name__ )
2019
2423        validate = marshmallow .validate .OneOf (choices = logging .getLevelNamesMapping ())
2524    ),
2625]
26+ """A marshmallow field for validating log levels.""" 
2727
2828
2929@dataclass  
@@ -36,7 +36,6 @@ class LoggerConfig:
3636            "metadata" : {
3737                "description" : "Log level for the logger. Uses standard logging levels." 
3838            },
39-             "required" : False ,
4039        },
4140    )
4241    """The log level for the logger.""" 
@@ -52,7 +51,6 @@ class LoggingConfig:
5251            "metadata" : {
5352                "description" : "Default default configuration for all loggers." ,
5453            },
55-             "required" : False ,
5654        },
5755    )
5856    """The default log level.""" 
@@ -63,27 +61,10 @@ class LoggingConfig:
6361            "metadata" : {
6462                "description" : "Configuration for a logger (the key is the logger name)." 
6563            },
66-             "required" : False ,
6764        },
6865    )
6966    """The list of loggers configurations.""" 
7067
71-     @classmethod  
72-     def  load (cls , configs : Mapping [str , Any ]) ->  Self :  # noqa: DOC502 
73-         """Load and validate configs from a dictionary. 
74- 
75-         Args: 
76-             configs: The configuration to validate. 
77- 
78-         Returns: 
79-             The configuration if they are valid. 
80- 
81-         Raises: 
82-             ValidationError: if the configuration are invalid. 
83-         """ 
84-         schema  =  class_schema (cls )()
85-         return  cast (Self , schema .load (configs , unknown = RAISE ))
86- 
8768
8869class  LoggingConfigUpdatingActor (Actor ):
8970    """Actor that listens for logging configuration changes and sets them. 
@@ -133,31 +114,36 @@ async def run() -> None:
133114
134115    def  __init__ (
135116        self ,
117+         * ,
136118        config_recv : Receiver [Mapping [str , Any ]],
137-         log_format : str  =  "%(asctime)s %(levelname)-8s %(name)s:%(lineno)s: %(message)s" ,
138119        log_datefmt : str  =  "%Y-%m-%dT%H:%M:%S%z" ,
120+         log_format : str  =  "%(asctime)s %(levelname)-8s %(name)s:%(lineno)s: %(message)s" ,
121+         name : str  |  None  =  None ,
139122    ):
140123        """Initialize this instance. 
141124
142125        Args: 
143126            config_recv: The receiver to listen for configuration changes. 
144-             log_format: Use the specified format string in logs. 
145127            log_datefmt: Use the specified date/time format in logs. 
128+             log_format: Use the specified format string in logs. 
129+             name: The name of this actor. If `None`, `str(id(self))` will be used. This 
130+                 is used mostly for debugging purposes. 
146131
147132        Note: 
148133            The `log_format` and `log_datefmt` parameters are used in a call to 
149134            `logging.basicConfig()`. If logging has already been configured elsewhere 
150135            in the application (through a previous `basicConfig()` call), then the format 
151136            settings specified here will be ignored. 
152137        """ 
153-         super ().__init__ ()
154138        self ._config_recv  =  config_recv 
155139
156140        # Setup default configuration. 
157141        # This ensures logging is configured even if actor fails to start or 
158142        # if the configuration cannot be loaded. 
159143        self ._current_config : LoggingConfig  =  LoggingConfig ()
160144
145+         super ().__init__ (name = name )
146+ 
161147        logging .basicConfig (
162148            format = log_format ,
163149            datefmt = log_datefmt ,
@@ -168,7 +154,7 @@ async def _run(self) -> None:
168154        """Listen for configuration changes and update logging.""" 
169155        async  for  message  in  self ._config_recv :
170156            try :
171-                 new_config  =  LoggingConfig . load ( message )
157+                 new_config  =  load_config ( LoggingConfig ,  message )
172158            except  marshmallow .ValidationError :
173159                _logger .exception (
174160                    "Invalid logging configuration received. Skipping config update" 
0 commit comments