Skip to content

Commit

Permalink
feat: update for Go 1.21
Browse files Browse the repository at this point in the history
  • Loading branch information
telemachus committed Aug 14, 2023
1 parent f1c149b commit 655fadb
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 186 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- ubuntu-latest
- macos-latest
- windows-latest
go: ['1.20']
go: ['1.21']
name: humane test (using go ${{ matrix.go }} on ${{ matrix.os }})
steps:
- uses: actions/checkout@v3
Expand Down
16 changes: 16 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
linters-settings:
depguard:
rules:
main:
files:
- $all
deny:
- pkg: reflect
desc: "avoid reflect"
test:
files:
- $all
deny:
- pkg: reflect
desc: "avoid reflect"
errcheck:
check-type-assertions: true
check-blank: true
Expand All @@ -9,6 +23,8 @@ linters-settings:
- fmt.Fprintln
- (*github.com/telemachus/humane/internal/buffer.Buffer).WriteByte
- (*github.com/telemachus/humane/internal/buffer.Buffer).WriteString
exhaustive:
default-signifies-exhaustive: true
goconst:
min-len: 2
min-occurrences: 3
Expand Down
14 changes: 14 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# humane version history

# v0.5.0

+ Switch from `exp/slog` to `log/slog` and from `exp/slices` to `slices` now
that Go 1.21 has been released.
+ Adjust the `NewHandler` function to match the latest `slog` API.
+ Use a pointer to `sync.Mutex` rather than `sync.Mutex`. See this discussion
in the guide to writing `slog` handlers for why: https://bit.ly/3s2KrOG.
+ Add `testing/slogtest`.
+ Fix a bug (found thanks to `testing/slogtest`): move the test for
`Attr.Empty` to catch all empty attrs.
+ Fix a bug (found thanks to `testing/slogtest`): make sure to call `Resolve`
on all attribute values.
7 changes: 5 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# To do list
# TODO list

+ Switch from strings.Builder to sync.Pool and a custom buffer as in slog?
+ Try preformatting of groups and attributes, as discussed [here][howto].
+ Simplify appendAttr.

[howto]: https://github.com/golang/example/blob/master/slog-handler-guide/README.md#with-pre-formatting
6 changes: 3 additions & 3 deletions benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import (
"context"
"errors"
"io"
"log/slog"
"testing"
"time"

"github.com/telemachus/humane"
"golang.org/x/exp/slog"
)

var (
Expand All @@ -30,7 +30,7 @@ var slogAttrs = []slog.Attr{
}

func BenchmarkSlog(b *testing.B) {
logger := slog.New(slog.NewTextHandler(io.Discard))
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
Expand All @@ -44,7 +44,7 @@ func BenchmarkSlog(b *testing.B) {
}

func BenchmarkHumane(b *testing.B) {
logger := slog.New(humane.NewHandler(io.Discard))
logger := slog.New(humane.NewHandler(io.Discard, nil))
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
Expand Down
6 changes: 3 additions & 3 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//
// 1. Get a slog logger using humane's handler with default options:
//
// logger := slog.New(humane.NewHandler(os.Stdout))
// logger := slog.New(humane.NewHandler(os.Stdout, nil))
// logger.Info("Message", "foo", "bar", "bizz", "buzz")
//
// 2. Get a slog logger using humane's handler with customized options:
Expand All @@ -22,13 +22,13 @@
// }
//
// func main() {
// ho := humane.Options{
// opts := &humane.Options{
// Level: slog.LevelError,
// ReplaceAttr: trimSource,
// TimeFormat: time.Kitchen,
// AddSource: true,
// }
// logger := slog.New(ho.NewHandler(os.Stderr))
// logger := slog.New(humane.NewHandler(os.Stderr, opts))
// // ... later
// logger.Error("Message", "error", err, "response", respStatus)
// }
Expand Down
80 changes: 36 additions & 44 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ not his.)
[logfmt]: https://brandur.org/logfmt
[details]: https://brandur.org/logfmt#human

## Warning

[slog][slogdiscussion] has been accepted for Go 1.21, but it is still under
development. This handler is new and also still being tweaked. Let me know
if you have trouble with it, but be aware that the API may change.

[slogdiscussion]: https://github.com/golang/go/issues/56345

## The Format

Briefly, the format is as follows.
Expand All @@ -30,7 +22,7 @@ The level and message Attrs appear as is without `key=value` structure or
quoting. Then the rest of the Attrs appear as `key=value` pairs. A time Attr
will be added by default to the third section. (See below for how to change
the format of this Attr or omit it entirely.) The three sections of the log
message are separated by a pipe character (`|`). The pipes should make it easy
line are separated by a pipe character (`|`). The pipes should make it easy
to parse out the sections of the message with (e.g.) `cut` or `awk`, but no
attempt is made to check for that character anywhere else in the log. Thus, if
pipes appear elsewhere, all bets are off. (This seems like a reasonable
Expand All @@ -41,54 +33,55 @@ probably use JSON or another format.)
## Installation

```
go install github.com/telemachus/humane
go get github.com/telemachus/humane
```

## Usage

```go
// Create a logger with default options. See below for more on available
// options.
logger := slog.New(humane.NewHandler(os.Stdout))
logger := slog.New(humane.NewHandler(os.Stdout, nil))
logger.Info("My informative message", "foo", "bar", "bizz", "buzz")
logger.Error("Ooops", slog.Any("error", err))
// Output:
// INFO | My informative message | foo=bar bizz=buzz time="2023-04-02T10:50.09 EDT"
// ERROR | Ooops | error="error message" time="2023-04-02T10:50.09 EDT"

// You can also set options. Again, see the next section for more details.
ho := humane.Options{
opts := humane.Options{
Level: slog.LevelError,
TimeFormat: time.RFC3339
}
logger := slog.New(ho.NewHandler(os.Stderr))
logger := slog.New(humane.NewHandler(os.Stderr, opts))
logger.Info("This message will not be written")
```

## Options

+ `Level slog.Leveler`: Level defaults to slog.Info. You can use
a [slog.Level](https://pkg.go.dev/golang.org/x/exp/slog#Level) to change
the default. If you want something more complex, you can also implement
a [slog.Leveler](https://pkg.go.dev/golang.org/x/exp/slog#Leveler).
a [slog.Level](https://pkg.go.dev/log/slog#Level) to change the default. If
you want something more complex, you can also implement
a [slog.Leveler](https://pkg.go.dev/log/slog#Leveler).
+ `ReplaceAttr func(groups []string, a slog.Attr)`: As in slog itself, this
function is applied to each Attr in a given Record during handling. This
allows you to, e.g., omit or edit Attrs in creative ways. See [slog's
documentation and tests for further examples](slog). Note that the
ReplaceAttr function is **not** applied to the level or message Attrs since
they receive specific formatting by this handler. (However, I am open to
reconsidering that. Please open an [issue][issue] to discuss it.) In order
to make the time and source Attrs easier to test for, they use constants
defined by slog for their keys: `slog.TimeKey` and `slog.SourceKey`.
documentation and tests for further examples](https://pkg.go.dev/log/slog).
Note that the ReplaceAttr function is **not** applied to the level or
message Attrs since they receive specific formatting by this handler.
(However, I am open to reconsidering that. Please open an [issue][issue] to
discuss it.) In order to make the time and source Attrs easier to test for,
they use constants defined by slog for their keys: `slog.TimeKey` and
`slog.SourceKey`.
+ `TimeFormat string`: The time format defaults to "2006-01-02T03:04.05 MST".
You can use this option to set some other time format. (You can also tweak
the time Attr via a ReplaceAttr function, but this is easier for simple
format changes.) The time Attr uses `slog.TimeKey` as its key value by
default.
the time format via a ReplaceAttr function, but setting this option is
easier for simple format changes.) The time Attr uses `slog.TimeKey` as its
key value by default.
+ `AddSource bool`: This option defaults to false. If you set it to true,
then an Attr containing `source=/path/to/source:line` will be added to each
record. If source Attr is present, it uses `slog.SourceKey` as its default
key value.
record. If a source Attr is present, it uses `slog.SourceKey` as its
default key value.

A common need (e.g., for testing) is to remove the time Attr altogether.
Here's a simple way to do that.
Expand All @@ -100,11 +93,11 @@ func removeTime(_ []string, a slog.Attr) slog.Attr {
}
return a
}
ho := humane.Options{ReplaceAttr: removeTime}
logger := slog.New(ho.NewHandler(os.Stdout))
opts := humane.Options{ReplaceAttr: removeTime}
logger := slog.New(humane.NewHandler(os.Stdout, opts))
```

[slog]: https://pkg.go.dev/golang.org/x/exp/slog
[slog]: https://pkg.go.dev/log/slog
[issue]: https://github.com/telemachus/humane/issues

## Bugs and Limitations
Expand All @@ -114,31 +107,30 @@ know][issue] if you find any.

One limitation concerns the source Attr. If you use the logger in a helper
function or a wrapper, then the source information will likely be wrong. See
[slog's documentation][sourceproblem] for a discussion and workaround. There
is also [an open issue][sourceissue] that proposes more support in slog for
writing helper functions. (There's another [open issue][pcissue] that
proposes other ways to give users of slog more help with the source Attr.)
[slog's documentation][sourceproblem] for a discussion and workaround.

[sourceproblem]: https://pkg.go.dev/golang.org/x/exp/slog#hdr-Wrapping_output_methods
[sourceissue]: https://github.com/golang/go/issues/59145
[pcissue]: https://github.com/golang/go/issues/59280
[sourceproblem]: https://pkg.go.dev/log/slog#hdr-Wrapping_output_methods


## Acknowledgements
## Acknowledgments

I'm using quite a lot of code from slog itself as well as from the [slog
extras repository][slogextras]. Thanks to Jonathan Amsterdam for both. I've
also taken ideas and code from sources on [Go's wiki][wiki] as well as several
blog posts about slog. See below for a list of resources. (Note that some of
the resources are more or less out of date since slog and its API have changed
over time.)
extras repository][slogextras]. The [guide to writing `slog` handlers][guide]
was also very useful. Thanks to Jonathan Amsterdam for for all three of these.
I've also taken ideas and code from sources on [Go's wiki][wiki] as well as
several blog posts about slog. See below for a list of resources. (Note that
some of the resources are more or less out of date since slog and its API have
changed over time.)



+ [A Guide to Writing `slog` Handlers][guide]
+ [Proposal: Structured Logging][proposal]
+ [`slog`: Golang's official structured logging package][sobyte]
+ [Structured logging in Go][mrkaran]
+ [A Comprehensive Guide to Structured Logging in Go][betterstack]

[slogextras]: https://github.com/jba/slog
[guide]: https://github.com/golang/example/tree/master/slog-handler-guide
[wiki]: https://github.com/golang/go/wiki/Resources-for-slog
[proposal]: https://go.googlesource.com/proposal/+/master/design/56345-structured-logging.md
[sobyte]: https://www.sobyte.net/post/2022-10/go-slog/
Expand Down
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
module github.com/telemachus/humane

go 1.20

require golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
go 1.21
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
Loading

0 comments on commit 655fadb

Please sign in to comment.