Fourth off the port list. Users do not open devtools, and "it did not work" with nothing to read is where a bug report dies -- especially on a rented box behind a tunnel, where the terminal that has the answer is not on this desk. Read from ComfyUI's own log FILE rather than from a buffer in this process. v4 kept both and its own comment says why the file is the half that matters: a crash and restart empties an in-memory buffer, and the lines from before the crash are exactly the ones worth reading. So this is the smaller half and the more useful one. Three things the panel refuses to do, each because of what a log is FOR: * It does not redraw while text is being selected. Copying a stack trace is the one thing anybody opens a log to do, and a panel that repaints under the drag makes it impossible. * It keeps the last lines when the server stops answering. The most interesting thing a log can say is that ComfyUI just died, and replacing the lines from just before it went with the error that says it is gone throws away the only evidence of why. * No log file is an ANSWER, with the reason and where to look instead. An empty list reads as a quiet log, and the difference matters precisely when somebody opened the panel because something else already broke.
65 lines
2.5 KiB
Python
65 lines
2.5 KiB
Python
"""The last lines ComfyUI printed.
|
|
|
|
Users do not open devtools, and "it did not work" with nothing to read is where
|
|
a bug report dies. This is the log they can actually reach.
|
|
|
|
Read from ComfyUI's own file rather than from a buffer in this process. v4 kept
|
|
both and its own docstring says why the file is the half that matters: a
|
|
CRASH AND RESTART empties an in-memory buffer, and the lines before the crash
|
|
are exactly the ones worth reading. A file survives it. So this is the smaller
|
|
half and the more useful one, and the buffer can be added if a case turns up
|
|
that the file misses.
|
|
|
|
Never raises. A log panel that fails is worse than one that says it found no
|
|
file, because the reason someone opened it is that something else already broke.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
#: Read from the end. A ComfyUI log runs to megabytes over a long session and
|
|
#: nobody scrolls back through a boot from three days ago.
|
|
MAX_BYTES = 512 * 1024
|
|
MAX_LINES = 2000
|
|
|
|
|
|
def log_file() -> Path | None:
|
|
"""ComfyUI's log, or None when this install does not write one."""
|
|
try:
|
|
import folder_paths
|
|
base = Path(folder_paths.base_path)
|
|
except Exception: # noqa: BLE001
|
|
return None
|
|
for name in ("comfyui.log", "comfyui.prev.log"):
|
|
candidate = base / "user" / name
|
|
if candidate.is_file():
|
|
return candidate
|
|
return None
|
|
|
|
|
|
def recent(limit: int = 600) -> dict:
|
|
"""`{lines, path, detail}`. `detail` is set only when there is nothing to show.
|
|
|
|
The absence of a log is a real state with a real cause -- ComfyUI started
|
|
without one -- so it is reported as an answer rather than as an empty list
|
|
that looks like a quiet log.
|
|
"""
|
|
limit = max(1, min(int(limit or 600), MAX_LINES))
|
|
path = log_file()
|
|
if path is None:
|
|
return {"lines": [], "path": None,
|
|
"detail": "ComfyUI is not writing a log file here, so there is nothing "
|
|
"to show. Its output is in the terminal it was started from."}
|
|
try:
|
|
size = path.stat().st_size
|
|
with path.open("rb") as fh:
|
|
if size > MAX_BYTES:
|
|
fh.seek(size - MAX_BYTES)
|
|
fh.readline() # drop the partial first line
|
|
text = fh.read().decode("utf-8", errors="replace")
|
|
except OSError as exc:
|
|
return {"lines": [], "path": str(path),
|
|
"detail": f"Could not read {path.name}: {exc.strerror or exc}."}
|
|
return {"lines": text.splitlines()[-limit:], "path": str(path), "detail": ""}
|