Compare commits

...
Sign in to create a new pull request.

6 commits

Author SHA1 Message Date
Tim Vaillancourt
0af7e6a1dd improve comments
Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com>
2023-07-07 17:06:19 +02:00
Tim Vaillancourt
c14ad0f27b Cleanup code comment
Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com>
2023-07-07 02:07:33 +02:00
Tim Vaillancourt
af958676b8 Cleanup code
Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com>
2023-07-07 02:00:30 +02:00
Tim Vaillancourt
70779b26ad Fix typo in log
Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com>
2023-07-07 01:43:42 +02:00
Tim Vaillancourt
90aa8efb29 remove dupe stats.path check
Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com>
2023-07-07 01:37:36 +02:00
Tim Vaillancourt
dd7f12f7c0 Add http pprof profiling endpoint
Signed-off-by: Tim Vaillancourt <tim@timvaillancourt.com>
2023-07-07 01:35:19 +02:00
5 changed files with 72 additions and 33 deletions

View file

@ -18,12 +18,12 @@ import (
// core. This means copying IP objects, slices, de-referencing pointers and taking the actual value, etc // core. This means copying IP objects, slices, de-referencing pointers and taking the actual value, etc
type Control struct { type Control struct {
f *Interface f *Interface
l *logrus.Logger l *logrus.Logger
cancel context.CancelFunc cancel context.CancelFunc
sshStart func() sshStart func()
statsStart func() httpStart func()
dnsStart func() dnsStart func()
} }
type ControlHostInfo struct { type ControlHostInfo struct {
@ -48,8 +48,8 @@ func (c *Control) Start() {
if c.sshStart != nil { if c.sshStart != nil {
go c.sshStart() go c.sshStart()
} }
if c.statsStart != nil { if c.httpStart != nil {
go c.statsStart() go c.httpStart()
} }
if c.dnsStart != nil { if c.dnsStart != nil {
go c.dnsStart() go c.dnsStart()

View file

@ -244,6 +244,9 @@ logging:
# As an example, to log as RFC3339 with millisecond precision, set to: # As an example, to log as RFC3339 with millisecond precision, set to:
#timestamp_format: "2006-01-02T15:04:05.000Z07:00" #timestamp_format: "2006-01-02T15:04:05.000Z07:00"
#http:
#listen: 127.0.0.1:8080
#stats: #stats:
#type: graphite #type: graphite
#prefix: nebula #prefix: nebula
@ -252,7 +255,6 @@ logging:
#interval: 10s #interval: 10s
#type: prometheus #type: prometheus
#listen: 127.0.0.1:8080
#path: /metrics #path: /metrics
#namespace: prometheusns #namespace: prometheusns
#subsystem: nebula #subsystem: nebula

34
http.go Normal file
View file

@ -0,0 +1,34 @@
package nebula
import (
"fmt"
"net/http"
_ "net/http/pprof"
"github.com/sirupsen/logrus"
"github.com/slackhq/nebula/config"
)
// startHttp returns a function to start an http server with pprof support and optionally a provided stats
// http handler.
func startHttp(l *logrus.Logger, c *config.C, listen string, statsHandler statsHandlerFunc) (func(), error) {
if listen == "" {
return nil, nil
}
var statsPath string
if statsHandler != nil {
statsPath = c.GetString("stats.path", "")
if statsPath == "" {
return nil, fmt.Errorf("stats.path should not be empty")
}
}
return func() {
l.Infof("Go pprof handler listening on %s at /debug/pprof", listen)
if statsHandler != nil {
http.Handle(statsPath, statsHandler(listen, statsPath))
}
l.Fatal(http.ListenAndServe(listen, nil))
}, nil
}

17
main.go
View file

@ -324,14 +324,25 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg
go lightHouse.LhUpdateWorker(ctx, ifce) go lightHouse.LhUpdateWorker(ctx, ifce)
} }
httpListen := c.GetString("http.listen", "")
if httpListen == "" {
if httpListen = c.GetString("stats.listen", ""); httpListen != "" {
l.Warn("http.listen is undef, falling back to stats.listen. stats.listen will be deprecated in a future release.")
}
}
// TODO - stats third-party modules start uncancellable goroutines. Update those libs to accept // TODO - stats third-party modules start uncancellable goroutines. Update those libs to accept
// a context so that they can exit when the context is Done. // a context so that they can exit when the context is Done.
statsStart, err := startStats(l, c, buildVersion, configTest) statsHTTPHandler, err := startStats(l, c, httpListen, buildVersion, configTest)
if err != nil { if err != nil {
return nil, util.NewContextualError("Failed to start stats emitter", nil, err) return nil, util.NewContextualError("Failed to start stats emitter", nil, err)
} }
httpStart, err := startHttp(l, c, httpListen, statsHTTPHandler)
if err != nil {
return nil, util.NewContextualError("Failed to start http server", nil, err)
}
if configTest { if configTest {
return nil, nil return nil, nil
} }
@ -348,5 +359,5 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg
dnsStart = dnsMain(l, hostMap, c) dnsStart = dnsMain(l, hostMap, c)
} }
return &Control{ifce, l, cancel, sshStart, statsStart, dnsStart}, nil return &Control{ifce, l, cancel, sshStart, httpStart, dnsStart}, nil
} }

