Skip to content

Commit

Permalink
slog-handler-guide: discuss Record.Clone
Browse files Browse the repository at this point in the history
Change-Id: I55c6367da953b9a59c4d5cd8ca817d3c051e12de
Reviewed-on: https://go-review.googlesource.com/c/example/+/513138
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Ian Cottrell <[email protected]>
Run-TryBot: Jonathan Amsterdam <[email protected]>
  • Loading branch information
jba committed Jul 26, 2023
1 parent b766721 commit 6088d5b
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 2 deletions.
40 changes: 39 additions & 1 deletion slog-handler-guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This document is maintained by Jonathan Amsterdam `[email protected]`.
1. [The `WithGroup` method](#the-`withgroup`-method)
1. [Testing](#testing)
1. [General considerations](#general-considerations)
1. [Copying records](#copying-records)
1. [Concurrency safety](#concurrency-safety)
1. [Robustness](#robustness)
1. [Speed](#speed)
Expand Down Expand Up @@ -766,7 +767,44 @@ in 65 lines.

# General considerations

TODO(jba): reintroduce the material on Record.Clone that used to be here.
## Copying records

Most handlers won't need to copy the `slog.Record` that is passed
to the `Handle` method.
Those that do must take special care in some cases.

A handler can make a single copy of a `Record` with an ordinary Go
assignment, channel send or function call if it doesn't retain the
original.
But if its actions result in more than one copy, it should call `Record.Clone`
to make the copies so that they don't share state.
This `Handle` method passes the record to a single handler, so it doesn't require `Clone`:

type Handler1 struct {
h slog.Handler
// ...
}

func (h *Handler1) Handle(ctx context.Context, r slog.Record) error {
return h.h.Handle(ctx, r)
}

This `Handle` method might pass the record to more than one handler, so it
should use `Clone`:

type Handler2 struct {
hs []slog.Handler
// ...
}

func (h *Handler2) Handle(ctx context.Context, r slog.Record) error {
for _, hh := range h.hs {
if err := hh.Handle(ctx, r.Clone()); err != nil {
return err
}
}
return nil
}

## Concurrency safety

Expand Down
39 changes: 38 additions & 1 deletion slog-handler-guide/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,44 @@ in 65 lines.

# General considerations

TODO(jba): reintroduce the material on Record.Clone that used to be here.
## Copying records

Most handlers won't need to copy the `slog.Record` that is passed
to the `Handle` method.
Those that do must take special care in some cases.

A handler can make a single copy of a `Record` with an ordinary Go
assignment, channel send or function call if it doesn't retain the
original.
But if its actions result in more than one copy, it should call `Record.Clone`
to make the copies so that they don't share state.
This `Handle` method passes the record to a single handler, so it doesn't require `Clone`:

type Handler1 struct {
h slog.Handler
// ...
}

func (h *Handler1) Handle(ctx context.Context, r slog.Record) error {
return h.h.Handle(ctx, r)
}

This `Handle` method might pass the record to more than one handler, so it
should use `Clone`:

type Handler2 struct {
hs []slog.Handler
// ...
}

func (h *Handler2) Handle(ctx context.Context, r slog.Record) error {
for _, hh := range h.hs {
if err := hh.Handle(ctx, r.Clone()); err != nil {
return err
}
}
return nil
}

## Concurrency safety

Expand Down

0 comments on commit 6088d5b

Please sign in to comment.