kquick / Thespian

Python Actor concurrency library
MIT License
189 stars 24 forks source link

simpleSystemBase logging OK, any multiprocessing base logging config fails #72

Closed barfarkle closed 3 years ago

barfarkle commented 3 years ago

Logging and logging config work fine with the simpleSystemBase. I neglected to do initial testing of logging with any multi-processing base and have enough code written now that I am a bit lost as to why logging config fails with these bases. To be honest, I am new to Thespian and don't really understand what I have to do (besides providing the config parameters) to get logging correctly configured for the multi-processing case.

These error messages are produced whenever an Actor is created. How can I resolve these config issues?

ERROR ActorAddr-(T|:63818) => Actor core.app_manager.AppManager @ ActorAddr-(T|:63818) instantiation exception Traceback (most recent call last): File "C:\Program Files\Python38\lib\logging\config.py", line 642, in configure self.configure_root(root) File "C:\Program Files\Python38\lib\logging\config.py", line 802, in configure_root self.common_logger_config(root, config, incremental) File "C:\Program Files\Python38\lib\logging\config.py", line 783, in common_logger_config logger.removeHandler(h) File "C:\Users\xxxx\.virtualenvs\MLGUI\lib\site-packages\thespian\system\logdirector.py", line 187, in removeHandler raise NotImplementedError('Cannot add logging handlers for Thespian Actors')
NotImplementedError: Cannot add logging handlers for Thespian Actors_

The above exception was the direct cause of the following exception: Traceback (most recent call last): File "C:\Users\xxxx\.virtualenvs\ML_GUI\lib\site-packages\thespian\system\actorManager.py", line 62, in _createInstance actorInst = withPossibleInitArgs(capabilities=self.capabilities, File "C:\Users\xxxx\.virtualenvs\ML_GUI\lib\site-packages\thespian\system\utilis.py", line 334, in create return klass({ k: self.kwargs[k] for k in initsig if k in self.kwargs }) File "D:\Projects\InfoEdgeV2\InfoEdge\core\app_manager.py", line 21, in init self.asys = ActorSystem(ACTOR_SYSTEM_BASE) File "C:\Users\xxxx\.virtualenvs\ML_GUI\lib\site-packages\thespian\actors.py", line 637, in init systemBase = self._startupActorSys( File "C:\Users\xxxx\.virtualenvs\ML_GUI\lib\site-packages\thespian\actors.py", line 662, in _startupActorSys systemBase = thespian.system \ File "C:\Users\xxxx\.virtualenvs\MLGUI\lib\site-packages\thespian\system\simpleSystemBase.py", line 257, in init if logDefs is not False: dictConfig(logDefs or defaultLoggingConfig) File "C:\Program Files\Python38\lib\logging\config.py", line 808, in dictConfig dictConfigClass(config).configure() File "C:\Program Files\Python38\lib\logging\config.py", line 644, in configure raise ValueError('Unable to configure root ' ValueError: Unable to configure root logger**_

Config used (copied from example code):

class actorLogFilter(logging.Filter):
    def filter(self, logrecord):
        return 'actorAddress' in logrecord.__dict__
class notActorLogFilter(logging.Filter):
    def filter(self, logrecord):
        return 'actorAddress' not in logrecord.__dict__
logcfg = { 'version': 1,
           'formatters': {
               'normal': {'format': '%(levelname)-8s %(message)s'},
               'actor': {'format': '%(levelname)-8s %(actorAddress)s => %(message)s'}},
           'filters': { 'isActorLog': { '()': actorLogFilter},
                        'notActorLog': { '()': notActorLogFilter}},
           'handlers': { 'h1': {'class': 'logging.FileHandler',
                                'filename': 'InfoEdge.log',
                                'formatter': 'normal',
                                'filters': ['notActorLog'],
                                'level': logging.INFO},
                         'h2': {'class': 'logging.FileHandler',
                                'filename': 'InfoEdge.log',
                                'formatter': 'actor',
                                'filters': ['isActorLog'],
                                'level': logging.INFO},},
           'loggers' : { '': {'handlers': ['h1', 'h2'], 'level': logging.DEBUG}}
         }

Code:

    asys = ActorSystem(ACTOR_SYSTEM_BASE, logDefs=logcfg)    
    # Fails on actor creation ...
    app_mg_addr = asys.createActor(AppManager, globalName=APP_MANAGER_NAME)
kquick commented 3 years ago

It looks like your AppManager actor itself is trying to register a logging handler or otherwise specify logging configuration, which isn't supported. Since the multiproc system bases create separate processes and the logging from those processes is redirected back to the central location, adding handlers or other logging reconfiguration is disabled from within the Actors themselves.

barfarkle commented 3 years ago

Thanks for the reply. The AppManager actor functions mostly as a registrar for plugin like Actors so they can find each other - no direct logging initialization there.

However, it does initialize a Qt window that serves as a ui root for the app that allows plugins to be activated.

Could there be something in Qt that is also doing logging cofiguration? Seems like a big framework like that would also be doing a lot of logging.

Many questions. I will do some more digging.

Unless someone maybe has seen issues like this with Qt before and knows of a work around?

barfarkle commented 3 years ago

Actually, now that you mention it, is that even a thing: an actor-based GUI with Thespian and PyQt?

kquick commented 3 years ago

I don't have a lot of experience with Python Qt bindings, but I suspect you are going to encounter some difficulties trying to run Qt from within Actors because Qt probably has internal event loops designed to manage the various keyboard, mouse, and screen operations. If that turns out to be t he case, you may be able to achieve it with a single Actor managing all of the Qt activities or with the Actor system handling all non-GUI operations and the Qt managed in the main application.

barfarkle commented 3 years ago

I think you may have found my bug - I was going for latter approach - Qt accessing the Actor system as an external entity and running in the context of the main thread - but appear to have screwed up the implementation details. Will correct and see if cleaner separation fixes the issue. Thanks a lot for your help!