github.com/thanos-io/thanos@v0.32.5/pkg/server/http/http.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package http 5 6 import ( 7 "context" 8 "net/http" 9 "net/http/pprof" 10 11 "github.com/felixge/fgprof" 12 "github.com/go-kit/log" 13 "github.com/go-kit/log/level" 14 "github.com/pkg/errors" 15 "github.com/prometheus/client_golang/prometheus" 16 "github.com/prometheus/client_golang/prometheus/promhttp" 17 toolkit_web "github.com/prometheus/exporter-toolkit/web" 18 "golang.org/x/net/http2" 19 "golang.org/x/net/http2/h2c" 20 21 "github.com/thanos-io/thanos/pkg/component" 22 "github.com/thanos-io/thanos/pkg/prober" 23 ) 24 25 // A Server defines parameters for serve HTTP requests, a wrapper around http.Server. 26 type Server struct { 27 logger log.Logger 28 comp component.Component 29 prober *prober.HTTPProbe 30 31 mux *http.ServeMux 32 srv *http.Server 33 34 opts options 35 } 36 37 // New creates a new Server. 38 func New(logger log.Logger, reg *prometheus.Registry, comp component.Component, prober *prober.HTTPProbe, opts ...Option) *Server { 39 options := options{} 40 for _, o := range opts { 41 o.apply(&options) 42 } 43 44 mux := http.NewServeMux() 45 if options.mux != nil { 46 mux = options.mux 47 } 48 49 registerMetrics(mux, reg) 50 registerProbes(mux, prober, logger) 51 registerProfiler(mux) 52 53 var h http.Handler 54 if options.enableH2C { 55 h2s := &http2.Server{} 56 h = h2c.NewHandler(mux, h2s) 57 } else { 58 h = mux 59 } 60 61 return &Server{ 62 logger: log.With(logger, "service", "http/server", "component", comp.String()), 63 comp: comp, 64 prober: prober, 65 mux: mux, 66 srv: &http.Server{Addr: options.listen, Handler: h}, 67 opts: options, 68 } 69 } 70 71 // ListenAndServe listens on the TCP network address and handles requests on incoming connections. 72 func (s *Server) ListenAndServe() error { 73 level.Info(s.logger).Log("msg", "listening for requests and metrics", "address", s.opts.listen) 74 err := toolkit_web.Validate(s.opts.tlsConfigPath) 75 if err != nil { 76 return errors.Wrap(err, "server could not be started") 77 } 78 79 flags := &toolkit_web.FlagConfig{ 80 WebListenAddresses: &([]string{s.opts.listen}), 81 WebSystemdSocket: ofBool(false), 82 WebConfigFile: &s.opts.tlsConfigPath, 83 } 84 85 return errors.Wrap(toolkit_web.ListenAndServe(s.srv, flags, s.logger), "serve HTTP and metrics") 86 } 87 88 // Shutdown gracefully shuts down the server by waiting, 89 // for specified amount of time (by gracePeriod) for connections to return to idle and then shut down. 90 func (s *Server) Shutdown(err error) { 91 level.Info(s.logger).Log("msg", "internal server is shutting down", "err", err) 92 if err == http.ErrServerClosed { 93 level.Warn(s.logger).Log("msg", "internal server closed unexpectedly") 94 return 95 } 96 97 if s.opts.gracePeriod == 0 { 98 s.srv.Close() 99 level.Info(s.logger).Log("msg", "internal server is shutdown", "err", err) 100 return 101 } 102 103 ctx, cancel := context.WithTimeout(context.Background(), s.opts.gracePeriod) 104 defer cancel() 105 106 if err := s.srv.Shutdown(ctx); err != nil { 107 level.Error(s.logger).Log("msg", "internal server shut down failed", "err", err) 108 return 109 } 110 level.Info(s.logger).Log("msg", "internal server is shutdown gracefully", "err", err) 111 } 112 113 // Handle registers the handler for the given pattern. 114 func (s *Server) Handle(pattern string, handler http.Handler) { 115 s.mux.Handle(pattern, handler) 116 } 117 118 func registerProfiler(mux *http.ServeMux) { 119 mux.HandleFunc("/debug/pprof/", pprof.Index) 120 mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) 121 mux.HandleFunc("/debug/pprof/profile", pprof.Profile) 122 mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) 123 mux.HandleFunc("/debug/pprof/trace", pprof.Trace) 124 mux.Handle("/debug/fgprof", fgprof.Handler()) 125 } 126 127 func registerMetrics(mux *http.ServeMux, g prometheus.Gatherer) { 128 if g != nil { 129 mux.Handle("/metrics", promhttp.HandlerFor(g, promhttp.HandlerOpts{ 130 EnableOpenMetrics: true, 131 })) 132 } 133 } 134 135 func registerProbes(mux *http.ServeMux, p *prober.HTTPProbe, logger log.Logger) { 136 if p != nil { 137 mux.Handle("/-/healthy", p.HealthyHandler(logger)) 138 mux.Handle("/-/ready", p.ReadyHandler(logger)) 139 } 140 } 141 142 // Helper for exporter toolkit FlagConfig. 143 func ofBool(i bool) *bool { 144 return &i 145 }