BurningTimesAi/공유/기획/FirstRising/몬스터보스/tools/unity_eval/logscan.py

63 lines
2.8 KiB
Python
Raw Permalink Normal View History

# -*- coding: utf-8 -*-
# 에디터 로그(Editor.log)를 기준으로 오류를 센다. 콘솔 조회(get_console_logs)는 엔진이 직접 찍는 오류(BatchDrawCommand 등)를 놓쳤다.
# python logscan.py mark 지금 로그 크기를 적어 둔다
# python logscan.py scan [이름] 적어 둔 자리부터 끝까지에서 오류 머리줄을 센다
import io, os, re, sys, collections
LOG = r"C:\Users\sw\AppData\Local\Unity\Editor\Editor.log"
MARK = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logscan.mark")
# 도구가 내는 메시지(게임 오류 아님)
IGNORE = ("Failed to handle /api/exec request",)
def read_from(offset):
with open(LOG, "rb") as f:
f.seek(offset)
return f.read().decode("utf-8", errors="replace")
def main():
cmd = sys.argv[1] if len(sys.argv) > 1 else "scan"
if cmd == "mark":
size = os.path.getsize(LOG)
io.open(MARK, "w").write(str(size))
print("mark", size)
return
offset = int(io.open(MARK).read().strip()) if os.path.exists(MARK) else 0
size = os.path.getsize(LOG)
if offset > size:
offset = 0 # 에디터가 다시 떠서 로그가 새로 시작됨
text = read_from(offset)
lines = text.split("\n")
heads = collections.Counter()
unloads = 0
for i, l in enumerate(lines):
l = l.rstrip("\r")
if l.startswith("Unloading ") and "unused Assets" in l:
unloads += 1
head = None
if l.startswith("A BatchDrawCommand was submitted"):
head = "A BatchDrawCommand was submitted with an invalid Batch, Mesh, or Material ID"
elif l.startswith(("UnityEngine.Debug:LogError", "UnityEngine.Debug:LogException", "UnityEngine.Debug:LogAssertion", "UnityEngine.Debug:LogErrorFormat")):
j = i
while j > 0 and not lines[j].startswith("UnityEngine.Debug:ExtractStackTraceNoAlloc"):
j -= 1
head = lines[j - 1].strip()[:200] if j > 0 else "?"
elif re.match(r"^[A-Za-z_\.]*Exception: ", l) or re.match(r"^[A-Za-z_\.]+Exception$", l.strip()):
head = l.strip()[:200]
elif l.startswith(("Assertion failed", "Some objects were not cleaned up", "Can't destroy", "Destroying GameObjects immediately")):
head = l.strip()[:200]
elif "error CS" in l:
head = l.strip()[:200]
if head is None:
continue
if any(x in head for x in IGNORE):
continue
heads[re.sub(r"\d+", "#", head)] += 1
name = sys.argv[2] if len(sys.argv) > 2 else ""
total = sum(heads.values())
print("LOGSCAN %s bytes=%d lines=%d unloadUnused=%d errors=%d" % (name, size - offset, len(lines), unloads, total))
for h, c in heads.most_common(20):
print(" x%d %s" % (c, h))
main()