diff --git a/Makefile b/Makefile index c01b908..89cf5e3 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,29 @@ GOMINVERSION = 1.16 NEBULA_CMD_PATH = "./cmd/nebula" -BUILD_NUMBER ?= dev+$(shell date -u '+%Y%m%d%H%M%S') GO111MODULE = on export GO111MODULE -# Ensure the version of go we are using is at least what is defined in GOMINVERSION at the top of this file -GOVERSION := $(shell go version | awk '{print substr($$3, 3)}') -GOISMIN := $(shell expr "$(GOVERSION)" ">=" "$(GOMINVERSION)") -ifneq "$(GOISMIN)" "1" -$(error "go version $(GOVERSION) is not supported, upgrade to $(GOMINVERSION) or above") +# Set up OS specific bits +ifeq ($(OS),Windows_NT) + #TODO: we should be able to ditch awk as well + GOVERSION := $(shell go version | awk "{print substr($$3, 3)}") + GOISMIN := $(shell IF "$(GOVERSION)" GEQ "$(GOMINVERSION)" ECHO 1) + NEBULA_CMD_SUFFIX = .exe + NULL_FILE = nul +else + GOVERSION := $(shell go version | awk '{print substr($$3, 3)}') + GOISMIN := $(shell expr "$(GOVERSION)" ">=" "$(GOMINVERSION)") + NEBULA_CMD_SUFFIX = + NULL_FILE = /dev/null +endif + +# Only defined the build number if we haven't already +ifndef BUILD_NUMBER + ifeq ($(shell git describe --exact-match 2>$(NULL_FILE)),) + BUILD_NUMBER = $(shell git describe --abbrev=0 --match "v*" | cut -dv -f2)-$(shell git branch --show-current)-$(shell git describe --long --dirty | cut -d- -f2-) + else + BUILD_NUMBER = $(shell git describe --exact-match --dirty | cut -dv -f2) + endif endif LDFLAGS = -X main.Build=$(BUILD_NUMBER) @@ -67,8 +82,8 @@ bin-freebsd: build/freebsd-amd64/nebula build/freebsd-amd64/nebula-cert mv $? . bin: - go build $(BUILD_ARGS) -ldflags "$(LDFLAGS)" -o ./nebula ${NEBULA_CMD_PATH} - go build $(BUILD_ARGS) -ldflags "$(LDFLAGS)" -o ./nebula-cert ./cmd/nebula-cert + go build $(BUILD_ARGS) -ldflags "$(LDFLAGS)" -o ./nebula${NEBULA_CMD_SUFFIX} ${NEBULA_CMD_PATH} + go build $(BUILD_ARGS) -ldflags "$(LDFLAGS)" -o ./nebula-cert${NEBULA_CMD_SUFFIX} ./cmd/nebula-cert install: go install $(BUILD_ARGS) -ldflags "$(LDFLAGS)" ${NEBULA_CMD_PATH} @@ -134,10 +149,10 @@ cert/cert.pb.go: cert/cert.proto .FORCE $(MAKE) -C cert cert.pb.go service: - @echo > /dev/null + @echo > $(NULL_FILE) $(eval NEBULA_CMD_PATH := "./cmd/nebula-service") ifeq ($(words $(MAKECMDGOALS)),1) - $(MAKE) service ${.DEFAULT_GOAL} --no-print-directory + @$(MAKE) service ${.DEFAULT_GOAL} --no-print-directory endif bin-docker: bin build/linux-amd64/nebula build/linux-amd64/nebula-cert diff --git a/cmd/nebula-service/logs_generic.go b/cmd/nebula-service/logs_generic.go new file mode 100644 index 0000000..5bbedc2 --- /dev/null +++ b/cmd/nebula-service/logs_generic.go @@ -0,0 +1,9 @@ +// +build !windows + +package main + +import "github.com/sirupsen/logrus" + +func HookLogger(l *logrus.Logger) { + // Do nothing, let the logs flow to stdout/stderr +} diff --git a/cmd/nebula-service/logs_windows.go b/cmd/nebula-service/logs_windows.go new file mode 100644 index 0000000..af6480e --- /dev/null +++ b/cmd/nebula-service/logs_windows.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/kardianos/service" + "github.com/sirupsen/logrus" +) + +// HookLogger routes the logrus logs through the service logger so that they end up in the Windows Event Viewer +// logrus output will be discarded +func HookLogger(l *logrus.Logger) { + l.AddHook(newLogHook(logger)) + l.SetOutput(ioutil.Discard) +} + +type logHook struct { + sl service.Logger +} + +func newLogHook(sl service.Logger) *logHook { + return &logHook{sl: sl} +} + +func (h *logHook) Fire(entry *logrus.Entry) error { + line, err := entry.String() + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err) + return err + } + + switch entry.Level { + case logrus.PanicLevel: + return h.sl.Error(line) + case logrus.FatalLevel: + return h.sl.Error(line) + case logrus.ErrorLevel: + return h.sl.Error(line) + case logrus.WarnLevel: + return h.sl.Warning(line) + case logrus.InfoLevel: + return h.sl.Info(line) + case logrus.DebugLevel: + return h.sl.Info(line) + default: + return nil + } +} + +func (h *logHook) Levels() []logrus.Level { + return logrus.AllLevels +} diff --git a/cmd/nebula-service/service.go b/cmd/nebula-service/service.go index 03336b6..be2dee0 100644 --- a/cmd/nebula-service/service.go +++ b/cmd/nebula-service/service.go @@ -25,7 +25,7 @@ func (p *program) Start(s service.Service) error { logger.Info("Nebula service starting.") l := logrus.New() - l.Out = os.Stdout + HookLogger(l) config := nebula.NewConfig(l) err := config.Load(*p.configPath) @@ -70,6 +70,10 @@ func doService(configPath *string, configTest *bool, build string, serviceFlag * build: build, } + // Here are what the different loggers are doing: + // - `log` is the standard go log utility, meant to be used while the process is still attached to stdout/stderr + // - `logger` is the service log utility that may be attached to a special place depending on OS (Windows will have it attached to the event log) + // - above, in `Run` we create a `logrus.Logger` which is what nebula expects to use s, err := service.New(prg, svcConfig) if err != nil { log.Fatal(err) @@ -85,6 +89,7 @@ func doService(configPath *string, configTest *bool, build string, serviceFlag * for { err := <-errs if err != nil { + // Route any errors from the system logger to stdout as a best effort to notice issues there log.Print(err) } } @@ -94,6 +99,7 @@ func doService(configPath *string, configTest *bool, build string, serviceFlag * case "run": err = s.Run() if err != nil { + // Route any errors to the system logger logger.Error(err) } default: