mirror of
https://github.com/open-webui/open-webui.git
synced 2026-11-05 07:57:06 +00:00
fix: report filter outlet and stream failures at error level
When a filter's outlet() or stream() hook raised, the error was logged at debug level and swallowed, so at the default log level nothing was printed at all: no message, no indication of which filter broke, and the rest of the outlet chain silently skipped. Plugin authors had no way to find the cause short of restarting the server with GLOBAL_LOG_LEVEL=DEBUG. Those two hooks now log at error level with the filter id and a traceback pointing at the failing line in the plugin. stream() runs once per streamed chunk, so a broken filter is reported once per response rather than once per chunk, using the filter context that already exists per response. inlet() stays at debug, since raising there is the documented way to reject a request, it already surfaces to the user in the chat, and escalating it would put a stack trace in the log on every rate-limit rejection. Valve construction failures are covered too, as they previously died on the same silent path, and the neighbouring user-valves error now names the filter as well.
This commit is contained in:
parent
29541cbb52
commit
11f39ff628
1 changed files with 19 additions and 7 deletions
|
|
@ -13,6 +13,14 @@ class FilterContext:
|
|||
self.valves_by_id = None
|
||||
self.function_valves = {}
|
||||
self.user_valves = {}
|
||||
self.failed_filter_ids = set()
|
||||
|
||||
def should_log_error(self, filter_id):
|
||||
"""True only on a filter's first failure this response, since stream filters run per chunk."""
|
||||
if filter_id in self.failed_filter_ids:
|
||||
return False
|
||||
self.failed_filter_ids.add(filter_id)
|
||||
return True
|
||||
|
||||
async def get_function_valves(self, filter_ids, filter_id, Valves):
|
||||
if filter_id not in self.function_valves:
|
||||
|
|
@ -172,22 +180,26 @@ async def process_filter_function(
|
|||
skip_files = (
|
||||
function_module.file_handler if filter_type == 'inlet' and hasattr(function_module, 'file_handler') else None
|
||||
)
|
||||
valves_by_id = await apply_filter_valves(function_module, filter_context, valves_by_id, filter_ids, filter_id)
|
||||
|
||||
try:
|
||||
valves_by_id = await apply_filter_valves(function_module, filter_context, valves_by_id, filter_ids, filter_id)
|
||||
|
||||
sig = inspect.signature(handler)
|
||||
params = get_filter_params(sig, filter_id, filter_type, form_data, extra_params)
|
||||
|
||||
if '__user__' in sig.parameters:
|
||||
try:
|
||||
await apply_user_valves(function_module, filter_context, filter_id, params)
|
||||
except Exception as e:
|
||||
log.exception(f'Failed to get user values: {e}')
|
||||
except Exception:
|
||||
log.exception('Failed to get user valves for filter %s', filter_id)
|
||||
|
||||
form_data = await run_filter_handler(handler, params)
|
||||
except Exception as e:
|
||||
log.debug('Error in %s handler %s: %s', filter_type, filter_id, e)
|
||||
raise e
|
||||
except Exception:
|
||||
if filter_type == 'inlet':
|
||||
# raising from inlet is the documented way to block a request, and already surfaces to the user
|
||||
log.debug('Error in inlet filter %s', filter_id, exc_info=True)
|
||||
elif filter_context is None or filter_context.should_log_error(filter_id):
|
||||
log.exception('Error in %s filter %s', filter_type, filter_id)
|
||||
raise
|
||||
|
||||
return form_data, valves_by_id, skip_files
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue