你正在使用哪个版本的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)
/* .... */
5条答案
按热度按时间xa9qqrwz1#
你的意思是使用https://pkg.go.dev/runtime/debug#PrintStack来丢弃ServeHTTP堆栈吗?
同时cc @neild per owner
pkmbmrz72#
是的,的确如此!
hwamh0ep3#
https://go.dev/cl/391474提到了这个问题:
net/http: dump handler stack in TimeoutHandler while panic
zbdgwd5y4#
原始问题 #22084
7lrncoxx5#
Change https://go.dev/cl/391474 mentions this issue:
net/http: dump handler stack in TimeoutHandler while panic
FYI, I've abandon CL391474.