949 separate logging for callbacks#958
Conversation
DominicOram
left a comment
There was a problem hiding this comment.
- When I run
pytest -m "not s03" -sI get multiple copies of logs printed. Have we got multiple handlers added? e.g.
[2023-11-09 15:19:37,488] bluesky.RE.state run_engine INFO: Change state on <bluesky.run_engine.RunEngine object at 0x7fac701ccb80> from 'idle' -> 'running'
[2023-11-09 15:19:37,488] bluesky.RE.state run_engine INFO: Change state on <bluesky.run_engine.RunEngine object at 0x7fac701ccb80> from 'idle' -> 'running'
[2023-11-09 15:19:37,488] bluesky.RE.state run_engine INFO: Change state on <bluesky.run_engine.RunEngine object at 0x7fac701ccb80> from 'idle' -> 'running'
[2023-11-09 15:19:37,488] bluesky.RE.state run_engine INFO: Change state on
...
- Must: If we merge this the setup of
ISYB_LOGGERandNEXUS_LOGGERnever gets called in prod so we won't get any logs from them. I know this is probably fixed in subsequent PRs when we move it to a separate process but I think it's good practice formainto not be broken between PRs - It feels like either:
NEXUS_LOGGER/ISPYB_LOGGERare sufficiently separate that they should live in with the nexus/ispyb callback code- We should have a helper list/dict in
log.pythat contains all LOGGERs for setup/teardown of tests
| if "hyperion.log" in sys.modules: | ||
| hyperion_log = sys.modules["hyperion.log"] | ||
| [h.close() for h in hyperion_log.LOGGER.handlers] | ||
| [hyperion_log.LOGGER.removeHandler(h) for h in hyperion_log.LOGGER.handlers] | ||
| if "dodal.log" in sys.modules: | ||
| dodal_log = sys.modules["dodal.log"] | ||
| [h.close() for h in dodal_log.LOGGER.handlers] | ||
| [dodal_log.LOGGER.removeHandler(h) for h in dodal_log.LOGGER.handlers] |
There was a problem hiding this comment.
Should: Pull this into a shared function
| "hyperion_ispyb_callback.txt", | ||
| ISPYB_LOGGER, | ||
| "DEBUG", | ||
| True, # TODO set dev mode for tests and remove this |
There was a problem hiding this comment.
Must: Is this todo addressed in a different PR? Feels like we shouldn't be doing this here...
| log.LOGGER.handlers.clear() | ||
| log.ISPYB_LOGGER.handlers.clear() | ||
| log.NEXUS_LOGGER.handlers.clear() | ||
| dodal_logger.handlers.clear() |
There was a problem hiding this comment.
Nit: I would put these in a list and clear them all with list comprehension, you can do the same below after the with too
| def set_up_callback_logging_handlers( | ||
| filename, | ||
| logger=LOGGER, | ||
| logging_level: str = "INFO", | ||
| dev_mode: bool = False, | ||
| ): | ||
| stream_handler = logging.StreamHandler() | ||
| _add_handler(logger, stream_handler, logging_level) | ||
| graylog_handler = set_up_graylog_handler(logging_level, dev_mode, logger) | ||
| file_handler = set_up_file_handler( | ||
| logging_level, dev_mode, _get_logging_file_path(filename), logger | ||
| ) | ||
| logger.addFilter(dc_group_id_filter) | ||
| return [stream_handler, graylog_handler, file_handler] |
There was a problem hiding this comment.
Should: What am I missing here that means we can't use dodal's set_up_logging_handlers?
|
Good point - do you think we should separate the repositories at some stage? If so I'll move the loggers to be with the modules. I did set up the ISPYB logger in the ispyb callback class, but this made me reconsider - yes, better to set them up in main, and then move them to the new main for the callbacks |
Codecov Report
@@ Coverage Diff @@
## main #958 +/- ##
==========================================
- Coverage 93.32% 93.26% -0.07%
==========================================
Files 54 54
Lines 2591 2597 +6
==========================================
+ Hits 2418 2422 +4
- Misses 173 175 +2
📣 Codecov offers a browser extension for seamless coverage viewing on GitHub. Try it in Chrome or Firefox today! |
DominicOram
left a comment
There was a problem hiding this comment.
Great, thanks for cleaning up the types as you went too. Nits in code, take them or leave them
| hyperion.log.set_up_logging_handlers( | ||
| logging_level=logging_level, dev_mode=bool(dev_mode) | ||
| ) | ||
| hyperion.log.set_up_logging_handlers( | ||
| logging_level=logging_level, | ||
| dev_mode=dev_mode, | ||
| filename="hyperion_ispyb_callback.txt", | ||
| logger=hyperion.log.ISPYB_LOGGER, | ||
| ) | ||
| hyperion.log.set_up_logging_handlers( | ||
| logging_level=logging_level, | ||
| dev_mode=dev_mode, | ||
| filename="hyperion_nexus_callback.txt", | ||
| logger=hyperion.log.NEXUS_LOGGER, | ||
| ) |
There was a problem hiding this comment.
Nit: I would do this with dictionary comprehension, but likely going to change soon when moved to separate processes anyway so big deal
| for logger in loggers: | ||
| for handler in logger.handlers: | ||
| handler.close() | ||
| [logger.handlers.clear() for logger in loggers] |
There was a problem hiding this comment.
Nit: You're running the for loop anyway, just move this into there and remove the list comprehension
| if LOGGER.handlers == []: | ||
| if dodal_logger.handlers == []: | ||
| print(f"Initialising Hyperion logger for tests at {log_level}") | ||
| set_up_logging_handlers(LOGGER, log_level, True) | ||
| if ISPYB_LOGGER.handlers == []: | ||
| print(f"Initialising ISPyB logger for tests at {log_level}") | ||
| set_up_logging_handlers( | ||
| logging_level=log_level, | ||
| dev_mode=True, | ||
| filename="hyperion_ispyb_callback.txt", | ||
| logger=ISPYB_LOGGER, | ||
| ) | ||
| if NEXUS_LOGGER.handlers == []: | ||
| print(f"Initialising nexus logger for tests at {log_level}") | ||
| set_up_logging_handlers( | ||
| logging_level=log_level, | ||
| dev_mode=True, | ||
| filename="hyperion_nexus_callback.txt", | ||
| logger=NEXUS_LOGGER, | ||
| ) |
There was a problem hiding this comment.
Nit: I would do this with dictionary comprehension
| If the HYPERION_LOG_DIR environment variable exists then logs will be put in here. | ||
|
|
||
| If no envrionment variable is found it will default it to the tmp/dev directory. | ||
| If no envrionment variable is found it will default it to the ./tmp/dev directory. |
There was a problem hiding this comment.
Nit: Spelling on environment
| else: | ||
| logging_path = Path("./tmp/dev/") | ||
|
|
||
| logging_path = Path(environ.get("HYPERION_LOG_DIR") or "./tmp/dev/") |
There was a problem hiding this comment.
This is beautiful, thanks!
| assert nexus_filehandler.baseFilename != hyperion_filehandler.baseFilename # type: ignore | ||
| assert ispyb_filehandler.baseFilename != hyperion_filehandler.baseFilename # type: ignore | ||
| assert ispyb_filehandler.baseFilename != nexus_filehandler.baseFilename # type: ignore |
There was a problem hiding this comment.
Nit: I would maybe do an explicit cast to FileHandler but not that big a deal
I think we should stay open to needing to but no need to now |
Fixes #949
Link to dodal PR (if required): #228
To test: