|
4 | 4 |
|
5 | 5 | import io |
6 | 6 | import logging |
| 7 | +import threading |
| 8 | +import traceback |
7 | 9 | from typing import Any, Callable |
8 | 10 |
|
9 | 11 | from django.conf import settings |
10 | 12 | from django.http import HttpResponse |
11 | | -from django.utils.log import CallbackFilter |
12 | 13 |
|
13 | 14 | import tidewave.tools as tidewave_tools |
14 | 15 | from tidewave.django.models import get_models |
|
18 | 19 | from tidewave.tools.get_logs import file_handler |
19 | 20 |
|
20 | 21 |
|
| 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 | + |
21 | 62 | class Middleware: |
22 | 63 | """Django middleware for Tidewave MCP integration |
23 | 64 |
|
|
0 commit comments