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

Add fxevent.Decorated and emit it from fx.Decorate #843

Merged
merged 3 commits into from Feb 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 38 additions & 0 deletions app_test.go
Expand Up @@ -343,6 +343,44 @@ func TestNewApp(t *testing.T) {
assert.Contains(t, err.Error(), "/app_test.go")
assert.Contains(t, err.Error(), "Failed: must provide constructor function")
})

t.Run("Decorates", func(t *testing.T) {
t.Parallel()
spy := new(fxlog.Spy)

type A struct{ value int }
app := fxtest.New(t,
Provide(func() A { return A{value: 0} }),
Decorate(func(a A) A { return A{value: a.value + 1} }),
Invoke(func(a A) { assert.Equal(t, a.value, 1) }),
WithLogger(func() fxevent.Logger { return spy }))
defer app.RequireStart().RequireStop()

require.Equal(t,
[]string{"Provided", "Provided", "Provided", "Provided", "LoggerInitialized", "Decorated", "Invoking", "Invoked", "Started"},
spy.EventTypes())
})

t.Run("DecoratesFromManyModules", func(t *testing.T) {
t.Parallel()
spy := new(fxlog.Spy)

type A struct{ value int }
m := Module("decorator",
Decorate(func(a A) A { return A{value: a.value + 1} }),
)
app := fxtest.New(t,
m,
Provide(func() A { return A{value: 0} }),
Decorate(func(a A) A { return A{value: a.value + 1} }),
WithLogger(func() fxevent.Logger { return spy }),
)
defer app.RequireStart().RequireStop()

require.Equal(t,
[]string{"Provided", "Provided", "Provided", "Provided", "LoggerInitialized", "Decorated", "Decorated", "Started"},
spy.EventTypes())
})
}

