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..f4b001383d1 --- /dev/null +++ b/go/vt/servenv/http.go @@ -0,0 +1,54 @@ +/* +Copyright 2023 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package servenv + +import ( + "errors" + "net" + "net/http" + "net/http/pprof" + + "vitess.io/vitess/go/vt/servenv/internal/mux" +) + +// HTTPHandle registers the given handler for the internal servenv mux. +func HTTPHandle(pattern string, handler http.Handler) { + mux.Mux.Handle(pattern, handler) +} + +// HTTPHandleFunc registers the given handler func for the internal servenv mux. +func HTTPHandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) { + mux.Mux.HandleFunc(pattern, handler) +} + +// HTTPServe starts the HTTP server for the internal servenv mux on the listener. +func HTTPServe(l net.Listener) error { + err := http.Serve(l, mux.Mux) + if errors.Is(err, http.ErrServerClosed) || errors.Is(err, net.ErrClosed) { + return nil + } + return err +} + +// HTTPRegisterProfile registers the default pprof HTTP endpoints with the internal servenv 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/internal/mux/mux.go b/go/vt/servenv/internal/mux/mux.go new file mode 100644 index 00000000000..1079f493ff9 --- /dev/null +++ b/go/vt/servenv/internal/mux/mux.go @@ -0,0 +1,21 @@ +/* +Copyright 2023 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package mux + +import "net/http" + +var Mux = http.NewServeMux() 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..80c3befe829 100644 --- a/go/vt/servenv/liveness_test.go +++ b/go/vt/servenv/liveness_test.go @@ -19,12 +19,13 @@ package servenv import ( "io" "net/http" - "net/http/httptest" "testing" + + "vitess.io/vitess/go/vt/servenv/testutils" ) func TestLivenessHandler(t *testing.T) { - server := httptest.NewServer(nil) + server := testutils.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..b020f9cfc83 100644 --- a/go/vt/servenv/status_test.go +++ b/go/vt/servenv/status_test.go @@ -19,13 +19,14 @@ package servenv import ( "io" "net/http" - "net/http/httptest" "regexp" "strings" "testing" "github.com/google/safehtml/template" "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/vt/servenv/testutils" ) func init() { @@ -43,7 +44,7 @@ func init() { } func TestStatus(t *testing.T) { - server := httptest.NewServer(nil) + server := testutils.HTTPTestServer() defer server.Close() resp, err := http.Get(server.URL + StatusURLPath()) @@ -68,7 +69,7 @@ func TestStatus(t *testing.T) { } func TestNamedStatus(t *testing.T) { - server := httptest.NewServer(nil) + server := testutils.HTTPTestServer() defer server.Close() name := "test" diff --git a/go/vt/servenv/testutils/testutils.go b/go/vt/servenv/testutils/testutils.go new file mode 100644 index 00000000000..de716bcd94e --- /dev/null +++ b/go/vt/servenv/testutils/testutils.go @@ -0,0 +1,28 @@ +/* +Copyright 2019 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testutils + +import ( + "net/http/httptest" + + "vitess.io/vitess/go/vt/servenv/internal/mux" +) + +// HTTPTestServer returns a httptest.Server for the internal servenv mux. +func HTTPTestServer() *httptest.Server { + return httptest.NewServer(mux.Mux) +} 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..b00de6b0d09 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/testutils" "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 := testutils.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