mirror of
https://github.com/mudler/LocalAI.git
synced 2026-05-16 20:52:08 -04:00
fix(http): make handler-error status visible in access log + transcription errors (#9707)
* fix(http): log accurate status code when handler returns error The custom xlog access-log middleware in API() reads res.Status *before* Echo's central HTTPErrorHandler runs, so when a handler returns an error without writing a response (e.g. TranscriptEndpoint's `return err` on backend failure) the status field stays at its default 200. The logged line then claims status=200 while the client receives 500 — silently hiding every 500/503/etc. that bubbles up through Echo's error handler. Mirror echo.DefaultHTTPErrorHandler's status derivation when err != nil and the response hasn't been committed: default to 500, upgrade to *echo.HTTPError.Code if applicable. The logged status now matches what the client actually sees, so failed transcription requests stop appearing as 200 in the access log. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Assisted-by: Claude:claude-opus-4-7 [Claude Code] * fix(transcription): log underlying error before returning 500 to client ModelTranscriptionWithOptions surfaces real failures — gRPC errors from a remote node, model load problems, ffmpeg conversion crashes — but TranscriptEndpoint just did `return err`, so Echo turned it into a 500 with a generic body and the original error was lost. Operators chasing transcription failures across distributed mode were left with "upstream returned 500" on the client and zero context anywhere in the frontend's logs. Add an xlog.Error before returning, recording model name, the staged audio path, and the underlying error. Combined with the access-log status fix, a failing transcription now leaves an audit trail (real status code in the access line, real cause in an Error line) instead of vanishing. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Assisted-by: Claude:claude-opus-4-7 [Claude Code] --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
@@ -167,6 +167,21 @@ func API(application *application.Application) (*echo.Echo, error) {
|
||||
res := c.Response()
|
||||
err := next(c)
|
||||
|
||||
// Echo's central HTTPErrorHandler runs *after* this middleware
|
||||
// returns, so res.Status still reads the default 200 here when a
|
||||
// handler returned an error without writing a response. Mirror
|
||||
// echo.DefaultHTTPErrorHandler's status derivation so the access
|
||||
// log reflects the status the client actually receives — without
|
||||
// this, every silent handler error logs as 200.
|
||||
status := res.Status
|
||||
if err != nil && !res.Committed {
|
||||
status = http.StatusInternalServerError
|
||||
var he *echo.HTTPError
|
||||
if errors.As(err, &he) {
|
||||
status = he.Code
|
||||
}
|
||||
}
|
||||
|
||||
// Fix for #7989: Reduce log verbosity of Web UI polling, resources API, and health checks
|
||||
// These paths are logged at DEBUG level (hidden by default) instead of INFO.
|
||||
isQuietPath := false
|
||||
@@ -177,10 +192,10 @@ func API(application *application.Application) (*echo.Echo, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if isQuietPath && res.Status == 200 {
|
||||
xlog.Debug("HTTP request", "method", req.Method, "path", req.URL.Path, "status", res.Status)
|
||||
if isQuietPath && status == 200 {
|
||||
xlog.Debug("HTTP request", "method", req.Method, "path", req.URL.Path, "status", status)
|
||||
} else {
|
||||
xlog.Info("HTTP request", "method", req.Method, "path", req.URL.Path, "status", res.Status)
|
||||
xlog.Info("HTTP request", "method", req.Method, "path", req.URL.Path, "status", status)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -128,6 +128,15 @@ func TranscriptEndpoint(cl *config.ModelConfigLoader, ml *model.ModelLoader, app
|
||||
|
||||
tr, err := backend.ModelTranscriptionWithOptions(req, ml, *config, appConfig)
|
||||
if err != nil {
|
||||
// Log before returning so the underlying error survives. Echo's
|
||||
// error handler turns this into a 500 with a generic body, which
|
||||
// otherwise leaves operators chasing a silent failure — see e.g.
|
||||
// distributed transcription, where the gRPC error from a remote
|
||||
// node is the only signal of what actually went wrong.
|
||||
xlog.Error("Transcription failed",
|
||||
"model", config.Name,
|
||||
"audio", dst,
|
||||
"error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user