-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: re-write log arg enrichment
- Loading branch information
Showing
8 changed files
with
153 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,83 @@ | ||
package logging | ||
|
||
import ( | ||
"reflect" | ||
|
||
"github.com/leg100/pug/internal/resource" | ||
) | ||
|
||
// enricher enriches a log record with further meaningful attributes that aren't | ||
// readily available to the caller. | ||
type enricher struct { | ||
enrichers []Enricher | ||
updaters []ArgsUpdater | ||
} | ||
|
||
// Enricher implementations update a log record with further info | ||
type Enricher interface { | ||
EnrichLogRecord(args ...any) []any | ||
func (e *enricher) AddArgsUpdater(updater ArgsUpdater) { | ||
e.updaters = append(e.updaters, updater) | ||
} | ||
|
||
func (e *enricher) AddEnricher(enricher Enricher) { | ||
e.enrichers = append(e.enrichers, enricher) | ||
func (e *enricher) enrich(args ...any) []any { | ||
for _, en := range e.updaters { | ||
args = en.UpdateArgs(args...) | ||
} | ||
return args | ||
} | ||
|
||
func (e *enricher) enrich(args ...any) []any { | ||
for _, en := range e.enrichers { | ||
args = en.EnrichLogRecord(args...) | ||
// ArgsUpdater updates a log message's arguments. | ||
type ArgsUpdater interface { | ||
UpdateArgs(args ...any) []any | ||
} | ||
|
||
// ReferenceUpdater checks log arguments for references to T via its ID, either directly | ||
// or via a struct field, and updates or adds T to the log arguments | ||
// accordingly. | ||
type ReferenceUpdater[T any] struct { | ||
Getter[T] | ||
|
||
Name string | ||
Field string | ||
} | ||
|
||
type Getter[T any] interface { | ||
Get(resource.ID) (T, error) | ||
} | ||
|
||
func (e *ReferenceUpdater[T]) UpdateArgs(args ...any) []any { | ||
for i, arg := range args { | ||
// Where an argument is of type resource.ID, try and retrieve the | ||
// resource corresponding to the ID and replace argument with the | ||
// resource. | ||
if id, ok := arg.(resource.ID); ok { | ||
t, err := e.Get(id) | ||
if err != nil { | ||
continue | ||
} | ||
// replace id with T | ||
args[i] = t | ||
return args | ||
} | ||
// Where an argument is a struct (or a pointer to a struct), check if it | ||
// has a field matching the expect field name, with a corresponding | ||
// value of type resource.ID, and if so, try and retrieve resource with | ||
// that resource.ID and add it as a log argument preceded with e.Name. | ||
v := reflect.Indirect(reflect.ValueOf(arg)) | ||
if v.Kind() != reflect.Struct { | ||
continue | ||
} | ||
f := reflect.Indirect(v.FieldByName(e.Field)) | ||
if !f.IsValid() { | ||
continue | ||
} | ||
id, ok := f.Interface().(resource.ID) | ||
if !ok { | ||
continue | ||
} | ||
t, err := e.Get(id) | ||
if err != nil { | ||
// T with id does not exist | ||
continue | ||
} | ||
return append(args, e.Name, t) | ||
} | ||
return args | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package logging | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/leg100/pug/internal/resource" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestReferenceUpdater(t *testing.T) { | ||
res := &fakeResource{ID: resource.NewID(resource.Module)} | ||
updater := &ReferenceUpdater[*fakeResource]{ | ||
Getter: &fakeResourceGetter{res: res}, | ||
Name: "fake", | ||
Field: "FakeResourceID", | ||
} | ||
|
||
t.Run("replace resource id with resource", func(t *testing.T) { | ||
args := []any{"fake", res.ID} | ||
got := updater.UpdateArgs(args...) | ||
|
||
want := []any{"fake", res} | ||
assert.Equal(t, want, got) | ||
}) | ||
|
||
t.Run("add resource when referenced from struct with pointer field", func(t *testing.T) { | ||
type logMsgArg struct { | ||
FakeResourceID *resource.ID | ||
} | ||
|
||
args := []any{"arg1", logMsgArg{FakeResourceID: &res.ID}} | ||
got := updater.UpdateArgs(args...) | ||
|
||
want := append(args, "fake", res) | ||
assert.Equal(t, want, got) | ||
}) | ||
|
||
t.Run("add resource when referenced from struct with non-pointer field", func(t *testing.T) { | ||
type logMsgArg struct { | ||
FakeResourceID resource.ID | ||
} | ||
|
||
args := []any{"arg1", logMsgArg{FakeResourceID: res.ID}} | ||
got := updater.UpdateArgs(args...) | ||
|
||
want := append(args, "fake", res) | ||
assert.Equal(t, want, got) | ||
}) | ||
|
||
t.Run("handle nil pointer from struct", func(t *testing.T) { | ||
type logMsgArg struct { | ||
FakeResourceID *resource.ID | ||
} | ||
|
||
args := []any{"arg1", logMsgArg{FakeResourceID: nil}} | ||
got := updater.UpdateArgs(args...) | ||
|
||
assert.Equal(t, got, got) | ||
}) | ||
} | ||
|
||
type fakeResource struct { | ||
resource.ID | ||
} | ||
|
||
type fakeResourceGetter struct { | ||
res *fakeResource | ||
} | ||
|
||
func (f *fakeResourceGetter) Get(resource.ID) (*fakeResource, error) { | ||
return f.res, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters