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

embed funcr, custom With* function example #68

Merged
merged 1 commit into from
Aug 19, 2021

Conversation

pohly
Copy link
Contributor

@pohly pohly commented Aug 12, 2021

This allows custom loggers to provide their own additional methods
while using most of the implementation from funcr.

That funcr had to be extended to support the helper concept in
testing.T didn't feel right because fnlogger then always implemented
the CallStackHelperLogSink interface even when the helper was
nil. This gets fixed by moving the implementation of that into the
testing logger, using the new embedding mechanism of funcr.

As a drive-by fix, the testing logger no longer prints a redundant ":"
when the prefix is empty.

The logr package describes how to implement a custom With* function. A
runable example for that gets added in funcr/example_test.go.

@pohly pohly mentioned this pull request Aug 12, 2021
@pohly pohly force-pushed the custom-with-example branch 3 times, most recently from 18a0bc5 to 00db538 Compare August 18, 2021 16:30
@thockin
Copy link
Contributor

thockin commented Aug 18, 2021

I don't understand what's going on with FnLogSink being a distinct type. The first commit is what I expected. I'm not clear on the second.

@pohly
Copy link
Contributor Author

pohly commented Aug 19, 2021

FnLogSink is what custom LogSink embed into their own struct. fnlogger is the internal implementation of the LogSink interface which uses FnLogSink. These two must be distinct types because, for example, fnlogger.WithName must not be inherited by custom implementations because it wouldn't do the right thing (it copies only the struct it knows about, not the full struct of the custom implementation).

Let me add a runable example. Perhaps that'll clarify this.

@pohly pohly changed the title WIP: custom with example WIP: custom With* function example Aug 19, 2021
@pohly pohly force-pushed the custom-with-example branch from 00db538 to f1226a8 Compare August 19, 2021 09:52
@pohly
Copy link
Contributor Author

pohly commented Aug 19, 2021

I ended up refactoring funcr differently. It's now split into a formatter and the full LogSink implementation.

I also addressed one aspect of PR #60 that didn't quite feel right but couldn't be solved differently at that time: adding the helper function to funcr.Options was both a small API break (struct not comparable anymore), not quite the right place (not a formatting option) and had the effect that fnlogger always implemented the additional interface even when not needed. I reverted that change and moved the implementation of the helper handling entirely under testing.

The downside is that more boilerplate code is needed there.

The original purpose of this PR, providing a code example for a custom With* function, is served by the example stdout logger in funcr/example_test.go. The previous example in funcr itself got removed.

@pohly pohly force-pushed the custom-with-example branch 2 times, most recently from 650bdbf to d9f1bb4 Compare August 19, 2021 10:02
t.Helper()
t.Logf("%s: %s", prefix, args)
l := &testlogger{
Formatter: funcr.NewFormatter(funcr.Options{}),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it would make sense to allow configuring the formatting, in particular the log level threshold. I've not added it to the PR to not bloat it further, but would like to see this addressed before logr v1.1.0.

The simplest solution would be:

func NewTestLoggerWithOptions(t *testing.T, opts funcr.Options) logr.Logger {
   ...
}

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd rather see TestLogger get its own options struct, even if that is just a typedef to funcr.Options.

@pohly pohly changed the title WIP: custom With* function example embed funcr, custom With* function example Aug 19, 2021
@pohly
Copy link
Contributor Author

pohly commented Aug 19, 2021

As a drive-by fix, the testing logger no longer prints a redundant ":" when the prefix is empty.

Output before:

$ go test -v ./testing
=== RUN   TestTestLogger
    test_test.go:28: : "level"=0 "msg"="info"
    test_test.go:29: : "level"=0 "msg"="V(0).info"
    test_test.go:31: : "msg"="error" "error"="error"
    test_test.go:32: : "level"=0 "msg"="hello world"
--- PASS: TestTestLogger (0.00s)

Output now:

=== RUN   TestLogger
    test_test.go:28: "level"=0 "msg"="info"
    test_test.go:29: "level"=0 "msg"="V(0).info"
    test_test.go:31: "msg"="error" "error"="error"
    test_test.go:32: testing: "level"=0 "msg"="with prefix"
    test_test.go:33: "level"=0 "msg"="hello world"
--- PASS: TestLogger (0.00s)

funcr/funcr.go Outdated
@@ -95,22 +88,46 @@ const (

const timestampFmt = "2006-01-02 15:04:05.000000"

// fnlogger inherits most of its LogSink implementation from FnLogSink
// and just needs to adapt the return value of the With functions.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This comment needs to be updated...

@@ -34,3 +34,77 @@ func ExampleUnderlier() {
}
// Output: hello world
}

// newStdoutLogger returns a logr.Logger that prints to stdout.
// It demonstrates how to implement a custom With* method which
Copy link
Contributor

Choose a reason for hiding this comment

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

s/method/function

@pohly pohly force-pushed the custom-with-example branch from d9f1bb4 to 89e8c23 Compare August 19, 2021 16:57
This allows custom loggers to provide their own additional methods
while using most of the implementation from funcr.

That funcr had to be extended to support the helper concept in
testing.T didn't feel right because fnlogger then always implemented
the CallStackHelperLogSink interface even when the helper was
nil. This gets fixed by moving the implementation of that into the
testing logger, using the new embedding mechanism of funcr.

As a drive-by fix, the testing logger no longer prints a redundant ":"
when the prefix is empty.

The logr package describes how to implement a custom With* function. A
runable example for that gets added in funcr/example_test.go.
@pohly pohly force-pushed the custom-with-example branch from 89e8c23 to 8836100 Compare August 19, 2021 16:59
@thockin
Copy link
Contributor

thockin commented Aug 19, 2021

Thanks!

/lgtm
/approve

@thockin thockin merged commit b303d6f into go-logr:master Aug 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants