-
Notifications
You must be signed in to change notification settings - Fork 16
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
switch logging to slog #189
base: main
Are you sure you want to change the base?
switch logging to slog #189
Conversation
cb54a3f
to
9e3b71e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @jlambert121 , thanks for your contribution! This seems like a good improvement to Boilerplate.
I don't think BoilerplateOptions
is the correct place for our Logger instance, that struct is specific to parsing configuration. There's two ways forward here:
- Least work:
Use slog.SetDefault after parsing the --silent option, then use the slog.Info etc methods at log callsites. This is pretty similar to the way the existing logger is utilized, and allows us to use the correct logger in util/shell.go
without modifying any function signatures.
- More work:
Pass the instance of *slog.Logger everywhere as a function argument. Typically I make the first two arguments of my functions context.Context and Logger. This allows different code paths to construct new logger instances with different key val attributes. There's not much value in doing that here as we're not using log attributes, so its more of a style preference to avoid the global.
I'd suggest going with the first (least work) option for now and we can revisit in the future if we want to start using log attributes :)
) | ||
|
||
// Run the given shell command with the given environment variables and arguments in the given working directory | ||
func RunShellCommandAndGetOutput(workingDir string, envVars []string, command string, args ...string) (string, error) { | ||
Logger.Printf("Running command: %s %s", command, strings.Join(args, " ")) | ||
logger := slog.New(prefixer.New()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need to use the same instance of the logger here, and below, to correctly respect the silent option.
handler := &Handler{ | ||
h: slog.NewTextHandler(buf, &slog.HandlerOptions{}), | ||
m: &sync.Mutex{}, | ||
writer: os.Stdout, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets use os.Stderr here, it's more typical for logs to be sent to STDERR whereas machine readable program output should go to STDOUT
} | ||
|
||
func (h *Handler) Handle(ctx context.Context, r slog.Record) error { | ||
msg := slog.StringValue(r.Message).String() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels weird because we're not using any of the attributes or grouping from the slog package - but this is still a net improvement allowing us to use --silent so I'm happy for this to go in as long as there's a TODO comment explaining it. Something like:
// TODO: Handle attributes and groups
_, err := fmt.Fprintf(h.writer, "[boilerplate] %s\n", r.Message)
return err
|
||
type Handler struct { | ||
h slog.Handler | ||
m *sync.Mutex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I'm reading this wrong, this mutex doesn't appear to be used and should be removed.
@@ -36,6 +38,8 @@ type BoilerplateOptions struct { | |||
DisableHooks bool | |||
DisableShell bool | |||
DisableDependencyPrompt bool | |||
Silent bool | |||
Logger *slog.Logger |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't feel right, I think we should either use a global slog.Default() or pass the logger instance as a function argument everywhere.
@Resonance1584 thanks for taking a look at this!
Agree, was trying to limit the signature changes until there was some feedback though. In order to have an optional passed in logger (we're utilizing boilerplate inside another application), would you be opposed to changing the signature on |
@jlambert121 I actually hadn't considered the use of this project as a library (thanks for raising that use case!) - which makes signature changes on exported functions problematic. What we could do here is add a new exported function for your use case, and modify the existing function so that they go through the same code path without breaking compatibility. ProcessTemplate(options, rootOpts *options.BoilerplateOptions, thisDep variables.Dependency) error {
var l *slog.Logger
if options.Silent {
l = slog.New(slog.NewTextHandler(io.Discard, nil))
} else {
l = slog.New(prefixer.New())
}
return ProcessTemplateWithLogger(l, options, rootOpts, thisDep)
}
ProcessTemplateWithLogger(l *slog.Logger, options, rootOpts *options.BoilerplateOptions, thisDep variables.Dependency) error {
// .. previous body of ProcessTemplate goes here
} Would that support your use case? Unfortunately we also won't be able to modify |
Yeah, this seems like probably the best option - I'll see about refactoring with this. Yeah, |
Description
Fixes #82.
Currently all logging is done via
utils.Logger
which just outputs logging tostdout
. It would be nice to have more control over logging by silencing logging when not needed or injecting a separate logger (compatible with*slog.Logger
).There is a lot of lines of change here, but it's just creating a
slog.Handler
that prefixes[boilerplate]
to log lines to maintain the existing look and passing an instance of the logger throughout.go
is not my primary language though, any feedback is greatly appreciated!NOTE: This does bump the minimum go version to
1.21
.TODOs
Read the Gruntwork contribution guidelines.
Release Notes (draft)
Updated logging to use
slog
library.Migration Guide
None