Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fix configuring loggers found in 'PREFECT_LOGGING_EXTRA_LOGGERS' #16652

Merged
merged 1 commit into from
Jan 21, 2025

Conversation

estasney
Copy link
Contributor

@estasney estasney commented Jan 8, 2025

Each logger defined in 'PREFECT_LOGGING_EXTRA_LOGGERS' now has their level set according to the 'prefect.extra' level. Previously, this only occurred when their level was NOTSET.

Additionally, avoid configuring the logger 'level' and 'propagate' values while iterating over 'extra_config.handlers'

closes #15370

Checklist

  • This pull request references any related issue by including "closes <link to issue>"
    • If no issue exists and your change is not a small fix, please create an issue first.
  • If this pull request adds new functionality, it includes unit tests that cover the changes
  • If this pull request removes docs files, it includes redirect settings in mint.json.
  • If this pull request adds functions or classes, it includes helpful docstrings.

@github-actions github-actions bot added the bug Something isn't working label Jan 8, 2025
Copy link

codspeed-hq bot commented Jan 8, 2025

CodSpeed Performance Report

Merging #16652 will not alter performance

Comparing estasney:fix-configuring-extra-loggers (d8d196d) with main (6b560c8)

Summary

✅ 2 untouched benchmarks

@j-carson
Copy link

j-carson commented Jan 9, 2025

I added a note to the issue, but this was not the change I wanted to do -- I wanted the level to be set on the handler which prefect owns and creates in this function, not on the logger, which belongs to some other library and may have other handlers on it.

for handler in extra_config.handlers:
if not config["incremental"]:
logger.addHandler(handler)
if logger.level == logging.NOTSET:
logger.setLevel(extra_config.level)
logger.propagate = extra_config.propagate

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it not work if this code were changed to:

handler.setLevel(extra_config.level) instead of logger.setLevel(extra_config.level) ?

Again, my motivation on creating the original issue is that non-prefect libraries may not know about the "extra_config.level" parameter and may have other mechanisms for setting up their own logging config. IMO, Prefect's handler should be more like an add on not a replacement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets assume we're using the logging.yml prefect uses. I'm also assuming non-prefect libraries follow the logging guidelines (IME most do) Python Logging

A library will typically do

logger.debug('User doesn't care about this')
logger.warning('User care's about this')

If I run a flow, I'll see the warning in the prefect ui, but not the debug. debug > notset. Assuming above, the libraries logger does not have its level set and defers to the root logger (warning).

What I'm proposing won't interfere with libraries logging config. It will only adjust how the user (us) receive them

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what if the handler set up by prefect isn't the only handler?

This issue came about because my library can create two handlers -- one at level debug to write to a log file and one at level warning to write to the console.

So for logger = logging.getLogger("myLib")

logger.debug - goes to one handler

logger.warning - matches two handlers

I was trying to make my prefect UI logger match what my console logger does today. The way I achieve that right now is:

logger.setLevel('debug')
for each handler in logger.getHandlers(), search for prefect's handler
handler.addFilter(my_filter_function)

where my_filter_function does not forward the debug level stuff up to the UI

This hack is dependent on the order in which library imports happen - because the parent level logger could be set by prefect or by my library depending on who's initializer runs first.

In my opinion, the prefect "extra logging level" should configure only prefect's handler object, not to the entire logger object.

Copy link
Collaborator

@zzstoatzz zzstoatzz Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @estasney and @j-carson for articulating your positions!

After chatting a bit with @desertaxle, we agree we're doing the wrong thing by modifying external loggers' levels. We should probably only configure our own handlers:

# In setup_logging():
for logger_name in PREFECT_LOGGING_EXTRA_LOGGERS.value():
    logger = logging.getLogger(logger_name)
    for handler in extra_config.handlers:
        if not config["incremental"]:
            handler.setLevel(extra_config.level)  # Only set level on our handler
            logger.addHandler(handler)
        logger.propagate = extra_config.propagate

This would technically be a breaking change but it's arguably more correct - we should only configure our own handlers, not override library logging levels.

What do you think @estasney? (sounds like this is what you were opting for @j-carson - feel free to correct me)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as a side note, please use pre-commit install before your next commit to avoid the static analysis errors

https://docs.prefect.io/contribute/dev-contribute#install-prefect-for-development

Copy link
Contributor Author

@estasney estasney Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@j-carson I see your point, and this is an interesting problem. I suppose my perspective was more geared towards favoring logging logic being defined in the deployment vs in code. I will remove the bit about setting external loggers.

@zzstoatzz Thanks for reviewing! Just want to point out that

handler.setLevel(extra_config.level)

May appear to cause side effects

  api:
    level: 0  
    class: prefect.logging.handlers.APILogHandler
    
  prefect.extra:
    level: "${PREFECT_LOGGING_LEVEL}"
    handlers: [api]
    propagate: false  

But would effectively become (after running setup_logging)

  api:
    level: "${PREFECT_LOGGING_LEVEL}" 
    class: prefect.logging.handlers.APILogHandler
    
  prefect.extra:
    level: "${PREFECT_LOGGING_LEVEL}"
    handlers: [api]
    propagate: false  

If the goal is not to modify the level of external loggers should we also extend that to the propagate property? I.e. don't modify external loggers propagate

Sorry I missed the pre-commit install I'll fix that now

I'll move this a draft PR as I also want to add a test

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zzstoatzz Yes, this is what I was asking for

@estasney estasney marked this pull request as draft January 17, 2025 19:54
…ed in 'PREFECT_LOGGING_EXTRA_LOGGERS'.

Previously the log level was set to `extra_config.level` if the logger's level was == `NOTSET`. Additionally, its propagate property was always set to extra.config.propagate.
This could lead to undesired behavior.

Add test `test_setup_logging_extra_loggers_does_not_modify_external_logger_level`
small optimization to check if config is incremental once vs per handler

Resolves PrefectHQ#15370
@estasney estasney force-pushed the fix-configuring-extra-loggers branch from 36ce093 to d8d196d Compare January 18, 2025 22:07
@estasney estasney marked this pull request as ready for review January 18, 2025 22:08
@estasney
Copy link
Contributor Author

Added test_setup_logging_extra_loggers_does_not_modify_external_logger_level
Squashed the commits and merges from main
Removed logger.propagate = extra_config.propagate since this would be mutating an external logger which is not desired

Copy link
Collaborator

@zzstoatzz zzstoatzz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you @estasney - nice test!

@zzstoatzz zzstoatzz merged commit 35f6cf4 into PrefectHQ:main Jan 21, 2025
45 checks passed
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working
Projects
None yet
3 participants