Skip to content

Commit f76df50

Browse files
committed
Surface boot exceptions in logs
1 parent 1f9a177 commit f76df50

File tree

1 file changed

+42
-1
lines changed

1 file changed

+42
-1
lines changed

src/tidewave/django/__init__.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
import io
66
import logging
7+
import threading
8+
import traceback
79
from typing import Any, Callable
810

911
from django.conf import settings
1012
from django.http import HttpResponse
11-
from django.utils.log import CallbackFilter
1213

1314
import tidewave.tools as tidewave_tools
1415
from tidewave.django.models import get_models
@@ -18,6 +19,46 @@
1819
from tidewave.tools.get_logs import file_handler
1920

2021

22+
def add_threading_except_hook():
23+
# Some errors prevent the server from starting, for example
24+
# a missing import in urls.py. The process keeps running, just
25+
# without the server. The LLM can fix the issue, then the watcher
26+
# restarts the server and it works as expected. To enable the LLM
27+
# to fix the issue, we need to surface the startup error in the
28+
# logs. The crash results from an uncaught exception in the Django
29+
# thread, so we patch the global excepthook, so that we write the
30+
# exception to the log file.
31+
32+
original_threading_excepthook = threading.excepthook
33+
34+
35+
def tidewave_excepthook(args):
36+
if args.thread is not None and args.thread.name == "django-main-thread":
37+
formatted = "".join(
38+
traceback.format_exception(args.exc_type, args.exc_value, args.exc_traceback)
39+
)
40+
message = "Django terminated with exception:\n" + formatted
41+
record = logging.LogRecord(
42+
name="tidewave.exceptionhook",
43+
level=logging.ERROR,
44+
pathname="",
45+
lineno=0,
46+
msg=message,
47+
args=(),
48+
exc_info=None,
49+
)
50+
51+
file_handler.emit(record)
52+
file_handler.flush()
53+
54+
if original_threading_excepthook is not None:
55+
original_threading_excepthook(args)
56+
57+
58+
threading.excepthook = tidewave_excepthook
59+
60+
add_threading_except_hook()
61+
2162
class Middleware:
2263
"""Django middleware for Tidewave MCP integration
2364

0 commit comments

Comments
 (0)