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  }