-
Writing my own mid for logging, and everything is fine but can't get a proper response status: This is mid func (s *Server) addonInfo(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
timeStarted := time.Now()
err := next(ctx)
fields := map[string]interface{}{
"latency": int64(time.Since(timeStarted) / time.Millisecond),
"method": ctx.Request().Method,
"path": ctx.Request().URL.Path,
"query": ctx.Request().URL.RawQuery,
"status": ctx.Response().Status,
}
if err != nil {
s.logger.SendErrorWithFields(err, fields)
return err
}
s.logger.SendWithFields(fields)
return nil
}
} This is how calling on error: return echo.NewHTTPError(http.StatusInternalServerError, "failed: "+err.Error()) Above logger sees the error but returns status 200 here: If i change error handling a bit: ec.NoContent(http.StatusInternalServerError)
return echo.NewHTTPError(http.StatusInternalServerError, "failed: "+err.Error()) Then everything is good, but it is not a good way to do it ) but I wander if there other options |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Check this block how status is written in global error handler. Line 379 in dec96f0 You can check err for type that contains code and extract it before logging err := next(c)
status := c.Response().Status
httpErr := new(echo.HTTPError)
if errors.As(err, &httpErr) {
status = httpErr.Code
}
fields := map[string]interface{}{
"latency": int64(time.Since(timeStarted) / time.Millisecond),
"method": c.Request().Method,
"path": c.Request().URL.Path,
"query": c.Request().URL.RawQuery,
"status": status,
} If someone wants to try out same middleware: func main() {
e := echo.New()
customMiddleware := func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
timeStarted := time.Now()
err := next(c)
status := c.Response().Status
httpErr := new(echo.HTTPError)
if errors.As(err, &httpErr) {
status = httpErr.Code
}
fields := map[string]interface{}{
"latency": int64(time.Since(timeStarted) / time.Millisecond),
"method": c.Request().Method,
"path": c.Request().URL.Path,
"query": c.Request().URL.RawQuery,
"status": status,
}
if err != nil {
fmt.Printf("on error: %v\n", fields)
//s.logger.SendErrorWithFields(err, fields)
return err
}
fmt.Printf("fields: %v\n", fields)
//s.logger.SendWithFields(fields)
return nil
}
}
e.Use(customMiddleware)
e.GET("/err", func(c echo.Context) error {
return echo.NewHTTPError(http.StatusInternalServerError, "failed: error")
})
e.GET("/ok", func(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"msg": "ok"})
})
server := http.Server{
Addr: ":8080",
Handler: e,
}
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
e.Logger.Fatal("shutting down the server")
}
} |
Beta Was this translation helpful? Give feedback.
"status": c.Response().Status,
returns200
aftererr := next(c)
because at that moment error handler as not yet modified response status (response has not been "commited" yet). It will be done for error in global error handler after the end of the handler chain execution.Check this block how status is written in global error handler.
echo/echo.go
Line 379 in dec96f0
You can check err for type that contains code and extract it before logging