Add a custom log handler and GUI viewer with filters - #6900
Conversation
| 'viewer': ['Viewer', 'current_viewer'], | ||
| } | ||
|
|
||
| _LOG_STREAM = _get_custom_log_stream() |
There was a problem hiding this comment.
I think that custom log handler should be initialized in napari.qt.qt_event_loop, same as notification manager.
There was a problem hiding this comment.
But the logger should work regardless of qt right? Also headless it would be useful.
There was a problem hiding this comment.
As I understand, it is log handler, not logger. The current code means, that each time one import napari it starts storing all logs in memory, even without a clean way to show them.
There was a problem hiding this comment.
Yes... but isn't that what we want? Would be good to be able to get these logs programmatically as well. We can also discard old logs if we go above a certain size.
There was a problem hiding this comment.
My personal feeling is that we should do this, like with notifications (warnigs), but I may be wrong.
There was a problem hiding this comment.
do what? I'm not sure I follow ^^'
| logger = logging.getLogger('napari') | ||
| logger.setLevel(logging.DEBUG) | ||
| logger.addHandler(handler) |
There was a problem hiding this comment.
It will be nice to connect to all loggers and be able to filter messages based on logger (so someone could filter logs only from a given plugin logger.
There was a problem hiding this comment.
True... I'm not sure how to do that though; I guess we somehow get the root logger? And btw, is there a way to get these logging parameters (level, thread, etc) "raw" instead of formatting to string and then de-formatting?
There was a problem hiding this comment.
EDIT: I changed to use the root logger and filter for napari by default. Probably less finnicky than registering specific plugins.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6900 +/- ##
==========================================
- Coverage 92.98% 92.94% -0.05%
==========================================
Files 635 641 +6
Lines 59857 60213 +356
==========================================
+ Hits 55661 55963 +302
- Misses 4196 4250 +54 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
1fa93cc to
eadaca2
Compare
|
This is starting to look fun. Try with this: import logging
logger = logging.getLogger()
logger.setLevel('DEBUG')
import napari
v = napari.Viewer()
logging.getLogger('napari').debug('some debug info')
logging.getLogger('napari.something').warning('this will show (sublogger of napari)')
logging.getLogger('napari-plugin').warning('will would also show, if napari-plugin was registered')
logging.getLogger('other-logger').warning('will not show!')
logging.getLogger('napari').error('very important!')Then open the log from the help menu: napari_logger.mp4 |
|
Main things that I don't know how to deal with:
|
|
@psobolewskiPhD I'm sure you'll like this :P |
# References and relevant issues Followup to napari/docs#463 # Description It looks like the condition from napari/docs#463 was never triggered, as base workflow in repository was triggered only by push to main branch, not on tag.
…nd add special for Windows (napari#7119) # References and relevant issues fix failing napari#7045 # Description Since 2024 July 1 there are wheels for PyQt5-Qt5, not only for macOS, but also for linux https://pypi.org/project/PyQt5-Qt5/#files It means that our pinning, that is calculated on linux, no longer works for windows runners. This PR removes the special case for macOS, and introduce it for Windows. --------- Co-authored-by: Peter Sobolewski <76622105+psobolewskiPhD@users.noreply.github.com>
This SO question and answers have lots of suggestions for using multiple handlers. It may mean that we need to explicitly declare handlers and no longer use the top level |
|
Actually, I "solved it" by explicitly readding to the handlers the default "fallback" handler. But yes, by default as soon as you add a handler, the base one no longer gets used. I'm not sure what's the best practice here, but since now we're handling everything including the root logger, I think it's better not to interfrere with other logging activities :P |
|
Looks sweet! I couldn't figure out how to get it to log notifications, like if something uses napari cc: @goanpeca this is relevant to napari/napari-plugin-manager#69 |
Yeah those are not calls to
Good point. I mostly copied the qt code from other places, I'm not experienced with this stuff. But yeah can always be done after, maybe with help from some qt pro :P |
Acutally, done xD |
|
Hmmm. Something's not working. If I try the code from an earlier comment (updated to use #!/usr/bin/env python3
import logging
logger = logging.getLogger()
logger.setLevel('DEBUG')
import napari
v = napari.Viewer()
logging.getLogger('napari').debug('some debug info')
logging.getLogger('other-logger').warning('will also show')
logging.getLogger('napari').error('very important!')
from napari._app_model._app import get_app_model
get_app_model().commands.execute_command('napari.window.help.show_log')
napari.run()viewer: (note: those two messages appear after I press some keys to take the screenshot) terminal output: |
|
Right. I see that the fix in 2812f0b means that we don't register the logger at import, we register for the lifetime of the viewer. I can't decide whether that loses some of the appeal, but maybe it's ok for now. Thoughts @Czaki @brisvag? The other change I was about to push is to change "show_log" to "show_logs" (both function name and action name). I think some folks (🙋) naturally would type "logs", which shows nothing in the command palette without the rename. (And typing only "log" prioritises the Shepp-Logan phantom sample dataset.) |
it's a bit worse than that, it's when the app runs. Even though the messages are logged after the viewer is created, they necessarily happen before I think this might be bad, and maybe the context can live on the viewer itself rather than on the app. What do you think @Czaki, do you think this would be easy to achieve? Or even desirable? |
pushed. I'm going to wait for feedback about the current state of this PR with the context manager before merging. |
My opinion is that enabling logger on import or even on viewer creation is a bad practice. We do not know if users are using napari as an application or in other scenarios. The problem will be bigger when we introduce napari-lite. Of course, we could register logger on viewer creation, but as I have above written, it does not look like a good idea for me. Also, it will be difficult to decide when to unregister. |
Sorry, I can't find where you're saying this "above". Why is this bad? If the problem is "tests crash", let's just test differently and xfail that specific qt+debugger mix. |
the paragraph above.
Because we started collecting logs even in situations when it cannot be seen, but still consumes memory and CPU cycles. |
Ah, lol, I thought you meant you had an explanation on the why, sorry :P
but say the viewer crasher before starting, those logs might be the thing that helps us debugging. Of course, we need to actually save them to file, which is planned. Is memory and cpu cycles really of concerns here? Like, does it even factor in compared to the import costs of our dependencies?? |
For long-running programs, through multiple hours, where every logging call is registered and saved? Yes.
if it is our program (someone start napari from bundle for example) we may enable it earlier. If it is someone's script he may read log from termianl. |
|
ok, so you're saying let's merge this as is and consider this only a GUI logging tool, period? |
In my opinion yes. We may further work around this problem. For example, add BTW. I think that is more important now to have 100% test coverage for this code, as code for debugging should not crash itself. |
|
Ok, color me convinced! |
|
Ok, I'll merge as-is, and we can always tweak in the future to handle more and/or let users opt-in to handle more. |
|
(Thank you both for the discussion! It's great to walk away for a bit and come back to have a decision made for you! 😂) |
|
This pull request has been mentioned on Image.sc Forum. There might be relevant details there: |
Original PR #6900 by brisvag Original: napari/napari#6900
…ilters Merged from original PR #6900 Original: napari/napari#6900

References and relevant issues
Followup on #6849 (comment)
Description
The idea is to have our own custom handler for log messages so we can then expose the logs as we prefer from the GUI. This will make it easier for users to copy-paste logs even if they didn't manually open from the console, and also easier for developers to quickly check things.
I never really worked with the logging module, so I have a feeling that this is garbage... but oh well, let's see how bad :P
To test, open napari and do some stuff. Then, from the terminal or console run:
EDIT: Added a very quick-and-dirty GUI for the logger based on the implementation of the
Aboutwidget. For how bad it is, it's actually ok xD You can open it from the menu `Help -> Show log".cc @Czaki