Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

use NullHandler for logging by default #150

Merged
merged 6 commits into from
Feb 15, 2023

Conversation

vladak
Copy link
Contributor

@vladak vladak commented Feb 5, 2023

This change makes sure the self.logger is always set to something. Given that enable_logger() has the flexibility of specifying the logging package, the loggers are switched, as opposed to handler juggling which might not be a good idea anyway as multiple log packages can be used simultaneously.

Copy link
Member

@tekktrik tekktrik left a comment

Choose a reason for hiding this comment

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

This looks good to me, and seems functionally the same. My only concern would be memory issues (e.g., adafruit_logging takes up precious RAM needed by a board). It may be worth seeing if this works on an M0 board. @brentru, was that a concern you had when making the library?

@vladak
Copy link
Contributor Author

vladak commented Feb 6, 2023

That's interesting and I have not considered that. Is there perhaps some tooling that would help with memory analysis ?

@FoamyGuy
Copy link
Contributor

FoamyGuy commented Feb 13, 2023

Can you expand a bit on why the way it's done today with the None check is not a good idea? I don't know what you meant by handler juggling.

This does seem to me like it would be functionally the same, but at the "cost" of extra RAM and the additional dependency needing to be loaded.

I don't quite understand why having the NullHandler pre-set by default like this preferable to having it be None and using the if statements to determine whether it should try to log or not.

I don't think I have an M0 device that I could hook up with airlift so I can't test that. Honestly though I would'nt be too surprised if it was already tough to get networking and minimqtt both imported and working even without expanding the RAM needed here. It's pretty tight already and the networking libraries are on the bigger side I think

@vladak
Copy link
Contributor Author

vladak commented Feb 14, 2023

It's a readability issue and I'd hope that the code changes make it apparent. Currently in the code there are 32 checks that determine whether self.logger is set to None so that the logger can be actually used. It is also a stability issue - when I was doing some changes to the code recently, I had to be carefull to carry the logger is not None checks around and also make sure that any new logger use is underneath the check. If I was not careful with keeping the check for all the cases where logger is used, then it might not be caught in my cursory testing that had the logger always set to something. It's similar (pattern wise) to the isLoggable() check done in Java logging to avoid unnecessary CPU churn if the log level in effect does not match the log level of the log statement, however in the case of the None check it results in NoneType exception rather than slower code.

As for the handler juggling, it was alternative idea when I considered the possibilities of addressing the readability issue. Basically have a single logger with NullHandler and replace it with handlers from the logger passed to enable_logger() and reverse the operation in disable_logger(). This approach also needs a logging module imported, obviously, is more complicated than necessary and does not play well with multiple distinct logging packages (say adafruit logging with CPython logging).

Another possibility would be to wrap this inside a function.

@dhalbert
Copy link
Contributor

Currently in the code there are 32 checks that determine whether self.logger is set to None

I agree that makes for a mess.

Another possibility would be to wrap this inside a function.

That seems like the simplest solution that doesn't import a logging package when it isn't needed. self.log_debug() and self.log_info() would do the None checks. Maybe you could use a single self.log() function because the levels (INFO, DEBUG, etc.) wouldn't be defined.

Another idea would be to create an adafruit_null_logging package that doesn't do anything except define the levels and use that to initialize the logger. Then the memory overhead is small. If real logging is needed, the real package would be imported. That makes for double definitions of the levels, so that's a little wasted space. I don't know if adafruit_logging could be configured to do lazy importing internally to achieve approximately the same effect.

@vladak vladak mentioned this pull request Feb 14, 2023
@vladak vladak force-pushed the logging_null_handler branch from a72259c to 6d8b72a Compare February 14, 2023 22:37
Copy link
Contributor

@dhalbert dhalbert left a comment

Choose a reason for hiding this comment

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

This looks good to me (once it builds). @tekktrik @FoamyGuy What do you think?

@tekktrik
Copy link
Member

I think this is good as well. It's then probably worth adding a docstring to the logger attribute in a follow-up PR the logging option is documented.

@dhalbert
Copy link
Contributor

I think this is good as well. It's then probably worth adding a docstring to the logger attribute in a follow-up PR the logging option is documented.

Not merged yet so could be added in this PR.

@tekktrik
Copy link
Member

tekktrik commented Feb 14, 2023

@vladak is that something you mind doing? Basically, for the logger attribute in __init__(), add a docstring beneath it documenting it like so:

    def __init___(self) -> None:
        self.logger = NullLogger()
        """An optional logging attribute that can be set with with a Logger to enable debug logging."""

Feel free to change the description above, just an idea to communicate how.

@vladak
Copy link
Contributor Author

vladak commented Feb 15, 2023

@vladak is that something you mind doing?

No issue other than my sleep schedule :-)

@dhalbert dhalbert requested a review from tekktrik February 15, 2023 15:04
Copy link
Member

@tekktrik tekktrik left a comment

Choose a reason for hiding this comment

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

Thanks!

@dhalbert dhalbert merged commit 342b8c9 into adafruit:main Feb 15, 2023
adafruit-adabot added a commit to adafruit/Adafruit_CircuitPython_Bundle that referenced this pull request Feb 16, 2023
Updating https://github.com/adafruit/Adafruit_CircuitPython_ADT7410 to 1.3.10 from 1.3.9:
  > Merge pull request adafruit/Adafruit_CircuitPython_ADT7410#23 from matsujirushi/patch-1
  > Add upload url to release action
  > Add .venv to .gitignore

Updating https://github.com/adafruit/Adafruit_CircuitPython_MiniMQTT to 7.2.2 from 7.2.1:
  > Merge pull request adafruit/Adafruit_CircuitPython_MiniMQTT#150 from vladak/logging_null_handler

Updating https://github.com/adafruit/Adafruit_CircuitPython_Bundle/circuitpython_library_list.md to NA from NA:
  > Updated download stats for the libraries
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants