[#493] Refactor serving of prometheus and pprof services

Rename `util/profiler` package to `httputil` and refactor it:

  * simplify utility HTTP server;

  * make more generic server's parameters in order to remove `viper.Viper`
    dependency;

  * use single constructor for creating the pprof and prometheus servers;

  * replace `enabled` config value with empty-check of the network address.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-05-12 01:59:05 +03:00 committed by Alex Vanin
parent 6339f1a468
commit 8d17dab86e
15 changed files with 295 additions and 304 deletions

44
pkg/util/http/calls.go Normal file
View file

@ -0,0 +1,44 @@
package httputil
import (
"context"
"net/http"
"github.com/pkg/errors"
)
// Serve listens and serves internal HTTP server.
//
// Returns any error returned by internal server
// except http.ErrServerClosed.
//
// After Shutdown call, Serve has no effect and
// returned error is always nil.
func (x *Server) Serve() error {
err := x.srv.ListenAndServe()
// http.ErrServerClosed is returned on server shutdown
// so we ignore this error.
if err != nil && errors.Is(err, http.ErrServerClosed) {
err = nil
}
return err
}
// Shutdown gracefully shuts down internal HTTP server.
//
// Shutdown is called with context which expires after
// configured timeout.
//
// Once Shutdown has been called on a server, it may not be reused;
// future calls to Serve method will have no effect.
func (x *Server) Shutdown() error {
ctx, cancel := context.WithTimeout(context.Background(), x.shutdownTimeout)
err := x.srv.Shutdown(ctx)
cancel()
return err
}

26
pkg/util/http/opts.go Normal file
View file

@ -0,0 +1,26 @@
package httputil
import (
"time"
)
// Option sets an optional parameter of Server.
type Option func(*cfg)
type cfg struct {
shutdownTimeout time.Duration
}
func defaultCfg() *cfg {
return &cfg{
shutdownTimeout: 15 * time.Second,
}
}
// WithShutdownTimeout returns option to set shutdown timeout
// of the internal HTTP server.
func WithShutdownTimeout(dur time.Duration) Option {
return func(c *cfg) {
c.shutdownTimeout = dur
}
}

16
pkg/util/http/pprof.go Normal file
View file

@ -0,0 +1,16 @@
package httputil
import (
"net/http"
"net/http/pprof"
)
// initializes pprof package in order to
// register Prometheus handlers on http.DefaultServeMux.
var _ = pprof.Handler("")
// Handler returns http.Handler for the
// Prometheus metrics collector.
func Handler() http.Handler {
return http.DefaultServeMux
}

87
pkg/util/http/server.go Normal file
View file

@ -0,0 +1,87 @@
package httputil
import (
"fmt"
"net/http"
"time"
)
// Prm groups the required parameters of the Server's constructor.
//
// All values must comply with the requirements imposed on them.
// Passing incorrect parameter values will result in constructor
// failure (error or panic depending on the implementation).
type Prm struct {
// TCP address for the server to listen on.
//
// Must be a valid TCP address.
Address string
// Must not be nil.
Handler http.Handler
}
// Server represents a wrapper over http.Server
// that provides interface to start and stop
// listening routine.
//
// For correct operation, Server must be created
// using the constructor (New) based on the required parameters
// and optional components. After successful creation,
// Server is immediately ready to work through API.
type Server struct {
shutdownTimeout time.Duration
srv *http.Server
}
const invalidValFmt = "invalid %s %s (%T): %v"
func panicOnPrmValue(n string, v interface{}) {
panicOnValue("parameter", n, v)
}
func panicOnOptValue(n string, v interface{}) {
panicOnValue("option", n, v)
}
func panicOnValue(t, n string, v interface{}) {
panic(fmt.Sprintf(invalidValFmt, t, n, v, v))
}
// New creates a new instance of the Server.
//
// Panics if at least one value of the parameters is invalid.
//
// Panics if at least one of next optinal parameters is invalid:
// * shutdown timeout is non-positive.
//
// The created Server does not require additional
// initialization and is completely ready for work.
func New(prm Prm, opts ...Option) *Server {
switch {
case prm.Address == "":
panicOnPrmValue("Address", prm.Address)
case prm.Handler == nil:
panicOnPrmValue("Handler", prm.Handler)
}
c := defaultCfg()
for _, o := range opts {
o(c)
}
switch {
case c.shutdownTimeout <= 0:
panicOnOptValue("shutdown timeout", c.shutdownTimeout)
}
return &Server{
shutdownTimeout: c.shutdownTimeout,
srv: &http.Server{
Addr: prm.Address,
Handler: prm.Handler,
},
}
}