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
Fix logging #17064
Fix logging #17064
Conversation
This reverts commit a20e207.
Thank you for your pull request. Before we can look at your contribution, we need to ensure all contributors are covered by a Contributor License Agreement. After the following items are addressed, please respond with a new comment here, and the automated system will re-verify.
Regards, |
Agreed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to add a test where app adds a handler and then imports grpcio. Would adding a NullHandler interfere with existing handler?
|
@srini100 No, I don't believe so. Handlers are added to particular loggers. So if the user configured a particular grpc module to have a handler (which I doubt would happen very often), then As for the additional test, sure! Sounds like a good idea. |
|
|
|
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great and discussed offline
class LoggingTest(unittest.TestCase): | ||
|
||
def test_logger_not_occupied(self): | ||
self.assertEqual(0, len(logging.getLogger().handlers)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed offline that if this test case run after the other two test cases, it will always success since the logging
module is reloaded.
reload_module(logging) | ||
reload_module(grpc) | ||
self.assertFalse( | ||
"No handlers could be found" in sys.stderr.getvalue()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optional: There is assertNotIn
function in unit test. https://docs.python.org/2/library/unittest.html#unittest.TestCase.assertNotIn
|
|
|
I was trying to get a feel for what the rest of the python ecosystem does with its logging, so I looked into the top few libraries on pypi: urllib3 maintains a logger for not quite every module, but for each one that does heavy lifting. The logger name is `__name__`, and no handlers are registered for any module-level loggers, including NullHandler. Their documentation spells out how to configure logging for the library. They explicitly configure a library root-level logger called `urllib3` to which they attach a `NullHandler`. This addresses the "no handlers could be found" problem. Their tests explicitly configure handlers, just like ours do. scrapy is more hands-on. It provides a configuration module for its logging and a whole document on how to handle logging with scrapy. It looks like log.py's whole reason for existence is making sure that a handler is attached to to the scrapy handler at startup. I think the extra complexity here is because scrapy also offers a CLI, so there has to be some way to configure logging without resorting to writing python, so I felt we didn't need to resort to this added complexity. --- Based on all of the libraries I've looked at, I think our current approach is reasonable. The one change I would make is to explicitly configure a `grpc` logger and to only attach a `NullHandler` to it instead of putting the burden on the author of each new module to configure it there. With this change, I have - Configured a logger in each module that cares about logging - Removed all NullHandlers attached to module-level loggers - Explicitly configured a `grpc` logger with a `NullHandler` attached Resolves: #16572 Related: #17064
This PR addresses both #17017 and #16572. In #16378, we add calls to
logging.basicConfig()
in various modules, which added a handler to the root logger.One potential solution to the problem is to by default configure each module-level logger with a
NullHandler
. This does two things:Without explicit configuration of a handler for the root logger in application code, this change will result in no logging output from
grpcio
. To address this issue for tests, I have added a call tologging.basicConfig()
in all unit tests and test utilities I could identify. It's entirely possible I've missed some places.