func TestWithLoggerErrorUseDefault(t *testing.T) {
Expand Down
7 changes: 7 additions & 0 deletions fxevent/console.go
Expand Up @@ -72,6 +72,13 @@ func (l *ConsoleLogger) LogEvent(event Event) {
if e.Err != nil {
l.logf("Error after options were applied: %v", e.Err)
}
case *Decorated:
for _, rtype := range e.OutputTypeNames {
l.logf("DECORATE\t%v <= %v", rtype, e.DecoratorName)
}
if e.Err != nil {
l.logf("Error after options were applied: %v", e.Err)
}
case *Invoking:
l.logf("INVOKE\t\t%s", e.FunctionName)
case *Invoked:
Expand Down
13 changes: 13 additions & 0 deletions fxevent/console_test.go
Expand Up @@ -115,6 +115,19 @@ func TestConsoleLogger(t *testing.T) {
},
want: "[Fx] PROVIDE *bytes.Buffer <= bytes.NewBuffer()\n",
},
{
name: "Decorated",
give: &Decorated{
DecoratorName: "bytes.NewBuffer()",
OutputTypeNames: []string{"*bytes.Buffer"},
},
want: "[Fx] DECORATE *bytes.Buffer <= bytes.NewBuffer()\n",
},
{
name: "DecorateError",
give: &Decorated{Err: errors.New("some error")},
want: "[Fx] Error after options were applied: some error\n",
},
{
name: "Invoking",
give: &Invoking{FunctionName: "bytes.NewBuffer()"},
Expand Down
15 changes: 15 additions & 0 deletions fxevent/event.go
Expand Up @@ -37,6 +37,7 @@ func (*OnStopExecuting) event() {}
func (*OnStopExecuted) event() {}
func (*Supplied) event() {}
func (*Provided) event() {}
func (*Decorated) event() {}
func (*Invoking) event() {}
func (*Invoked) event() {}
func (*Stopping) event() {}
Expand Down Expand Up @@ -125,6 +126,20 @@ type Provided struct {
Err error
}

// Decorated is emitted when a decorator is provided to Fx.
type Decorated struct {
// DecoratorName is the name of the decorator function that was
// provided to Fx.
DecoratorName string

// OutputTypeNames is a list of names of types that are decorated by
// this decorator.
OutputTypeNames []string

// Err is non-nil if we failed to provide this decorator.
Err error
}

// Invoking is emitted before we invoke a function specified with fx.Invoke.
type Invoking struct {
// FunctionName is the name of the function that will be invoked.
Expand Down
1 change: 1 addition & 0 deletions fxevent/event_test.go
Expand Up @@ -37,6 +37,7 @@ func TestForCoverage(t *testing.T) {
&OnStopExecuted{},
&Supplied{},
&Provided{},
&Decorated{},
&Invoking{},
&Invoked{},
&Stopping{},
Expand Down
11 changes: 11 additions & 0 deletions fxevent/zap.go
Expand Up @@ -87,6 +87,17 @@ func (l *ZapLogger) LogEvent(event Event) {
l.Logger.Error("error encountered while applying options",
zap.Error(e.Err))
}
case *Decorated:
for _, rtype := range e.OutputTypeNames {
l.Logger.Info("decorated",
zap.String("decorator", e.DecoratorName),
zap.String("type", rtype),
)
}
if e.Err != nil {
l.Logger.Error("error encountered while applying options",
zap.Error(e.Err))
}
case *Invoking:
// Do not log stack as it will make logs hard to read.
l.Logger.Info("invoking",
Expand Down
20 changes: 20 additions & 0 deletions fxevent/zap_test.go
Expand Up @@ -163,6 +163,26 @@ func TestZapLogger(t *testing.T) {
"error": "some error",
},
},
{
name: "Decorate",
give: &Decorated{
DecoratorName: "bytes.NewBuffer()",
OutputTypeNames: []string{"*bytes.Buffer"},
},
wantMessage: "decorated",
wantFields: map[string]interface{}{
"decorator": "bytes.NewBuffer()",
"type": "*bytes.Buffer",
},
},
{
name: "Decorate with Error",
give: &Decorated{Err: someError},
wantMessage: "error encountered while applying options",
wantFields: map[string]interface{}{
"error": "some error",
},
},
{
name: "Invoking/Success",
give: &Invoking{FunctionName: "bytes.NewBuffer()"},
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -12,4 +12,4 @@ require (
golang.org/x/sys v0.0.0-20210903071746-97244b99971b
)

replace go.uber.org/dig => github.com/uber-go/dig v1.13.1-0.20220208182428-8193c7fedade
replace go.uber.org/dig => github.com/uber-go/dig v1.13.1-0.20220217170604-a7e23e31e975
4 changes: 2 additions & 2 deletions go.sum
Expand Up @@ -22,8 +22,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/uber-go/dig v1.13.1-0.20220208182428-8193c7fedade h1:q2FxCCuMWy3p904qjF7NyaFj4EP/G5T7eACVKLvMgrU=
github.com/uber-go/dig v1.13.1-0.20220208182428-8193c7fedade/go.mod h1:jHAn/z1Ld1luVVyGKOAIFYz/uBFqKjjEEdIqVAqfQ2o=
github.com/uber-go/dig v1.13.1-0.20220217170604-a7e23e31e975 h1:DThTt5qayrILkBHJQIu19u38oTPaWH/LU+RxMLz0/tA=
github.com/uber-go/dig v1.13.1-0.20220217170604-a7e23e31e975/go.mod h1:jHAn/z1Ld1luVVyGKOAIFYz/uBFqKjjEEdIqVAqfQ2o=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
Expand Down
14 changes: 13 additions & 1 deletion module.go
Expand Up @@ -179,7 +179,19 @@ func (m *module) executeInvoke(i invoke) (err error) {

func (m *module) decorate() (err error) {
for _, decorator := range m.decorators {
if err := runDecorator(m.scope, decorator); err != nil {
var info dig.DecorateInfo
err := runDecorator(m.scope, decorator, dig.FillDecorateInfo(&info))
outputNames := make([]string, len(info.Outputs))
for i, o := range info.Outputs {
outputNames[i] = o.String()
}

m.app.log.LogEvent(&fxevent.Decorated{
DecoratorName: fxreflect.FuncName(decorator.Target),
OutputTypeNames: outputNames,
Err: err,
})
if err != nil {
return err
}
}
Expand Down