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

Improve shutdown logs #87

Merged
merged 5 commits into from
Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Changed

- service: Improve shutdown logs #87

### Deprecated

### Removed
Expand Down
12 changes: 3 additions & 9 deletions service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import (

// HandleSignals manages OS signals that ask the service/daemon to stop.
// The stopFunction should break the loop in the Beat so that
// the service shut downs gracefully.
// the service shutdowns gracefully.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shutdowns -> "shuts down"

func HandleSignals(stopFunction func(), cancel context.CancelFunc) {
var callback sync.Once
logger := logp.NewLogger("service")
Expand All @@ -49,20 +49,14 @@ func HandleSignals(stopFunction func(), cancel context.CancelFunc) {
go func() {
sig := <-sigc

switch sig {
case syscall.SIGINT, syscall.SIGTERM:
logger.Debug("Received sigterm/sigint, stopping")
case syscall.SIGHUP:
logger.Debug("Received sighup, stopping")
}

logger.Infof("Received signal %q, stopping", sig)
cancel()
callback.Do(stopFunction)
}()

// Handle the Windows service events
go ProcessWindowsControlEvents(func() {
logger.Debug("Received svc stop/shutdown request")
logger.Info("Received Windows SVC stop/shutdown request")
callback.Do(stopFunction)
})
}
Expand Down
21 changes: 16 additions & 5 deletions service/service_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func (m *beatService) Execute(args []string, r <-chan svc.ChangeRequest, changes
changes <- svc.Status{State: svc.StartPending}
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}

log := logp.NewLogger("service_windows")
loop:
for c := range r {
switch c.Cmd {
Expand All @@ -55,18 +56,29 @@ loop:
// Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4
time.Sleep(100 * time.Millisecond)
changes <- c.CurrentStatus
case svc.Stop, svc.Shutdown:

// The svc.Cmd tye does not implement the Stringer interface and its
// underlying type is an integer, therefore it's needed to manually log them.
case svc.Stop:
log.Info("received state change 'svc.Stop' from windows service manager")
break loop
case svc.Shutdown:
log.Info("received state change 'svc.Shutdown' from windows service manager")
break loop

default:
logp.Err("Unexpected control request: $%d. Ignored.", c)
log.Errorf("Unexpected control request: $%d. Ignored.", c)
}
}
changes <- svc.Status{State: svc.StopPending}
log.Info("changed windows service state to svc.StopPending, invoking stopCallback")
m.stopCallback()

// Block until notifyWindowsServiceStopped below is called. This is required
// as the windows/svc package will transition the service to STOPPED state
// once this function returns.
<-m.done
log.Debug("windows service state changed to svc.Stopped")
return ssec, errno
}

Expand All @@ -89,7 +101,7 @@ const couldNotConnect syscall.Errno = 1063
func ProcessWindowsControlEvents(stopCallback func()) {
defer close(serviceInstance.executeFinished)

// nolint: staticcheck // keep using the deprecated method in order to maintain the existing behavior
//nolint:staticcheck // keep using the deprecated method in order to maintain the existing behavior
isInteractive, err := svc.IsAnInteractiveSession()
if err != nil {
logp.Err("IsAnInteractiveSession: %v", err)
Expand All @@ -104,12 +116,11 @@ func ProcessWindowsControlEvents(stopCallback func()) {

serviceInstance.stopCallback = stopCallback
err = run(os.Args[0], serviceInstance)

if err == nil {
return
}

// nolint: errorlint // this system error is a special case
//nolint:errorlint // this system error is a special case
if errnoErr, ok := err.(syscall.Errno); ok && errnoErr == couldNotConnect {
/*
If, as in the case of Jenkins, the process is started as an interactive process, but the invoking process
Expand Down