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

feat: support JSON structured log formatting #179

Merged
merged 12 commits into from
Aug 29, 2024

Conversation

pehlicd
Copy link
Contributor

@pehlicd pehlicd commented Aug 20, 2024

This pr aims to give option to select one of the log formats text or json. It also introduces new flag -log-format to achieve.

I modified the tests so it should work out of the box. Also fixed some typos that I saw in general.

Please let me know if you also want me to modify README.

Closes #178

@pehlicd pehlicd changed the title chore: implement log formatting and fix some typos feat: implement log formatting and fix some typos Aug 20, 2024
Copy link
Owner

@mccutchen mccutchen left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution (and the typo fixes)!

In the past, I've been reluctant to make go-httpbin too opinionated about logging, given the wide variety of possible use cases. Instead, we added a generic mechanism for pluggable observers to enable users to add whatever instrumentation they needed (see #11, #74, etc).

However, now that slog is in the stdlib of the two most recent go versions it is now safe for us to adopt, and JSON structured logging seems "standardized enough" to warrant easy support here, so I think a change like this makes sense.

Left a couple of small comments below, plus I think there are some test failures to address, but LGTM at a high level!

httpbin/cmd/cmd.go Outdated Show resolved Hide resolved
httpbin/middleware.go Outdated Show resolved Hide resolved
httpbin/cmd/cmd_test.go Outdated Show resolved Hide resolved
Copy link
Owner

@mccutchen mccutchen left a comment

Choose a reason for hiding this comment

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

A few more comments, but this is coming along!

httpbin/cmd/cmd_test.go Outdated Show resolved Hide resolved
httpbin/middleware.go Outdated Show resolved Hide resolved
httpbin/middleware.go Outdated Show resolved Hide resolved
httpbin/middleware.go Outdated Show resolved Hide resolved
httpbin/cmd/cmd.go Outdated Show resolved Hide resolved
httpbin/cmd/cmd.go Outdated Show resolved Hide resolved
httpbin/cmd/cmd_test.go Outdated Show resolved Hide resolved
@pehlicd pehlicd requested a review from mccutchen August 28, 2024 14:56
Copy link
Owner

@mccutchen mccutchen left a comment

Choose a reason for hiding this comment

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

Apologies for how many rounds of review this is taking, I appreciate your patience. A few, hopefully final, comments below.

httpbin/cmd/cmd_test.go Outdated Show resolved Hide resolved
httpbin/cmd/cmd_test.go Outdated Show resolved Hide resolved
Comment on lines 169 to 176
var logLevel = slog.LevelInfo

return func(result Result) {
l.Printf(
logFmt,
time.Now().Format(dateFmt),
result.Status,
result.Method,
result.URI,
result.Size,
result.Duration.Seconds()*1e3, // https://github.com/golang/go/issues/5491#issuecomment-66079585
result.UserAgent,
result.ClientIP,
if result.Status >= 500 {
logLevel = slog.LevelError
} else if result.Status >= 400 && result.Status < 500 {
logLevel = slog.LevelWarn
}
Copy link
Owner

Choose a reason for hiding this comment

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

This isn't safe, we're modifying a logLevel var defined outside this function on every invocation. I think that means a single 5xx response followed by a 2xx response will be logged at error level.

I'd probably do something like this instead:

logLevel := slog.InfoLevel
if result.Status >= 500 {
    logLevel = slog.LevelError
} else if result.Status >= 400 {
    logLevel = slog.LevelWarn
}

Yep, confirmed locally with a /status/500 then /status/200 request, where the latter is logged at ERROR level:

$ make run
mkdir -p dist
CGO_ENABLED=0 go build -ldflags="-s -w" -o dist/go-httpbin ./cmd/go-httpbin
HOST=127.0.0.1 PORT=8080 dist/go-httpbin
time=2024-08-28T14:18:06.611-04:00 level=INFO msg="go-httpbin listening on http://127.0.0.1:8080"
time=2024-08-28T14:18:14.150-04:00 level=ERROR msg="500 GET /status/500 0.0ms" status=500 method=GET uri=/status/500 size_bytes=0 duration_ms=0.01675 user_agent=curl/8.7.1 client_ip=127.0.0.1:60335
time=2024-08-28T14:18:24.516-04:00 level=ERROR msg="200 GET /status/200 0.1ms" status=200 method=GET uri=/status/200 size_bytes=0 duration_ms=0.08220799999999999 user_agent=curl/8.7.1 client_ip=127.0.0.1:60338

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh yeah true, sorry about that, will fix it in my next commit.

@pehlicd
Copy link
Contributor Author

pehlicd commented Aug 29, 2024

Apologies for how many rounds of review this is taking, I appreciate your patience. A few, hopefully final, comments below.

No need to apologize 🙂. It's completely understandable that maintaining high-quality code requires thorough review.

@pehlicd pehlicd requested a review from mccutchen August 29, 2024 13:35
@mccutchen mccutchen merged commit 7053398 into mccutchen:main Aug 29, 2024
3 checks passed
@mccutchen mccutchen changed the title feat: implement log formatting and fix some typos feat: support JSON structured log formatting Aug 29, 2024
@mccutchen
Copy link
Owner

Thanks for the contribution @pehlicd! This is now released as v2.14.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: implement log formatting
2 participants