Skip to content

Commit

Permalink
Use mmap to simplify searching for tracebacks in logs
Browse files Browse the repository at this point in the history
  • Loading branch information
tysmith committed May 16, 2024
1 parent ab26f6f commit 78fb816
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 21 deletions.
33 changes: 14 additions & 19 deletions grizzly/common/status_reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
from functools import partial
from itertools import zip_longest
from logging import DEBUG, INFO, basicConfig, getLogger
from os import SEEK_CUR, getenv
from mmap import ACCESS_READ, mmap
from os import getenv
from pathlib import Path
from platform import system
from re import match
Expand Down Expand Up @@ -73,24 +74,18 @@ def from_file(
token = b"Traceback (most recent call last):"
assert len(token) < cls.READ_LIMIT
try:
with log_file.open("rb") as in_fp:
for chunk in iter(partial(in_fp.read, cls.READ_LIMIT), b""):
idx = chunk.find(token)
if idx > -1:
# calculate offset of data in the file
pos = in_fp.tell() - len(chunk) + idx
break
if len(chunk) == cls.READ_LIMIT:
# seek back to avoid missing beginning of token
in_fp.seek(len(token) * -1, SEEK_CUR)
else:
# no traceback here, move along
return None
# seek back 2KB to collect preceding lines
in_fp.seek(max(pos - 2048, 0))
data = in_fp.read(cls.READ_LIMIT)
except OSError: # pragma: no cover
# in case the file goes away
with log_file.open("rb") as lfp:
with mmap(lfp.fileno(), 0, access=ACCESS_READ) as lmm:
idx = lmm.find(token)
if idx == -1:
# no traceback here, move along
return None
# seek back 2KB to collect preceding lines
lmm.seek(max(idx - len(token) - 2048, 0))
data = lmm.read(cls.READ_LIMIT)
except (OSError, ValueError): # pragma: no cover
# OSError: in case the file goes away
# ValueError: cannot mmap an empty file on Windows
return None

data_lines = data.decode("ascii", errors="ignore").splitlines()
Expand Down
4 changes: 2 additions & 2 deletions grizzly/common/test_status_reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ def test_status_reporter_09(mocker, tmp_path):
test_fp.write(
' File "some/long/path/name/foobar.py", line 5000, in <module>\n'
)
test_fp.write(f" some_long_name_for_a_func_{j:0>4d}()\n")
test_fp.write(f" some_long_name_for_a_func_{j:04d}()\n")
test_fp.write("IndexError: list index out of range\n")
rptr = StatusReporter.load(db_file, tb_path=tmp_path)
rptr._sys_info = _fake_sys_info
Expand Down Expand Up @@ -598,7 +598,7 @@ def test_traceback_report_04(tmp_path):
test_fp.write(" second()\n")
for i in reversed(range(TracebackReport.MAX_LINES)):
test_fp.write(' File "foo.py", line 5, in <module>\n')
test_fp.write(f" func_{i:0>2d}()\n")
test_fp.write(f" func_{i:02d}()\n")
test_fp.write("END_WITH_BLANK_LINE\n\n")
test_fp.write("end junk\n")
tbr = TracebackReport.from_file(test_log)
Expand Down

0 comments on commit 78fb816

Please sign in to comment.