Skip to content

Commit

Permalink
Refactored Windows Service code to use kardianos library
Browse files Browse the repository at this point in the history
  • Loading branch information
james-bebbington committed Jun 18, 2020
1 parent 9028089 commit 07b4b17
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 49 deletions.
3 changes: 1 addition & 2 deletions cmd/otelcol/main_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ func main() {
}

func runService(params service.Parameters) {
// do not need to supply service name when startup is invoked through Service Control Manager directly
err := svc.Run("", service.NewWindowsService(params))
err := service.RunWindowsService(params)
if err != nil {
log.Fatalf("failed to start service: %v", err)
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
github.com/hashicorp/consul/api v1.2.0 // indirect
github.com/jaegertracing/jaeger v1.17.0
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024
github.com/kardianos/service v1.1.0
github.com/mjibson/esc v0.2.0
github.com/open-telemetry/opentelemetry-proto v0.3.0
github.com/openzipkin/zipkin-go v0.2.1
Expand Down
4 changes: 3 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/kardianos/service v1.1.0 h1:QV2SiEeWK42P0aEmGcsAgjApw/lRxkwopvT+Gu6t1/0=
github.com/kardianos/service v1.1.0/go.mod h1:RrJI2xn5vve/r32U5suTbeaSGoMU6GbNPoj36CVYcHc=
github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
Expand Down Expand Up @@ -1170,7 +1172,6 @@ go.opencensus.io v0.22.1 h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io v0.1.0 h1:EANZoRCOP+A3faIlw/iN6YEWoYb1vleZRKm1EvH8T48=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
Expand Down Expand Up @@ -1316,6 +1317,7 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
75 changes: 29 additions & 46 deletions service/service_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,87 +21,70 @@ import (
"log"
"syscall"

svc "github.com/kardianos/service"
"go.uber.org/zap/zapcore"
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/eventlog"
)

type WindowsService struct {
app *Application
params Parameters
}

func NewWindowsService(params Parameters) *WindowsService {
return &WindowsService{params: params}
}

func (s *WindowsService) Execute(args []string, requests <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
if len(args) == 0 {
log.Fatal("expected first argument supplied to service.Execute to be the service name")
}

changes <- svc.Status{State: svc.StartPending}
s.start(args[0], s.params)
changes <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}

for req := range requests {
switch req.Cmd {
case svc.Interrogate:
changes <- req.CurrentStatus
case svc.Stop, svc.Shutdown:
s.stop()
return
default:
log.Fatalf(fmt.Sprintf("unexpected control request #%d", req))
}
func RunWindowsService(params Parameters) error {
// Can supply any non-empty service name when startup is invoked through Service Control Manager
// directly, however that name will be returned when the service name is referenced internally
// (e.g. as the Event Viewer Logger Source)
s, err := svc.New(&WindowsService{params: params}, &svc.Config{Name: "OpenTelemetry Collector"})
if err != nil {
return err
}

return
return s.Run()
}

func (s *WindowsService) start(logSourceName string, params Parameters) {
var err error
s.app, err = newWithEventViewerLoggingHook(logSourceName, params)
func (m *WindowsService) Start(s svc.Service) error {
logger, err := s.Logger(make(chan error, 500))
if err != nil {
log.Fatal(err)
}

m.app, err = newWithEventViewerLoggingHook(logger, m.params)
if err != nil {
log.Fatal(err)
}

// app.Start blocks until receiving a SIGTERM signal, so we need to start it asynchronously
go func() {
err = s.app.Start()
err = m.app.Start()
if err != nil {
log.Fatalf("application run finished with error: %v", err)
}
}()

// wait until the app is in the Running state
for state := range s.app.GetStateChannel() {
for state := range m.app.GetStateChannel() {
if state == Running {
break
}
}

return nil
}

func (s *WindowsService) stop() {
// simulate a SIGTERM signal to terminate the application
s.app.signalsChannel <- syscall.SIGTERM
func (m *WindowsService) Stop(s svc.Service) error {
m.app.signalsChannel <- syscall.SIGTERM

// wait until the app is in the Closed state
for state := range s.app.GetStateChannel() {
for state := range m.app.GetStateChannel() {
if state == Closed {
break
}
}

s.app = nil
return nil
}

func newWithEventViewerLoggingHook(serviceName string, params Parameters) (*Application, error) {
elog, err := eventlog.Open(serviceName)
if err != nil {
return nil, fmt.Errorf("failed to open event log: %v", err)
}

func newWithEventViewerLoggingHook(logger svc.Logger, params Parameters) (*Application, error) {
params.LoggingHooks = append(
params.LoggingHooks,
func(entry zapcore.Entry) error {
Expand All @@ -110,13 +93,13 @@ func newWithEventViewerLoggingHook(serviceName string, params Parameters) (*Appl
switch entry.Level {
case zapcore.FatalLevel, zapcore.PanicLevel, zapcore.DPanicLevel:
// golang.org/x/sys/windows/svc/eventlog does not support Critical level event logs
return elog.Error(3, msg)
return logger.Error(msg)
case zapcore.ErrorLevel:
return elog.Error(3, msg)
return logger.Error(msg)
case zapcore.WarnLevel:
return elog.Warning(2, msg)
return logger.Warning(msg)
case zapcore.InfoLevel:
return elog.Info(1, msg)
return logger.Info(msg)
}

// ignore Debug level logs
Expand Down

0 comments on commit 07b4b17

Please sign in to comment.