Compare commits
6 commits
master
...
add-http-p
Author | SHA1 | Date | |
---|---|---|---|
|
0af7e6a1dd | ||
|
c14ad0f27b | ||
|
af958676b8 | ||
|
70779b26ad | ||
|
90aa8efb29 | ||
|
dd7f12f7c0 |
5 changed files with 72 additions and 33 deletions
16
control.go
16
control.go
|
@ -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()
|
||||||
|
|
|
@ -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
34
http.go
Normal 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
17
main.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
34
stats.go
34
stats.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue