From 94fbd241558213a924c5cf1fede1ca9e437927e8 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Wed, 26 Apr 2023 21:08:17 +0200 Subject: [PATCH] servenv: Move away from using default HTTP muxer Up until now we've been using the implicit default HTTP mux. The problem of using this mux is that it works implicitly also for profiling endpoints. So the moment that `net/http/pprof` is imported, those endpoints get added. We want to be able to make enabling the profiling endpoints optional, but there's no way to do that with the default mux except by recompiling and removing the import. By moving everything away from the default mux to an explicit mux for the servenv, we can make this configurable in the near future. It still gets added to the default mux, but we don't use that anymore so it doesn't get exposed. The changes here now explicitly add the profiling endpoints so that we can make that optional in a follow up. Signed-off-by: Dirkjan Bussink --- go/cmd/vtgate/index.go | 4 +- go/cmd/vtorc/index.go | 4 +- go/cmd/vttablet/index.go | 4 +- go/stats/opentsdb/opentsdb.go | 2 +- .../prometheusbackend/prometheusbackend.go | 4 +- go/streamlog/streamlog.go | 2 +- go/streamlog/streamlog_flaky_test.go | 9 ++++- go/vt/discovery/healthcheck.go | 2 +- go/vt/servenv/exporter.go | 10 +++-- go/vt/servenv/exporter_test.go | 7 +++- go/vt/servenv/flushlogs.go | 2 +- go/vt/servenv/http.go | 39 +++++++++++++++++++ go/vt/servenv/liveness.go | 2 +- go/vt/servenv/liveness_test.go | 3 +- go/vt/servenv/pprof.go | 1 + go/vt/servenv/run.go | 8 +++- go/vt/servenv/servenv.go | 2 - go/vt/servenv/status.go | 8 ++-- go/vt/servenv/status_test.go | 5 +-- go/vt/throttler/demo/throttler_demo.go | 2 +- go/vt/throttler/throttlerlogz.go | 3 +- go/vt/throttler/throttlerz.go | 3 +- go/vt/vtctld/api.go | 2 +- go/vt/vtctld/api_test.go | 4 +- go/vt/vtctld/debug_health.go | 3 +- go/vt/vtgate/api.go | 3 +- go/vt/vtgate/executor.go | 6 +-- go/vt/vtgate/querylog.go | 5 ++- go/vt/vtgate/vtgate.go | 4 +- go/vt/vtorc/server/api.go | 3 +- go/vt/vttablet/endtoend/framework/server.go | 8 +++- .../tabletmanager/vreplication/vrlog.go | 3 +- go/vt/vttablet/tabletserver/querylogz.go | 3 +- go/vt/vttablet/tabletserver/txlogz.go | 3 +- misc/errcheck_excludes.txt | 1 - 35 files changed, 125 insertions(+), 49 deletions(-) create mode 100644 go/vt/servenv/http.go diff --git a/go/cmd/vtgate/index.go b/go/cmd/vtgate/index.go index be06ed6f10b..aec221b5339 100644 --- a/go/cmd/vtgate/index.go +++ b/go/cmd/vtgate/index.go @@ -18,6 +18,8 @@ package main import ( "net/http" + + "vitess.io/vitess/go/vt/servenv" ) // This is a separate file so it can be selectively included/excluded from @@ -25,7 +27,7 @@ import ( func init() { // Anything unrecognized gets redirected to the status page. - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/debug/status", http.StatusFound) }) } diff --git a/go/cmd/vtorc/index.go b/go/cmd/vtorc/index.go index dcbe1113e53..43ad41850a4 100644 --- a/go/cmd/vtorc/index.go +++ b/go/cmd/vtorc/index.go @@ -18,11 +18,13 @@ package main import ( "net/http" + + "vitess.io/vitess/go/vt/servenv" ) func init() { // Anything unrecognized gets redirected to the status page. - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/debug/status", http.StatusFound) }) } diff --git a/go/cmd/vttablet/index.go b/go/cmd/vttablet/index.go index be06ed6f10b..aec221b5339 100644 --- a/go/cmd/vttablet/index.go +++ b/go/cmd/vttablet/index.go @@ -18,6 +18,8 @@ package main import ( "net/http" + + "vitess.io/vitess/go/vt/servenv" ) // This is a separate file so it can be selectively included/excluded from @@ -25,7 +27,7 @@ import ( func init() { // Anything unrecognized gets redirected to the status page. - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/debug/status", http.StatusFound) }) } diff --git a/go/stats/opentsdb/opentsdb.go b/go/stats/opentsdb/opentsdb.go index f12fa02e2fe..3e85052b5f4 100644 --- a/go/stats/opentsdb/opentsdb.go +++ b/go/stats/opentsdb/opentsdb.go @@ -113,7 +113,7 @@ func InitWithoutServenv(prefix string) { stats.RegisterPushBackend("opentsdb", backend) - http.HandleFunc("/debug/opentsdb", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/debug/opentsdb", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") dataPoints := (*backend).getDataPoints() sort.Sort(byMetric(dataPoints)) diff --git a/go/stats/prometheusbackend/prometheusbackend.go b/go/stats/prometheusbackend/prometheusbackend.go index 2ae88ebb665..9a5ceb7b10b 100644 --- a/go/stats/prometheusbackend/prometheusbackend.go +++ b/go/stats/prometheusbackend/prometheusbackend.go @@ -18,7 +18,6 @@ package prometheusbackend import ( "expvar" - "net/http" "strings" "github.com/prometheus/client_golang/prometheus" @@ -26,6 +25,7 @@ import ( "vitess.io/vitess/go/stats" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/servenv" ) // PromBackend implements PullBackend using Prometheus as the backing metrics storage. @@ -39,7 +39,7 @@ var ( // Init initializes the Prometheus be with the given namespace. func Init(namespace string) { - http.Handle("/metrics", promhttp.Handler()) + servenv.HTTPHandle("/metrics", promhttp.Handler()) be.namespace = namespace stats.Register(be.publishPrometheusMetric) } diff --git a/go/streamlog/streamlog.go b/go/streamlog/streamlog.go index c7916c49256..572c4481777 100644 --- a/go/streamlog/streamlog.go +++ b/go/streamlog/streamlog.go @@ -183,7 +183,7 @@ func (logger *StreamLogger[T]) Name() string { // ServeLogs registers the URL on which messages will be broadcast. // It is safe to register multiple URLs for the same StreamLogger. func (logger *StreamLogger[T]) ServeLogs(url string, logf LogFormatter) { - http.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc(url, func(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) return diff --git a/go/streamlog/streamlog_flaky_test.go b/go/streamlog/streamlog_flaky_test.go index b829f965174..9c0b0366a1d 100644 --- a/go/streamlog/streamlog_flaky_test.go +++ b/go/streamlog/streamlog_flaky_test.go @@ -28,6 +28,8 @@ import ( "syscall" "testing" "time" + + "vitess.io/vitess/go/vt/servenv" ) type logMessage struct { @@ -51,7 +53,12 @@ func TestHTTP(t *testing.T) { defer l.Close() addr := l.Addr().String() - go http.Serve(l, nil) + go func() { + err := servenv.HTTPServe(l) + if err != nil { + t.Errorf("http serve returned unexpected error: %v", err) + } + }() logger := New[*logMessage]("logger", 1) logger.ServeLogs("/log", testLogf) diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go index ad325ba5c7c..f73d9a18be0 100644 --- a/go/vt/discovery/healthcheck.go +++ b/go/vt/discovery/healthcheck.go @@ -348,7 +348,7 @@ func NewHealthCheck(ctx context.Context, retryDelay, healthCheckTimeout time.Dur hc.topoWatchers = topoWatchers healthcheckOnce.Do(func() { - http.Handle("/debug/gateway", hc) + servenv.HTTPHandle("/debug/gateway", hc) }) // start the topo watches here diff --git a/go/vt/servenv/exporter.go b/go/vt/servenv/exporter.go index d8eb4ef428d..a3d23dc4b74 100644 --- a/go/vt/servenv/exporter.go +++ b/go/vt/servenv/exporter.go @@ -105,6 +105,10 @@ type Exporter struct { mu sync.Mutex } +func init() { + HTTPHandle("/debug/vars", expvar.Handler()) +} + // NewExporter creates a new Exporter with name as namespace. // label is the name of the additional dimension for the stats vars. func NewExporter(name, label string) *Exporter { @@ -153,12 +157,12 @@ func (e *Exporter) URLPrefix() string { // HandleFunc sets or overwrites the handler for url. If Exporter has a name, // url remapped from /path to /name/path. If name is empty, the request -// is passed through to http.HandleFunc. +// is passed through to HTTPHandleFunc. func (e *Exporter) HandleFunc(url string, f func(w http.ResponseWriter, r *http.Request)) { e.mu.Lock() defer e.mu.Unlock() if e.name == "" { - http.HandleFunc(url, f) + HTTPHandleFunc(url, f) return } @@ -169,7 +173,7 @@ func (e *Exporter) HandleFunc(url string, f func(w http.ResponseWriter, r *http. hf := &handleFunc{f: f} e.handleFuncs[url] = hf - http.HandleFunc(e.URLPrefix()+url, func(w http.ResponseWriter, r *http.Request) { + HTTPHandleFunc(e.URLPrefix()+url, func(w http.ResponseWriter, r *http.Request) { if f := hf.Get(); f != nil { f(w, r) } diff --git a/go/vt/servenv/exporter_test.go b/go/vt/servenv/exporter_test.go index 4a9edf4da6e..f692e7d5d03 100644 --- a/go/vt/servenv/exporter_test.go +++ b/go/vt/servenv/exporter_test.go @@ -43,7 +43,12 @@ func TestHandleFunc(t *testing.T) { } defer listener.Close() port := listener.Addr().(*net.TCPAddr).Port - go http.Serve(listener, nil) + go func() { + err := HTTPServe(listener) + if err != nil { + t.Errorf("HTTPServe returned: %v", err) + } + }() ebd := NewExporter("", "") ebd.HandleFunc("/path", func(w http.ResponseWriter, r *http.Request) { diff --git a/go/vt/servenv/flushlogs.go b/go/vt/servenv/flushlogs.go index 6b88e137654..d3ba162249a 100644 --- a/go/vt/servenv/flushlogs.go +++ b/go/vt/servenv/flushlogs.go @@ -25,7 +25,7 @@ import ( func init() { OnInit(func() { - http.HandleFunc("/debug/flushlogs", func(w http.ResponseWriter, r *http.Request) { + HTTPHandleFunc("/debug/flushlogs", func(w http.ResponseWriter, r *http.Request) { logutil.Flush() fmt.Fprint(w, "flushed") }) diff --git a/go/vt/servenv/http.go b/go/vt/servenv/http.go new file mode 100644 index 00000000000..2edb9a76fe8 --- /dev/null +++ b/go/vt/servenv/http.go @@ -0,0 +1,39 @@ +package servenv + +import ( + "errors" + "net" + "net/http" + "net/http/httptest" + "net/http/pprof" +) + +var mux = http.NewServeMux() + +func HTTPHandle(pattern string, handler http.Handler) { + mux.Handle(pattern, handler) +} + +func HTTPHandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) { + mux.HandleFunc(pattern, handler) +} + +func HTTPServe(l net.Listener) error { + err := http.Serve(l, mux) + if errors.Is(err, http.ErrServerClosed) || errors.Is(err, net.ErrClosed) { + return nil + } + return err +} + +func HTTPTestServer() *httptest.Server { + return httptest.NewServer(mux) +} + +func HTTPRegisterProfile() { + HTTPHandleFunc("/debug/pprof/", pprof.Index) + HTTPHandleFunc("/debug/pprof/cmdline", pprof.Cmdline) + HTTPHandleFunc("/debug/pprof/profile", pprof.Profile) + HTTPHandleFunc("/debug/pprof/symbol", pprof.Symbol) + HTTPHandleFunc("/debug/pprof/trace", pprof.Trace) +} diff --git a/go/vt/servenv/liveness.go b/go/vt/servenv/liveness.go index 1b3365501a1..5acd08edf60 100644 --- a/go/vt/servenv/liveness.go +++ b/go/vt/servenv/liveness.go @@ -29,7 +29,7 @@ import ( // further behind on its backlog. func init() { - http.HandleFunc("/debug/liveness", func(rw http.ResponseWriter, r *http.Request) { + HTTPHandleFunc("/debug/liveness", func(rw http.ResponseWriter, r *http.Request) { // Do nothing. Return success immediately. }) } diff --git a/go/vt/servenv/liveness_test.go b/go/vt/servenv/liveness_test.go index 38662e9150a..974e9177d83 100644 --- a/go/vt/servenv/liveness_test.go +++ b/go/vt/servenv/liveness_test.go @@ -19,12 +19,11 @@ package servenv import ( "io" "net/http" - "net/http/httptest" "testing" ) func TestLivenessHandler(t *testing.T) { - server := httptest.NewServer(nil) + server := HTTPTestServer() defer server.Close() resp, err := http.Get(server.URL + "/debug/liveness") diff --git a/go/vt/servenv/pprof.go b/go/vt/servenv/pprof.go index d431dd9239b..d1d8e99588f 100644 --- a/go/vt/servenv/pprof.go +++ b/go/vt/servenv/pprof.go @@ -342,4 +342,5 @@ func init() { fs.StringSliceVar(&pprofFlag, "pprof", pprofFlag, "enable profiling") }) OnInit(pprofInit) + OnInit(HTTPRegisterProfile) } diff --git a/go/vt/servenv/run.go b/go/vt/servenv/run.go index 82dfc285efb..5b585184331 100644 --- a/go/vt/servenv/run.go +++ b/go/vt/servenv/run.go @@ -19,7 +19,6 @@ package servenv import ( "fmt" "net" - "net/http" "net/url" "os" "os/signal" @@ -49,7 +48,12 @@ func Run(port int) { if err != nil { log.Exit(err) } - go http.Serve(l, nil) + go func() { + err := HTTPServe(l) + if err != nil { + log.Errorf("http serve returned unexpected error: %v", err) + } + }() ExitChan = make(chan os.Signal, 1) signal.Notify(ExitChan, syscall.SIGTERM, syscall.SIGINT) diff --git a/go/vt/servenv/servenv.go b/go/vt/servenv/servenv.go index b808573810c..e4464020cbf 100644 --- a/go/vt/servenv/servenv.go +++ b/go/vt/servenv/servenv.go @@ -29,8 +29,6 @@ limitations under the License. package servenv import ( - // register the HTTP handlers for profiling - _ "net/http/pprof" "net/url" "os" "os/signal" diff --git a/go/vt/servenv/status.go b/go/vt/servenv/status.go index 0aa5597f7da..ac912fd881e 100644 --- a/go/vt/servenv/status.go +++ b/go/vt/servenv/status.go @@ -167,12 +167,12 @@ func newStatusPage(name string) *statusPage { } sp.tmpl = template.Must(sp.reparse(nil)) if name == "" { - http.HandleFunc(StatusURLPath(), sp.statusHandler) + HTTPHandleFunc(StatusURLPath(), sp.statusHandler) // Debug profiles are only supported for the top level status page. registerDebugBlockProfileRate() registerDebugMutexProfileFraction() } else { - http.HandleFunc("/"+name+StatusURLPath(), sp.statusHandler) + HTTPHandleFunc("/"+name+StatusURLPath(), sp.statusHandler) } return sp } @@ -277,7 +277,7 @@ func (sp *statusPage) reparse(sections []section) (*template.Template, error) { // Toggle the block profile rate to/from 100%, unless specific rate is passed in func registerDebugBlockProfileRate() { - http.HandleFunc("/debug/blockprofilerate", func(w http.ResponseWriter, r *http.Request) { + HTTPHandleFunc("/debug/blockprofilerate", func(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) return @@ -307,7 +307,7 @@ func registerDebugBlockProfileRate() { // Toggle the mutex profiling fraction to/from 100%, unless specific fraction is passed in func registerDebugMutexProfileFraction() { - http.HandleFunc("/debug/mutexprofilefraction", func(w http.ResponseWriter, r *http.Request) { + HTTPHandleFunc("/debug/mutexprofilefraction", func(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) return diff --git a/go/vt/servenv/status_test.go b/go/vt/servenv/status_test.go index e5d20f12ca6..d55fc8a3a2c 100644 --- a/go/vt/servenv/status_test.go +++ b/go/vt/servenv/status_test.go @@ -19,7 +19,6 @@ package servenv import ( "io" "net/http" - "net/http/httptest" "regexp" "strings" "testing" @@ -43,7 +42,7 @@ func init() { } func TestStatus(t *testing.T) { - server := httptest.NewServer(nil) + server := HTTPTestServer() defer server.Close() resp, err := http.Get(server.URL + StatusURLPath()) @@ -68,7 +67,7 @@ func TestStatus(t *testing.T) { } func TestNamedStatus(t *testing.T) { - server := httptest.NewServer(nil) + server := HTTPTestServer() defer server.Close() name := "test" diff --git a/go/vt/throttler/demo/throttler_demo.go b/go/vt/throttler/demo/throttler_demo.go index 3593bc0806d..615f7c4fc93 100644 --- a/go/vt/throttler/demo/throttler_demo.go +++ b/go/vt/throttler/demo/throttler_demo.go @@ -302,7 +302,7 @@ func main() { servenv.ParseFlags(flagSetName) go servenv.RunDefault() - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/throttlerz", http.StatusTemporaryRedirect) }) diff --git a/go/vt/throttler/throttlerlogz.go b/go/vt/throttler/throttlerlogz.go index a12dc84d567..80ff09b1707 100644 --- a/go/vt/throttler/throttlerlogz.go +++ b/go/vt/throttler/throttlerlogz.go @@ -27,6 +27,7 @@ import ( "golang.org/x/exp/slices" "vitess.io/vitess/go/vt/logz" + "vitess.io/vitess/go/vt/servenv" ) const logHeaderHTML = ` @@ -101,7 +102,7 @@ var ( ) func init() { - http.HandleFunc("/throttlerlogz/", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/throttlerlogz/", func(w http.ResponseWriter, r *http.Request) { throttlerlogzHandler(w, r, GlobalManager) }) } diff --git a/go/vt/throttler/throttlerz.go b/go/vt/throttler/throttlerz.go index c5c6c8832f9..42b9a18284f 100644 --- a/go/vt/throttler/throttlerz.go +++ b/go/vt/throttler/throttlerz.go @@ -24,6 +24,7 @@ import ( "golang.org/x/exp/slices" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/servenv" ) const listHTML = ` @@ -50,7 +51,7 @@ var ( ) func init() { - http.HandleFunc("/throttlerz/", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/throttlerz/", func(w http.ResponseWriter, r *http.Request) { throttlerzHandler(w, r, GlobalManager) }) } diff --git a/go/vt/vtctld/api.go b/go/vt/vtctld/api.go index 07eda0a1470..ee2c970503b 100644 --- a/go/vt/vtctld/api.go +++ b/go/vt/vtctld/api.go @@ -122,7 +122,7 @@ func httpErrorf(w http.ResponseWriter, r *http.Request, format string, args ...a } func handleAPI(apiPath string, handlerFunc func(w http.ResponseWriter, r *http.Request) error) { - http.HandleFunc(apiPrefix+apiPath, func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc(apiPrefix+apiPath, func(w http.ResponseWriter, r *http.Request) { defer func() { if x := recover(); x != nil { httpErrorf(w, r, "uncaught panic: %v", x) diff --git a/go/vt/vtctld/api_test.go b/go/vt/vtctld/api_test.go index 8a7e53c7f2d..37464cd83cb 100644 --- a/go/vt/vtctld/api_test.go +++ b/go/vt/vtctld/api_test.go @@ -22,12 +22,12 @@ import ( "encoding/json" "io" "net/http" - "net/http/httptest" "strings" "testing" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/topo/memorytopo" "vitess.io/vitess/go/vt/wrangler" @@ -46,7 +46,7 @@ func TestAPI(t *testing.T) { cells := []string{"cell1", "cell2"} ts := memorytopo.NewServer(cells...) actionRepo := NewActionRepository(ts) - server := httptest.NewServer(nil) + server := servenv.HTTPTestServer() defer server.Close() ks1 := &topodatapb.Keyspace{ diff --git a/go/vt/vtctld/debug_health.go b/go/vt/vtctld/debug_health.go index c7daba3c478..ca4e1d8aae9 100644 --- a/go/vt/vtctld/debug_health.go +++ b/go/vt/vtctld/debug_health.go @@ -24,12 +24,13 @@ import ( "context" "vitess.io/vitess/go/acl" + "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/topo" ) // RegisterDebugHealthHandler register a debug health http endpoint for a vtcld server func RegisterDebugHealthHandler(ts *topo.Server) { - http.HandleFunc("/debug/health", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/debug/health", func(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.MONITORING); err != nil { acl.SendError(w, err) return diff --git a/go/vt/vtgate/api.go b/go/vt/vtgate/api.go index d4a6fb240d7..d4d7d143b21 100644 --- a/go/vt/vtgate/api.go +++ b/go/vt/vtgate/api.go @@ -24,6 +24,7 @@ import ( "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/servenv" ) // This file implements a REST-style API for the vtgate web interface. @@ -41,7 +42,7 @@ func httpErrorf(w http.ResponseWriter, r *http.Request, format string, args ...a } func handleAPI(apiPath string, handlerFunc func(w http.ResponseWriter, r *http.Request) error) { - http.HandleFunc(apiPrefix+apiPath, func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc(apiPrefix+apiPath, func(w http.ResponseWriter, r *http.Request) { defer func() { if x := recover(); x != nil { httpErrorf(w, r, "uncaught panic: %v", x) diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index 8d877a0b22c..cfa4bae3ed8 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -179,9 +179,9 @@ func NewExecutor( stats.NewCounterFunc("QueryPlanCacheMisses", "Query plan cache misses", func() int64 { return e.plans.Misses() }) - http.Handle(pathQueryPlans, e) - http.Handle(pathScatterStats, e) - http.Handle(pathVSchema, e) + servenv.HTTPHandle(pathQueryPlans, e) + servenv.HTTPHandle(pathScatterStats, e) + servenv.HTTPHandle(pathVSchema, e) }) return e } diff --git a/go/vt/vtgate/querylog.go b/go/vt/vtgate/querylog.go index f7d1af01613..c501c5af2a4 100644 --- a/go/vt/vtgate/querylog.go +++ b/go/vt/vtgate/querylog.go @@ -21,6 +21,7 @@ import ( "sync" "vitess.io/vitess/go/streamlog" + "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/vtgate/logstats" ) @@ -49,13 +50,13 @@ func initQueryLogger(vtg *VTGate) error { SetQueryLogger(streamlog.New[*logstats.LogStats]("VTGate", queryLogBufferSize)) QueryLogger.ServeLogs(QueryLogHandler, streamlog.GetFormatter(QueryLogger)) - http.HandleFunc(QueryLogzHandler, func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc(QueryLogzHandler, func(w http.ResponseWriter, r *http.Request) { ch := QueryLogger.Subscribe("querylogz") defer QueryLogger.Unsubscribe(ch) querylogzHandler(ch, w, r) }) - http.HandleFunc(QueryzHandler, func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc(QueryzHandler, func(w http.ResponseWriter, r *http.Request) { queryzHandler(vtg.executor, w, r) }) diff --git a/go/vt/vtgate/vtgate.go b/go/vt/vtgate/vtgate.go index 381aaab682b..acf796f0408 100644 --- a/go/vt/vtgate/vtgate.go +++ b/go/vt/vtgate/vtgate.go @@ -409,13 +409,13 @@ func resolveAndLoadKeyspace(ctx context.Context, srvResolver *srvtopo.Resolver, } func (vtg *VTGate) registerDebugEnvHandler() { - http.HandleFunc("/debug/env", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/debug/env", func(w http.ResponseWriter, r *http.Request) { debugEnvHandler(vtg, w, r) }) } func (vtg *VTGate) registerDebugHealthHandler() { - http.HandleFunc("/debug/health", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/debug/health", func(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.MONITORING); err != nil { acl.SendError(w, err) return diff --git a/go/vt/vtorc/server/api.go b/go/vt/vtorc/server/api.go index 1a7f0a1c1da..ee840c1abc0 100644 --- a/go/vt/vtorc/server/api.go +++ b/go/vt/vtorc/server/api.go @@ -24,6 +24,7 @@ import ( "vitess.io/vitess/go/acl" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/vtorc/inst" "vitess.io/vitess/go/vt/vtorc/logic" "vitess.io/vitess/go/vt/vtorc/process" @@ -101,7 +102,7 @@ func getACLPermissionLevelForAPI(apiEndpoint string) string { // RegisterVTOrcAPIEndpoints is used to register the VTOrc API endpoints func RegisterVTOrcAPIEndpoints() { for _, apiPath := range vtorcAPIPaths { - http.Handle(apiPath, apiHandler) + servenv.HTTPHandle(apiPath, apiHandler) } } diff --git a/go/vt/vttablet/endtoend/framework/server.go b/go/vt/vttablet/endtoend/framework/server.go index 9ca0aa4fbf7..2fca66f6d93 100644 --- a/go/vt/vttablet/endtoend/framework/server.go +++ b/go/vt/vttablet/endtoend/framework/server.go @@ -24,6 +24,7 @@ import ( "time" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/yaml2" @@ -89,7 +90,12 @@ func StartCustomServer(connParams, connAppDebugParams mysql.ConnParams, dbName s return vterrors.Wrap(err, "could not start listener") } ServerAddress = fmt.Sprintf("http://%s", ln.Addr().String()) - go http.Serve(ln, nil) + go func() { + err := servenv.HTTPServe(ln) + if err != nil { + log.Errorf("HTTPServe failed: %v", err) + } + }() for { time.Sleep(10 * time.Millisecond) response, err := http.Get(fmt.Sprintf("%s/debug/vars", ServerAddress)) diff --git a/go/vt/vttablet/tabletmanager/vreplication/vrlog.go b/go/vt/vttablet/tabletmanager/vreplication/vrlog.go index b55e54bb79c..a36b6ad2336 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vrlog.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vrlog.go @@ -28,6 +28,7 @@ import ( "vitess.io/vitess/go/streamlog" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/servenv" ) var ( @@ -63,7 +64,7 @@ func (stats *VrLogStats) Send(detail string) { } func init() { - http.HandleFunc("/debug/vrlog", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/debug/vrlog", func(w http.ResponseWriter, r *http.Request) { ch := vrLogStatsLogger.Subscribe("vrlogstats") defer vrLogStatsLogger.Unsubscribe(ch) vrlogStatsHandler(ch, w, r) diff --git a/go/vt/vttablet/tabletserver/querylogz.go b/go/vt/vttablet/tabletserver/querylogz.go index f13491846fb..41a40a0720c 100644 --- a/go/vt/vttablet/tabletserver/querylogz.go +++ b/go/vt/vttablet/tabletserver/querylogz.go @@ -26,6 +26,7 @@ import ( "vitess.io/vitess/go/acl" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logz" + "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" ) @@ -86,7 +87,7 @@ var ( ) func init() { - http.HandleFunc("/querylogz", func(w http.ResponseWriter, r *http.Request) { + servenv.HTTPHandleFunc("/querylogz", func(w http.ResponseWriter, r *http.Request) { ch := tabletenv.StatsLogger.Subscribe("querylogz") defer tabletenv.StatsLogger.Unsubscribe(ch) querylogzHandler(ch, w, r) diff --git a/go/vt/vttablet/tabletserver/txlogz.go b/go/vt/vttablet/tabletserver/txlogz.go index 4b0eee4a037..04a2147a7e0 100644 --- a/go/vt/vttablet/tabletserver/txlogz.go +++ b/go/vt/vttablet/tabletserver/txlogz.go @@ -31,6 +31,7 @@ import ( "vitess.io/vitess/go/vt/logz" querypb "vitess.io/vitess/go/vt/proto/query" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" ) @@ -72,7 +73,7 @@ var ( ) func init() { - http.HandleFunc("/txlogz", txlogzHandler) + servenv.HTTPHandleFunc("/txlogz", txlogzHandler) } // txlogzHandler serves a human readable snapshot of the diff --git a/misc/errcheck_excludes.txt b/misc/errcheck_excludes.txt index cd2218d7332..fb689e26288 100644 --- a/misc/errcheck_excludes.txt +++ b/misc/errcheck_excludes.txt @@ -18,7 +18,6 @@ io.WriteString(net/http.ResponseWriter) (net.Listener).Close (net/http.ResponseWriter).Write -net/http.Serve (*os.File).Close os.Remove