go net/http: http.TimeoutHandler重写panic堆栈跟踪

hof1towb  于 7个月前  发布在  Go
关注(0)|答案(5)|浏览(71)

你正在使用哪个版本的Go( go version )?

$ go version
go version go1.17.7 linux/amd64

这个问题在最新版本中是否重现?

目前使用的是最新版本

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/co11ter/.cache/go-build"
GOENV="/home/co11ter/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/co11ter/go/pkg/mod"
GONOPROXY="xdevteam.com"
GONOSUMDB="xdevteam.com"
GOOS="linux"
GOPATH="/home/co11ter/go"
GOPRIVATE="xdevteam.com"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/go"
GOSUMDB="off"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17.6"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build1126018893=/tmp/go-build -gno-record-gcc-switches"

你做了什么?

我使用了 http.TimeoutHandler 中间件,并在处理程序中触发了恐慌。
复现问题的代码:

package main

import (
	"log"
	"net/http"
	"time"
)

func main() {
	mux := http.NewServeMux()

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		panic("panic")
	})

	mux.Handle("/", http.TimeoutHandler(handler, time.Second, "timeout"))

	log.Fatal(http.ListenAndServe(":8080", mux))
}

你期望看到什么?

当我向 http://localhost:8080 发送HTTP请求时,我期望得到原始的恐慌堆栈跟踪,如下所示:

2022/03/10 15:15:30 http: panic serving [::1]:34108: panic
goroutine 6 [running]:
net/http.(*conn).serve.func1()
	/usr/lib/go/src/net/http/server.go:1802 +0xb9
panic({0x6058e0, 0x697da0})
	/usr/lib/go/src/runtime/panic.go:1047 +0x266
main.main.func1({0xffffffffffffffff, 0x72}, 0x0)
	/home/co11ter/go/softswiss/a8r/cmd/tt/main.go:12 +0x27
net/http.HandlerFunc.ServeHTTP(0x0, {0x69bde0, 0xc000184000}, 0x0)
	/usr/lib/go/src/net/http/server.go:2047 +0x2f
net/http.(*timeoutHandler).ServeHTTP(0xc000026280, {0x69e5c0, 0xc0001401c0}, 0xc000164100)
	/usr/lib/go/src/net/http/server.go:3342 +0x893
net/http.(*ServeMux).ServeHTTP(0x0, {0x69e5c0, 0xc0001401c0}, 0xc000164100)
	/usr/lib/go/src/net/http/server.go:2425 +0x149
net/http.serverHandler.ServeHTTP({0xc000090030}, {0x69e5c0, 0xc0001401c0}, 0xc000164100)
	/usr/lib/go/src/net/http/server.go:2879 +0x43b
net/http.(*conn).serve(0xc00010ea00, {0x69f3c0, 0xc00007edb0})
	/usr/lib/go/src/net/http/server.go:1930 +0xb08
created by net/http.(*Server).Serve
	/usr/lib/go/src/net/http/server.go:3034 +0x4e8

这样就可以调查处理程序层中的每个问题。

你看到了什么?

我在控制台上看到的是恐慌的堆栈跟踪,但没有指向问题:

2022/03/10 15:15:30 http: panic serving [::1]:34108: panic
goroutine 6 [running]:
net/http.(*conn).serve.func1()
	/usr/lib/go/src/net/http/server.go:1802 +0xb9
panic({0x6058e0, 0x697da0})
	/usr/lib/go/src/runtime/panic.go:1047 +0x266
net/http.(*timeoutHandler).ServeHTTP(0xc000026280, {0x69e5c0, 0xc0001401c0}, 0xc000164100)
	/usr/lib/go/src/net/http/server.go:3342 +0x893
net/http.(*ServeMux).ServeHTTP(0x0, {0x69e5c0, 0xc0001401c0}, 0xc000164100)
	/usr/lib/go/src/net/http/server.go:2425 +0x149
net/http.serverHandler.ServeHTTP({0xc000090030}, {0x69e5c0, 0xc0001401c0}, 0xc000164100)
	/usr/lib/go/src/net/http/server.go:2879 +0x43b
net/http.(*conn).serve(0xc00010ea00, {0x69f3c0, 0xc00007edb0})
	/usr/lib/go/src/net/http/server.go:1930 +0xb08
created by net/http.(*Server).Serve
	/usr/lib/go/src/net/http/server.go:3034 +0x4e8

进一步调查

https://github.com/golang/go/blob/master/src/net/http/server.go#L3379
http.TimeoutHandler 中的源代码重写了恐慌并破坏了堆栈跟踪。因此,我们无法在处理程序层上调查原始问题。

/* .... */
	
       go func() {
		defer func() {
			if p := recover(); p != nil {
				panicChan <- p
			}
		}()
		h.handler.ServeHTTP(tw, r)
		close(done)
	}()
	select {
	case p := <-panicChan:
		panic(p)

        /* .... */
xa9qqrwz

xa9qqrwz1#

你的意思是使用https://pkg.go.dev/runtime/debug#PrintStack来丢弃ServeHTTP堆栈吗?

if p := recover(); p != nil {
  debug.PrintStack()             
  panicChan <- p
}

同时cc @neild per owner

pkmbmrz7

pkmbmrz72#

是的,的确如此!

hwamh0ep

hwamh0ep3#

https://go.dev/cl/391474提到了这个问题:net/http: dump handler stack in TimeoutHandler while panic

7lrncoxx

7lrncoxx5#

Change https://go.dev/cl/391474 mentions this issue: net/http: dump handler stack in TimeoutHandler while panic
FYI, I've abandon CL391474.

相关问题