Skip to content

Commit 831a156

Browse files
committed
feat: improve error parser to include line numbers and context lines
1 parent 4608d7b commit 831a156

File tree

3 files changed

+54
-37
lines changed

3 files changed

+54
-37
lines changed

src/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
from .modnames import clean_name
22
from .mods import Mod, ModList
3-
from .parse import parse_local, compare_mods, fetch_errors, merge_errors
3+
from .parse import parse_local, compare_mods, parse_errors, merge_errors

src/bot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from readerwriterlock.rwlock import RWLockRead
1717

1818
import app_version
19-
from src import ModList, parse_local, compare_mods, fetch_errors, env, merge_errors, config
19+
from src import ModList, parse_local, compare_mods, parse_errors, env, merge_errors, config
2020
from typing import Optional, List
2121

2222

@@ -157,7 +157,7 @@ async def on_checkmods(message: Message, original_message: Message, logs: List[s
157157
mods_local = parse_local(log)
158158

159159
response = compare_mods(mods_local.mods, modlist.get_online_mods(game.name))
160-
errors = fetch_errors(log)
160+
errors = parse_errors(log)
161161

162162
time_watch = datetime.datetime.now()
163163
merged_errors = merge_errors(errors)

src/parse.py

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -119,39 +119,53 @@ def compare_mods(mods_local, mods_online: Dict[str, Mod]):
119119
return result
120120

121121

122-
def fetch_errors(log):
123-
errors = ""
124-
is_in_error = False
125-
was_in_warning = False
126-
127-
for i, line in enumerate(log.splitlines()):
128-
if line == "":
129-
if is_in_error:
130-
errors += "\n"
131-
is_in_error = False
132-
continue
133-
134-
if line.startswith("[Info") or line.startswith("[Debug") or line.startswith("[Message"):
135-
if is_in_error:
136-
errors += "\n"
137-
is_in_error = False
138-
was_in_warning = False
139-
140-
if is_in_error or line.startswith("[Error") or line.startswith("[Fatal") or "Exception in ZRpc::HandlePackage:" in line:
141-
if was_in_warning or not is_in_error:
142-
errors += "\n"
143-
was_in_warning = False
144-
errors += f"{line}\n"
145-
is_in_error = True
146-
147-
if line.startswith("[Warning"):
148-
errors += f"{line}\n"
149-
was_in_warning = True
150-
151-
return errors.replace("\n\n\n", "\n\n")
122+
def parse_errors(log: str, context_before=4, context_after=0):
123+
lines = log.splitlines()
124+
line_types = ["Normal"] * len(lines)
152125

126+
for i, line in enumerate(lines):
127+
if line.startswith("[Error") or line.startswith("[Fatal") or "Exception in ZRpc::HandlePackage:" in line:
128+
line_types[i] = "Error"
129+
elif line.startswith("[Warning"):
130+
line_types[i] = "Warning"
131+
elif line.startswith("[Info") or line.startswith("[Debug") or line.startswith("[Message") or line.strip() == "":
132+
line_types[i] = "Normal"
133+
elif i > 0 and line_types[i - 1] == "Error":
134+
line_types[i] = "Error"
135+
lines[i] = " " + lines[i]
136+
elif i > 0 and line_types[i - 1] == "Warning":
137+
line_types[i] = "Warning"
138+
lines[i] = " " + lines[i]
139+
140+
for i, line_type in enumerate(line_types):
141+
if line_type == "Error" or line_type == "Warning":
142+
for j in range(max(0, i - context_before), i):
143+
if line_types[j] == "Normal":
144+
line_types[j] = "Context"
145+
for j in range(i + 1, min(len(lines), i + 1 + context_after)):
146+
if line_types[j] == "Normal":
147+
line_types[j] = "Context"
153148

154-
def merge_errors(errors) -> str:
149+
errors = ""
150+
for i, line in enumerate(lines):
151+
next_is_error = i < len(lines) - 1 and line_types[i + 1] == "Error"
152+
next_is_not_error = i < len(lines) - 1 and line_types[i + 1] != "Error"
153+
prefix = f"{str(i + 1).rjust(4)} | "
154+
155+
if line_types[i] == "Error":
156+
errors += f"{prefix}{line}\n"
157+
elif line_types[i] == "Warning":
158+
errors += f"{prefix}{line}\n"
159+
elif line_types[i] == "Context" and lines[i].strip() != "":
160+
errors += f"{prefix}{line}\n"
161+
if line_types[i] == "Error" and next_is_not_error:
162+
errors += "\n"
163+
if line_types[i] != "Error" and next_is_error:
164+
errors += "\n"
165+
166+
return errors.replace("\n\n\n", "\n\n").strip("\n")
167+
168+
def merge_errors(errors: str) -> str:
155169
result = ""
156170
max_length = 50
157171
lines = errors.splitlines()
@@ -162,22 +176,25 @@ def merge_errors(errors) -> str:
162176
skip -= 1
163177
continue
164178
for i2, line in enumerate(lines[i1 + 1:i1 + max_length]):
165-
if error == line:
179+
if error[4:] == line[4:]:
166180
end_pos = i1 + 1 + i2
167181
length = end_pos - i1
168182
block1 = lines[i1:end_pos]
169183
block2 = lines[end_pos:end_pos + length]
184+
block1_cmp = [l[4:] for l in block1]
185+
block2_cmp = [l[4:] for l in block2]
170186
duplicates = 1
171187

172-
while block1 == block2:
188+
while block1_cmp == block2_cmp:
173189
end_pos += length
174190
block2 = lines[end_pos:end_pos + length]
191+
block2_cmp = [l[4:] for l in block2]
175192
duplicates += 1
176193

177194
if duplicates > 1 and len(block1) * duplicates >= 3:
178195
header = f"----- {duplicates}x -----"
179196
result += "\n" + header + "\n"
180-
result += "\n".join(block1).strip() + "\n"
197+
result += "\n".join(block1).strip("\n") + "\n"
181198
result += "-" * len(header) + "\n\n"
182199
skip = length * duplicates - 1
183200
break

0 commit comments

Comments
 (0)