Skip to content

bpo-41943: Fix bug where assertLogs doesn't correctly filter messages… #22565

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

Merged
merged 4 commits into from
Nov 2, 2020

Conversation

iritkatriel
Copy link
Member

@iritkatriel iritkatriel commented Oct 5, 2020

… by level

@vsajip , @pitrou

https://bugs.python.org/issue41943

Automerge-Triggered-By: GH:vsajip

@iritkatriel iritkatriel changed the title bpo-41898: Fix bug where assertLogs doesn't correctly filter messages… bpo-41943: Fix bug where assertLogs doesn't correctly filter messages… Oct 5, 2020
log_foo.info("1")
finally:
log_foo.setLevel(oldLevel)

def testAssertLogsFailureMismatchingLogger(self):
# Failure due to mismatching logger (and the logged message is
Copy link
Member Author

Choose a reason for hiding this comment

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

Note that this test is similar to the one just above it, which doesn't set the level on the log_foo logger. In that case, log_foo has level WARNING, so the message is blocked by it. But in the new test log_foo lets the message through to the root logger, which has that _CapturingHandler attached to it. But since the _CapturingHandler's level was not set, it is NOTSET which is 0 so I guess it allows all messages through. So my change sets the level of the handler to the level specified by the user.

So with my change we set the log level both on the logger and on the handler attached to it. This seems to fix this particular bug but I'm not sure the interplay between the logger's and the handler's log level is always what we would expect it to be. Here is a small script demonstrating what's going on:

import logging

FORMAT = '%(levelname)-10s %(asctime)s: %(message)s'
handler = logging.StreamHandler()

# Uncomment the next line to fix it
# handler.setLevel(logging.WARNING) 
logging.basicConfig(format=FORMAT, level=logging.WARNING, handlers=[handler])

logger = logging.getLogger('blah')
logger.setLevel(logging.INFO)

logger.info('information')
logger.warning('warning')
logger.error('error')

As it is, all 3 log lines are emitted. If you uncomment the setLevel on the handler, only the warning and error are.

@iritkatriel iritkatriel marked this pull request as draft October 6, 2020 18:22
@iritkatriel
Copy link
Member Author

I converted this to draft because I want to try and fix the issue in the logging library rather than patch over it as I did here.

…config7_ok, test_config_8a_ok) are still failing
@iritkatriel
Copy link
Member Author

@vsajip I think the problem is in Logger.callHandlers(). In this loop:

        c = self
        found = 0
        while c:
            for hdlr in c.handlers:
                found = found + 1
                if record.levelno >= hdlr.level:
                    hdlr.handle(record)
            if not c.propagate:
                c = None    #break out
            else:
                c = c.parent

initially c is the current logger. It calls all handlers in c that have level at most that of the record. Then, as long as c.propagate is True it climbs up the logger tree and calls all handlers on ancestor loggers. But it never checks the levels of any of the ancestor loggers, only the levels of their handlers. So if the logger has a level set and the handler doesn't, we get into problems.

So I added this check:

        while c:
            if not c.isEnabledFor(record.levelno):
                c = None    #break out
            else:
                the code that was in the while loop before

Now the new test passes, but three pre-existing tests fail. I fixed one of them, by adding a handler to the child logger (following the fix, the root logger doesn't handle the record anymore).

test_config7_ok is a similar story - probably need to add a handler to the child logger (or change the expected results).

test_config8_ok I haven't investigated yet.

What do you think about the fix and it implications?

@vsajip
Copy link
Member

vsajip commented Oct 7, 2020

But it never checks the levels of any of the ancestor loggers, only the levels of their handlers.

This is by design - it's always worked like this. So, the change you propose shouldn't be made, and tests need to fit in with the existing behaviour.

@iritkatriel
Copy link
Member Author

But it never checks the levels of any of the ancestor loggers, only the levels of their handlers.

This is by design - it's always worked like this. So, the change you propose shouldn't be made, and tests need to fit in with the existing behaviour.

So the other option I see is in my first commit to this PR - to make assertLogs set the level on both the logger and the handler. Does that look right?

…s (test_config7_ok, test_config_8a_ok) are still failing"

This reverts commit 35d016b.
@vsajip
Copy link
Member

vsajip commented Oct 7, 2020

to make assertLogs set the level on both the logger and the handler.

I think that's right. In general you set levels on loggers (as they are checked first), and then levels on handlers when the specific audience for those handlers want more filtering/less verbosity than the logger.

The tests just have to work with the expected/by design behaviour in this area. If necessary, the docs for assertLogs can be beefed up to make things clearer, with examples, if needed.

@iritkatriel iritkatriel marked this pull request as ready for review October 7, 2020 18:37
@iritkatriel
Copy link
Member Author

@vsajip can you please request a review from @pitrou? I don't think I have that button.

@vsajip vsajip requested a review from pitrou October 9, 2020 13:29
@pitrou
Copy link
Member

pitrou commented Oct 12, 2020

I'd rather let @vsajip decide on this, he's much more of an expert in logging than I am.

@iritkatriel
Copy link
Member Author

Thanks.
@vsajip, @pitrou Do we want to backport this?

@iritkatriel iritkatriel deleted the assertLogsBug branch November 27, 2020 15:19
@iritkatriel iritkatriel added the type-bug An unexpected behavior, bug, or error label Dec 23, 2020
adorilson pushed a commit to adorilson/cpython that referenced this pull request Mar 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants