-
Notifications
You must be signed in to change notification settings - Fork 1k
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 stacklevel in logging
to log the actual user call site (instead of the call site inside the logger wrapper) of log functions
#2730
Conversation
Sounds good, thanks for the fix. Would you be so kind to add a test for this bug? Your example should be a good template for testing. The failing doc CI should be fixed if you merge with/rebase on main. |
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
During writing tests for import logging
from accelerate import Accelerator
from accelerate.logging import get_logger
from rich.logging import RichHandler
logger = get_logger(__name__)
if __name__ == "__main__":
accelerator = Accelerator()
logging.basicConfig(
format="%(filename)s:%(name)s:%(lineno)s - %(message)s",
datefmt="%m/%d %H:%M:%S",
level=logging.INFO,
handlers=[RichHandler(show_time=True, show_level=True, show_path=True)],
)
logger.info(f"process index: {accelerator.process_index}", in_order=True, main_process_only=True) The reason is that all processes other than the main process wait for the main process in this case, but the main process goes into another conditional branch that never waits the remaining processes. Since this PR is specific to |
@BenjaminBossan Tests are added for |
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.
Thanks for adding tests to this PR. In fact, you added quite a lot of tests, since there are no existing dedicated tests for the logger (at least that I could find, ping @muellerzr).
However, I feel like this extensive testing detracts from the core issue that we want to check in this PR and I would suggest to create a separate PR to add general tests for the logger (and potentially solve the bug you found).
For this specific PR, I think a very simple, focused test should be sufficient, for instance:
import logging
import pytest
from accelerate import Accelerator
from accelerate.logging import MultiProcessAdapter, get_logger
@pytest.fixture(scope="module")
def accelerator():
return Accelerator()
@pytest.mark.usefixtures("accelerator")
def test_log_stack(caplog):
logger = get_logger(__name__)
logging.basicConfig(
format="%(filename)s:%(name)s:%(lineno)s - %(message)s",
datefmt="%m/%d %H:%M:%S",
)
logger.warning("Test")
assert len(caplog.records) == 1
rec = caplog.records[0]
assert rec.filename == <name of test file>
# ... more attributes if so desired
Note that I use pytest to simplify some stuff and if you indeed want to create a separate PR to add general tests, I would recommend to take a similar approach. As is, I find the tests hard to understand, as they use a lot of custom classes and use the logger in a very different way from what an accelerate user would typically do.
tests/test_logging.py
Outdated
) | ||
|
||
|
||
def assert_equals(value, expected, prefix=""): |
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.
We don't need this, pytest already generates readable error messages.
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.
I'm not quite an expert in testing, thanks for your comments. I have re-written the tests into two simple tests: 1) check the logged message is correct in a normal setting; and 2) check the logged message is correct when the user overrides stacklevel
in a custom logger wrapper. These tests are most relevant to this PR, and hopefully they can serve as a starting point for future tests.
f3bfc2c
to
0667340
Compare
0667340
to
17a8f45
Compare
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.
Thanks for simplifying the tests, they are much easier to understand now.
Something I like to do with tests for bugfixes is to add a comment that references the original issue to quickly find out why a test exists, but it's not a must have.
@muellerzr please check if this can be merged.
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.
Thanks for doing this and nicely done with the tests!
… of the call site inside the logger wrapper) of log functions (#2730) * fix stacklevel in logging to log info about the actual user callsite * Add two tests for stacklevel in logging --------- Co-authored-by: luowyang <luowyang@github.com>
… of the call site inside the logger wrapper) of log functions (#2730) * fix stacklevel in logging to log info about the actual user callsite * Add two tests for stacklevel in logging --------- Co-authored-by: luowyang <luowyang@github.com>
Fix
stacklevel
inlogging
Fixes #2114
Currently,
accelerate.logging
does not correctly log the user call site of log functions such as.log()
and.info()
. Consider the following example modified from issue #2114:In its current state, the above script shows something like
The calling site of the logging function
.info()
is incorrectly shown as line 61 ofaccelerate.logging.MultiProcessAdapter.log
, which is the calling site inside the logger wrapperMultiProcessAdapter
. This happens because thestacklevel
argument of the logging function is set to its default value1
, which shows the calling site of the wrapped logger's.log()
. See the docs of Pythonlogging
for more details of whatstacklevel
means.There exists a simple fix to the above issue: modify
stacklevel
inMultiProcessAdapter.log
to2
(skipMultiProcessAdapter.log
in the calling stack), unless the users explicitly provide their ownstacklevel
. This fix is summarized as one line of additional code:After applying the above fix, the script mentioned earlier prints the correct message (
test_logging.py
is the script's name):Before submitting
Pull Request section?
to it if that's the case.
documentation guidelines, and
here are tips on formatting docstrings. No. This PR is a bug fix and contains no API change.
Who can review?
Anyone in the community is free to review the PR once the tests have passed. Feel free to tag
members/contributors who may be interested in your PR.
@kiyoon @BenjaminBossan