-
-
Notifications
You must be signed in to change notification settings - Fork 32k
py311: incorrect logging.LogRecord.module value (and related attrs) when using a custom log-level method #97941
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
Comments
You can use the def trace(self, message, *args, **kwargs):
if self.isEnabledFor(TRACE):
kwargs.setdefault('stacklevel', 2)
self._log(TRACE, message, args, **kwargs) then when I run
|
No, you can not, because as I already said at the bottom of my post, that breaks on Python <= 3.10 def trace(self, message, *args, **kwargs):
if self.isEnabledFor(TRACE):
kwargs.setdefault('stacklevel', 2)
self._log(TRACE, message, args, **kwargs)
this requires having two separate methods for py<3.11 and for py>=3.11, which is bad and a sign that this is a regression in 3.11 class MyLoggingClass(logging.getLoggerClass()):
if sys.version_info >= (3, 11):
def trace(self, message, *args, **kws):
if self.isEnabledFor(TRACE):
kws["stacklevel"] = 2
self._log(TRACE, message, args, **kws)
else:
def trace(self, message, *args, **kws):
if self.isEnabledFor(TRACE):
self._log(TRACE, message, args, **kws) $ python3.10 -m myproject
[content][myproject.content][trace] foo
[content][myproject.content][trace] bar
$ python3.11 -m myproject
[content][myproject.content][trace] foo
[content][myproject.content][trace] bar |
Yes, but gh-89334 (for which the change in #28287 was made) is a valid issue, isn't it? Do you have an alternative fix for it? Not sure why you need two methods, anyway - you could just have |
The intention is to optimize log calls. There could of course be a simple if-block inside the method, but that doesn't change the fact that you have to make a distinction between py311 and below.
I made a suggestion in my OP in regards to also checking for the |
Not sure if that suggestion's specific enough to constitute a fix; perhaps I'm not understanding exactly what you're getting at. Would you like to propose an alternative PR with tests that resolves both this issue and gh-89334 in a different way to #28287? If so, please make sure to add the users who worked on #28287 so they can comment on it. |
I'm talking about ignoring the call stack frame in which
Well, I could have a look at least, but I'm not sure if I will manage to get a PR ready with working tests as I am very much unfamiliar with the internals of the stdlib as well as the test setup. |
I had a closer look at this, and I believe it's not worth fixing. That would require making a distinction between "internal" and "external" calls to The workaround with the stacklevel keyword value depending on the python version may be ugly, but it's working and makes sense for skipping wrapper functions/methods like the custom |
Bug report
#28287 has introduced changes to the
logging.LogRecord
'smodule
,pathname
andfilename
attributes when a custom log-level method gets used due to how thelogging.Logger.findCaller()
andlogging.currentframe()
methods were changed and how "internal" call stack frames are handled now. This change doesn't seem intentional to me, so I decided to open this bug report.Related: streamlink/streamlink#4862
Your environment
Reproduction
Consider the following example which defines a custom
trace()
logging method on a customLogger
subclass that gets set as the default logger class.myproject/__init__.py
myproject/__main__.py
myproject/logger.py
myproject/content.py
Result
As you can see, on py311 the custom
logger.trace()
method causes the log record to have a differentmodule
(andpathname
+filename
), but not any of the default log-level methods like the genericlog()
method.From what it looks like, the call stack that's being read and iterated now stops at the first "non internal frame". Since the default log-level methods are considered "internal", everything's working fine. The custom
trace()
method however is not "internal" and is thus used as the source of the log call instead of the example'scontent()
function.This "internal frame" implementation is not quite right, because the
trace()
method is calling the private_log()
method, and not any of the public log-level methods where it would make sense to stop on those "internal" call stack frames. It should also ignore call stack frames which are calling the private_log()
method, so users can define custom log-level methods like in the example shown above.The solution for now is defining two
trace()
methods, one for py<3.11 and one for py>=3.11, where the py311 one sets thestacklevel
keyword on the_log()
call to2
(instead of the default value of1
), so the loop skips one additional call stack frame when checking for "internal" call stack frames, which would be the customtrace()
method. This is a bad and very unintuitive workaround though.Thanks for taking a look at this.
The text was updated successfully, but these errors were encountered: