Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pkg/loop: rm PromServerOpts; export PromServer fields #200

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 22 additions & 32 deletions pkg/loop/prom.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,64 +15,54 @@ import (
)

type PromServer struct {
port int
Port int
Logger logger.Logger // required
Handler http.Handler // optional

srvrDone chan struct{} // closed when the http server is done
srvr *http.Server
tcpListener *net.TCPListener
lggr logger.Logger

handler http.Handler
}

type PromServerOpts struct {
Handler http.Handler
}

func NewPromServer(port int, lggr logger.Logger) *PromServer {
return PromServerOpts{}.New(port, lggr)
}

func (o PromServerOpts) New(port int, lggr logger.Logger) *PromServer {
s := &PromServer{
port: port,
lggr: lggr,
srvrDone: make(chan struct{}),
srvr: &http.Server{
// reasonable default based on typical prom poll interval of 15s.
ReadTimeout: 5 * time.Second,
},

handler: o.Handler,
func (p *PromServer) init() *PromServer {
p.srvrDone = make(chan struct{})
p.srvr = &http.Server{
// reasonable default based on typical prom poll interval of 15s.
ReadTimeout: 5 * time.Second,
}
if s.handler == nil {
s.handler = promhttp.HandlerFor(
if p.Handler == nil {
p.Handler = promhttp.HandlerFor(
prometheus.DefaultGatherer,
promhttp.HandlerOpts{
EnableOpenMetrics: true,
},
)
}
return s
return p
}

// Start starts HTTP server on specified port to handle metrics requests
func (p *PromServer) Start() error {
p.lggr.Debugf("Starting prom server on port %d", p.port)
if p.Logger == nil {
return errors.New("nil Logger")
}
p.init()
p.Logger.Debugf("Starting prom server on port %d", p.Port)
err := p.setupListener()
if err != nil {
return err
}

http.Handle("/metrics", p.handler)
http.Handle("/metrics", p.Handler)

go func() {
defer close(p.srvrDone)
err := p.srvr.Serve(p.tcpListener)
if errors.Is(err, net.ErrClosed) {
// ErrClose is expected on gracefully shutdown
p.lggr.Warnf("%s closed", p.Name())
p.Logger.Warnf("%s closed", p.Name())
} else {
p.lggr.Errorf("%s: %s", p.Name(), err)
p.Logger.Errorf("%s: %s", p.Name(), err)
}

}()
Expand All @@ -88,14 +78,14 @@ func (p *PromServer) Close() error {

// Name of the server
func (p *PromServer) Name() string {
return fmt.Sprintf("%s-prom-server", p.lggr.Name())
return fmt.Sprintf("%s-prom-server", p.Logger.Name())
}

// setupListener creates explicit listener so that we can resolve `:0` port, which is needed for testing
// if we didn't need the resolved addr, or could pick a static port we could use p.srvr.ListenAndServer
func (p *PromServer) setupListener() error {
l, err := net.ListenTCP("tcp", &net.TCPAddr{
Port: p.port,
Port: p.Port,
})
if err != nil {
return err
Expand Down
10 changes: 5 additions & 5 deletions pkg/loop/prom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ func TestPromServer(t *testing.T) {
testReg.MustRegister(testMetric)
testMetric.Inc()

s := PromServerOpts{Handler: testHandler}.New(0, logger.Test(t))
s := &PromServer{Handler: testHandler, Logger: logger.Test(t)}
// check that port is not resolved yet
require.Equal(t, -1, s.Port())
require.Equal(t, -1, s.ResolvedPort())
require.NoError(t, s.Start())

url := fmt.Sprintf("http://localhost:%d/metrics", s.Port())
url := fmt.Sprintf("http://localhost:%d/metrics", s.ResolvedPort())
resp, err := http.Get(url) //nolint
require.NoError(t, err)
require.NoError(t, err, "endpoint %s", url)
Expand All @@ -42,9 +42,9 @@ func TestPromServer(t *testing.T) {
require.NoError(t, s.Close())
}

// Port is the resolved port and is only known after Start().
// ResolvedPort is the resolved port and is only known after Start().
// returns -1 before it is resolved or if there was an error during resolution.
func (p *PromServer) Port() int {
func (p *PromServer) ResolvedPort() int {
if p.tcpListener == nil {
return -1
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/loop/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (s *Server) start() error {
s.Logger.Errorf("Failed to setup tracing: %s", err)
}

s.promServer = NewPromServer(envCfg.PrometheusPort, s.Logger)
s.promServer = &PromServer{Port: envCfg.PrometheusPort, Logger: s.Logger}
if err := s.promServer.Start(); err != nil {
return fmt.Errorf("error starting prometheus server: %w", err)
}
Expand Down