View file

@ -3,7 +3,6 @@ package nebula
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"net" "net"
"net/http" "net/http"
"runtime" "runtime"
@ -19,10 +18,12 @@ import (
"github.com/slackhq/nebula/config" "github.com/slackhq/nebula/config"
) )
type statsHandlerFunc func(listen, path string) http.Handler
// startStats initializes stats from config. On success, if any further work // startStats initializes stats from config. On success, if any further work
// is needed to serve stats, it returns a func to handle that work. If no // is needed to serve stats, it returns a statsHandlerFunc for that work. If
// work is needed, it'll return nil. On failure, it returns nil, error. // no work is needed, it'll return nil. On failure, it returns nil, error.
func startStats(l *logrus.Logger, c *config.C, buildVersion string, configTest bool) (func(), error) { func startStats(l *logrus.Logger, c *config.C, listen, buildVersion string, configTest bool) (f statsHandlerFunc, err error) {
mType := c.GetString("stats.type", "") mType := c.GetString("stats.type", "")
if mType == "" || mType == "none" { if mType == "" || mType == "none" {
return nil, nil return nil, nil
@ -33,7 +34,6 @@ func startStats(l *logrus.Logger, c *config.C, buildVersion string, configTest b
return nil, fmt.Errorf("stats.interval was an invalid duration: %s", c.GetString("stats.interval", "")) return nil, fmt.Errorf("stats.interval was an invalid duration: %s", c.GetString("stats.interval", ""))
} }
var startFn func()
switch mType { switch mType {
case "graphite": case "graphite":
err := startGraphiteStats(l, interval, c, configTest) err := startGraphiteStats(l, interval, c, configTest)
@ -41,8 +41,7 @@ func startStats(l *logrus.Logger, c *config.C, buildVersion string, configTest b
return nil, err return nil, err
} }
case "prometheus": case "prometheus":
var err error f, err = startPrometheusStats(l, interval, c, listen, buildVersion, configTest)
startFn, err = startPrometheusStats(l, interval, c, buildVersion, configTest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -56,7 +55,7 @@ func startStats(l *logrus.Logger, c *config.C, buildVersion string, configTest b
go metrics.CaptureDebugGCStats(metrics.DefaultRegistry, interval) go metrics.CaptureDebugGCStats(metrics.DefaultRegistry, interval)
go metrics.CaptureRuntimeMemStats(metrics.DefaultRegistry, interval) go metrics.CaptureRuntimeMemStats(metrics.DefaultRegistry, interval)
return startFn, nil return f, nil
} }
func startGraphiteStats(l *logrus.Logger, i time.Duration, c *config.C, configTest bool) error { func startGraphiteStats(l *logrus.Logger, i time.Duration, c *config.C, configTest bool) error {
@ -79,18 +78,12 @@ func startGraphiteStats(l *logrus.Logger, i time.Duration, c *config.C, configTe
return nil return nil
} }
func startPrometheusStats(l *logrus.Logger, i time.Duration, c *config.C, buildVersion string, configTest bool) (func(), error) { func startPrometheusStats(l *logrus.Logger, i time.Duration, c *config.C, listen, buildVersion string, configTest bool) (statsHandlerFunc, error) {
namespace := c.GetString("stats.namespace", "") namespace := c.GetString("stats.namespace", "")
subsystem := c.GetString("stats.subsystem", "") subsystem := c.GetString("stats.subsystem", "")
listen := c.GetString("stats.listen", "")
if listen == "" { if listen == "" {
return nil, fmt.Errorf("stats.listen should not be empty") return nil, fmt.Errorf("http.listen or stats.listen must be defined to use Prometheus stats")
}
path := c.GetString("stats.path", "")
if path == "" {
return nil, fmt.Errorf("stats.path should not be empty")
} }
pr := prometheus.NewRegistry() pr := prometheus.NewRegistry()
@ -114,14 +107,13 @@ func startPrometheusStats(l *logrus.Logger, i time.Duration, c *config.C, buildV
pr.MustRegister(g) pr.MustRegister(g)
g.Set(1) g.Set(1)
var startFn func() var startHandler statsHandlerFunc
if !configTest { if !configTest {
startFn = func() { startHandler = func(listen, path string) http.Handler {
l.Infof("Prometheus stats listening on %s at %s", listen, path) l.Infof("Prometheus stats listening on %s at %s", listen, path)
http.Handle(path, promhttp.HandlerFor(pr, promhttp.HandlerOpts{ErrorLog: l})) return promhttp.HandlerFor(pr, promhttp.HandlerOpts{ErrorLog: l})
log.Fatal(http.ListenAndServe(listen, nil))
} }
} }
return startFn, nil return startHandler, nil
} }