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

set up windows event logger first in main #1672

Merged
merged 5 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
29 changes: 15 additions & 14 deletions cmd/launcher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,28 @@ import (
)

func main() {
// create initial logger. As this is prior to options parsing,
// use the environment to determine verbosity. It will be
// re-leveled during options parsing.
logger := logutil.NewServerLogger(env.Bool("LAUNCHER_DEBUG", false))
systemSlogger, logCloser, err := multislogger.SystemSlogger()
if err != nil {
fmt.Fprintf(os.Stderr, "error creating system logger: %v\n", err)
os.Exit(1)
}
defer logCloser.Close()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

should we close this just before starting the windows svc? it have two windows event writers does not seem to be an issue 🤷

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe, yeah? We might not want to do the defer anyway since defers won't execute when we exit with os.Exit, which we do a lot in this file.

I think it'd be ideal if it were easy to pass this system slogger into runWindowsSvc, but that looks like it would be kind of an annoying refactor to have to do...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yea, it would be an annoying refactor, also weird passing around a closer

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm sure we want the refactor. I'm less sure we want it today (I'm not sure how hard it would be, it's just adding slogger as a parameter to the subcommands, right?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

seems like we would also need to pass around the closer within main.go if we don't want to use defer .... I'm torn between wanting clean code and wanting to make sure we close the handler before we exit

Copy link
Contributor

Choose a reason for hiding this comment

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

I bet we could refactor out the os.Exit calls and use defer as expected. Or at least consolidate them and be clever. I wouldn't want to pass closers around.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we could do something like

func main() {
	if err := runMain(); err != nil {
		os.Exit(1)
	}
}

func runMain() error {
        // do stuff
        // return an err or nil
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, that's not bad. I was thinking of something much more complicated:

var exitDeferred []func

func osExit(ret int) {
  for _, fn := range exitDeferred {
    fn()
  }
  os.Exit(ret)
}

func main() {
  exitDeferred = append(exitDeferred, ...)
  osExit(0)
}

Copy link
Contributor

Choose a reason for hiding this comment

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

I think both of these are good options 👍 since we already have 2 other defer funcs in here that we'd probably want to move around too, I'm fine w punting this refactor to a subsequent PR in order to merge this one

Copy link
Contributor

Choose a reason for hiding this comment

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

Adding system multislogger to subcommands: #1674


ctx, cancel := context.WithCancel(context.Background())
defer cancel()

level.Info(logger).Log(
"msg", "Launcher starting up",
systemSlogger.Log(ctx, slog.LevelInfo,
"launcher starting up",
"version", version.Version().Version,
"revision", version.Version().Revision,
)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// create initial logger. As this is prior to options parsing,
// use the environment to determine verbosity. It will be
// re-leveled during options parsing.
logger := logutil.NewServerLogger(env.Bool("LAUNCHER_DEBUG", false))
ctx = ctxlog.NewContext(ctx, logger)

// set up system slogger to write to os logs
systemSlogger := multislogger.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
Level: slog.LevelInfo,
}))

// If this is a development build directory, we want to skip the TUF lookups and just run
// the requested build. Don't care about errors here. This is developer experience shim
inBuildDir := false
Expand Down
7 changes: 7 additions & 0 deletions pkg/log/multislogger/multislogger.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package multislogger
import (
"context"
"log/slog"
"os"

"github.com/kolide/kit/ulid"
slogmulti "github.com/samber/slog-multi"
Expand Down Expand Up @@ -88,3 +89,9 @@ func ctxValuesMiddleWare(ctx context.Context, record slog.Record, next func(cont

return next(ctx, record)
}

func defaultSystemSlogger() *MultiSlogger {
return New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
Level: slog.LevelInfo,
}))
}
12 changes: 12 additions & 0 deletions pkg/log/multislogger/syslogger_posix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//go:build !windows
// +build !windows

package multislogger

import (
"io"
)

func SystemSlogger() (*MultiSlogger, io.Closer, error) {
return defaultSystemSlogger(), io.NopCloser(nil), nil
}
45 changes: 45 additions & 0 deletions pkg/log/multislogger/syslogger_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//go:build windows
// +build windows

package multislogger

import (
"context"
"io"
"log/slog"

"github.com/kolide/launcher/pkg/log/eventlog"
"golang.org/x/sys/windows"
)

const serviceName = "launcher"

func SystemSlogger() (*MultiSlogger, io.Closer, error) {
if !windows.GetCurrentProcessToken().IsElevated() {
syslogger := defaultSystemSlogger()
Comment on lines +18 to +19
Copy link
Contributor

Choose a reason for hiding this comment

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

This is an interesting idea. Is the intent to try to capture people running in a terminal? Im game for trying this. I don't know if we have better rope to know what our caller is


syslogger.Log(context.TODO(), slog.LevelDebug,
"launcher running on windows without elevated permissions, using default stderr instead of eventlog",
)

return syslogger, io.NopCloser(nil), nil
}

eventLogWriter, err := eventlog.NewWriter(serviceName)
if err != nil {
syslogger := defaultSystemSlogger()

syslogger.Log(context.TODO(), slog.LevelError,
"could not create eventlog writer, using default stderr instead of eventlog",
"err", err,
)

return syslogger, io.NopCloser(nil), nil
}

systemSlogger := New(slog.NewJSONHandler(eventLogWriter, &slog.HandlerOptions{
Level: slog.LevelInfo,
}))

return systemSlogger, eventLogWriter, nil
}
Loading