Skip to content

logger middleware shows wrong status code when used with timeout middleware #1953

Open
@gmattcrowley

Description

@gmattcrowley

Issue Description

When using both the "Logging" and "Timeout" middleware together, the client is getting the appropriate 503 response, but the logs show that the response was 200.

Checklist

  • Dependencies installed
  • No typos
  • Searched existing issues and docs

Expected behaviour

The server logs would show accurate response details, eg. "status": 503 in the case of the request timeout

Actual behaviour

The server logs show "status": 200

Example:
{"time":"2021-08-10T11:12:02.5457958-04:00","id":"","remote_ip":"::1","host":"localhost:8080","method":"POST","uri":"/sleep","user_agent":"PostmanRuntime/7.28.2","status":200,"error":"","latency":11997200,"latency_human":"11.9972ms","bytes_in":0,"bytes_out":0}

Steps to reproduce

  1. Create a simple echo server with a single endpoint that sleeps for a few seconds
  2. Add the use the logging and timeout middleware, set timeout to less than the above sleep
  3. Startup the server and invoke the endpoint

Working code to debug

package main

import (
	"time"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"github.com/labstack/gommon/log"
)

func main() {
	e := echo.New()
	e.Use(middleware.Logger())
	e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
		Timeout: time.Duration(1) * time.Millisecond,
	}))
	e.Logger.SetLevel(log.INFO)

	e.POST("/sleep", func(c echo.Context) error {
		c.Logger().Info("Before sleeping in /sleep")
		time.Sleep(12 * time.Second)
		c.Logger().Info("After sleeping in /sleep")
		return nil
	})

	e.Logger.Panic(e.Start(":8080"))
}

Version/commit

go 1.16

require (
github.com/labstack/echo/v4 v4.5.0
github.com/labstack/gommon v0.3.0
)

Additional Comments:

This example also seems to throw a Data Race warning if you run it a couple times... I think the stack traces suggests it's related to the timeout handler as well.

I think in another issue the timeout middleware was described as a having many landmines, is there another way other echo users are dealing with request timeouts? My particular use case is internal only so I really only need to ensure that connections don't hang indefinately. Would server timeouts be good enough for that?

Example:

package main

import (
	"net/http"
	"time"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"github.com/labstack/gommon/log"
)

func main() {
	e := echo.New()
	e.Use(middleware.Logger())
	e.Logger.SetLevel(log.INFO)

	e.POST("/sleep", func(c echo.Context) error {
		time.Sleep(12 * time.Second)
		return nil
	})

	srv := &http.Server{
		Addr:         ":8080",
		Handler:      e,
		ReadTimeout:  1 * time.Second,
		WriteTimeout: 1 * time.Second,
	}

	if err := srv.ListenAndServe(); err != http.ErrServerClosed {
		e.Logger.Fatal(err)
	}
}

In that case my client would get a server hangup (oh and the Logger still logs it as a 200, which is still a problem...)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions