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

Include Module Traces in Events #1122

Merged
merged 3 commits into from
Oct 17, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@ func New(opts ...Option) *App {
// user gave us. For the last case, however, we need to fall
// back to what was provided to fx.Logger if fx.WithLogger
// fails.
log: logger,
log: logger,
trace: []string{fxreflect.CallerStack(1, 2)[0].String()},
}
app.modules = append(app.modules, app.root)

Expand Down
117 changes: 114 additions & 3 deletions app_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Uber Technologies, Inc.
// Copyright (c) 2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -29,7 +29,9 @@ import (
"log"
"os"
"reflect"
"regexp"
"runtime"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -650,9 +652,114 @@ func TestWithLogger(t *testing.T) {
})
}

type errHandlerFunc func(error)
func getInt() int { return 0 }

func (f errHandlerFunc) HandleError(err error) { f(err) }
func decorateInt(i int) int { return i }

var moduleA = Module(
"ModuleA",
Provide(getInt),
Decorate(decorateInt),
Supply(int64(14)),
Replace("foo"),
)

func getModuleB() Option {
return Module(
"ModuleB",
moduleA,
)
}

func TestModuleTrace(t *testing.T) {
t.Parallel()

moduleC := Module(
"ModuleC",
getModuleB(),
)

app, spy := NewSpied(moduleC)
require.NoError(t, app.Err())

wantTrace, err := regexp.Compile(
// Provide/decorate itself, initialized via init.
"^go.uber.org/fx_test.init \\(.*fx/app_test.go:.*\\)\n" +
// ModuleA initialized via init.
"go.uber.org/fx_test.init \\(.*fx/app_test.go:.*\\) \\(ModuleA\\)\n" +
// ModuleB from getModuleB.
"go.uber.org/fx_test.getModuleB \\(.*fx/app_test.go:.*\\) \\(ModuleB\\)\n" +
// ModuleC above.
"go.uber.org/fx_test.TestModuleTrace \\(.*fx/app_test.go:.*\\) \\(ModuleC\\)\n" +
// Top-level app & corresponding module created by NewSpied.
"go.uber.org/fx_test.NewSpied \\(.*fx/app_test.go:.*\\)$",
)
require.NoError(t, err, "test regexp compilation error")

for _, tt := range []struct {
desc string
getTrace func(t *testing.T) []string
}{
{
desc: "Provide",
getTrace: func(t *testing.T) []string {
t.Helper()
var event *fxevent.Provided
for _, e := range spy.Events().SelectByTypeName("Provided") {
pe, ok := e.(*fxevent.Provided)
if !ok {
continue
}

if strings.HasSuffix(pe.ConstructorName, "getInt()") {
event = pe
break
}
}
require.NotNil(t, event, "could not find provide event for getInt()")
return event.ModuleTrace
},
},
{
desc: "Decorate",
getTrace: func(t *testing.T) []string {
t.Helper()
events := spy.Events().SelectByTypeName("Decorated")
require.Len(t, events, 1)
event, ok := events[0].(*fxevent.Decorated)
require.True(t, ok)
return event.ModuleTrace
},
},
{
desc: "Supply",
getTrace: func(t *testing.T) []string {
t.Helper()
events := spy.Events().SelectByTypeName("Supplied")
require.Len(t, events, 1)
event, ok := events[0].(*fxevent.Supplied)
require.True(t, ok)
return event.ModuleTrace
},
},
{
desc: "Replaced",
getTrace: func(t *testing.T) []string {
t.Helper()
events := spy.Events().SelectByTypeName("Replaced")
require.Len(t, events, 1)
event, ok := events[0].(*fxevent.Replaced)
require.True(t, ok)
return event.ModuleTrace
},
},
} {
t.Run(tt.desc, func(t *testing.T) {
gotTrace := strings.Join(tt.getTrace(t), "\n")
assert.Regexp(t, wantTrace, gotTrace)
})
}
}

func TestRunEventEmission(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -813,6 +920,10 @@ func (e *customError) Unwrap() error {
return e.err
}

type errHandlerFunc func(error)

func (f errHandlerFunc) HandleError(err error) { f(err) }

func TestInvokes(t *testing.T) {
t.Parallel()

Expand Down
20 changes: 15 additions & 5 deletions fxevent/console_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,19 @@ func TestConsoleLogger(t *testing.T) {
{
name: "Supplied",
give: &Supplied{
TypeName: "*bytes.Buffer",
StackTrace: []string{"main.main", "runtime.main"},
TypeName: "*bytes.Buffer",
StackTrace: []string{"main.main", "runtime.main"},
ModuleTrace: []string{"main.main"},
},
want: "[Fx] SUPPLY *bytes.Buffer\n",
},
{
name: "Supplied with module",
give: &Supplied{
TypeName: "*bytes.Buffer",
ModuleName: "myModule",
StackTrace: []string{"main.main", "runtime.main"},
TypeName: "*bytes.Buffer",
ModuleName: "myModule",
StackTrace: []string{"main.main", "runtime.main"},
ModuleTrace: []string{"main.main", "mypackage.GetMyModule"},
},
want: "[Fx] SUPPLY *bytes.Buffer from module \"myModule\"\n",
},
Expand All @@ -169,6 +171,7 @@ func TestConsoleLogger(t *testing.T) {
OutputTypeNames: []string{"*bytes.Buffer"},
Private: false,
StackTrace: []string{"main.main", "runtime.main"},
ModuleTrace: []string{"main.main"},
},
want: "[Fx] PROVIDE *bytes.Buffer <= bytes.NewBuffer()\n",
},
Expand All @@ -179,6 +182,7 @@ func TestConsoleLogger(t *testing.T) {
OutputTypeNames: []string{"*bytes.Buffer"},
Private: true,
StackTrace: []string{"main.main", "runtime.main"},
ModuleTrace: []string{"main.main"},
},
want: "[Fx] PROVIDE (PRIVATE) *bytes.Buffer <= bytes.NewBuffer()\n",
},
Expand All @@ -190,6 +194,7 @@ func TestConsoleLogger(t *testing.T) {
OutputTypeNames: []string{"*bytes.Buffer"},
Private: false,
StackTrace: []string{"main.main", "runtime.main"},
ModuleTrace: []string{"main.main", "mypackage.GetMyModule"},
},
want: "[Fx] PROVIDE *bytes.Buffer <= bytes.NewBuffer() from module \"myModule\"\n",
},
Expand All @@ -201,6 +206,7 @@ func TestConsoleLogger(t *testing.T) {
OutputTypeNames: []string{"*bytes.Buffer"},
Private: true,
StackTrace: []string{"main.main", "runtime.main"},
ModuleTrace: []string{"main.main", "mypackage.GetMyModule"},
},
want: "[Fx] PROVIDE (PRIVATE) *bytes.Buffer <= bytes.NewBuffer() from module \"myModule\"\n",
},
Expand All @@ -209,6 +215,7 @@ func TestConsoleLogger(t *testing.T) {
give: &Replaced{
OutputTypeNames: []string{"*bytes.Buffer"},
StackTrace: []string{"main.main", "runtime.main"},
ModuleTrace: []string{"main.main"},
},
want: "[Fx] REPLACE *bytes.Buffer\n",
},
Expand All @@ -218,6 +225,7 @@ func TestConsoleLogger(t *testing.T) {
ModuleName: "myModule",
OutputTypeNames: []string{"*bytes.Buffer"},
StackTrace: []string{"main.main", "runtime.main"},
ModuleTrace: []string{"main.main", "mypackage.GetMyModule"},
},
want: "[Fx] REPLACE *bytes.Buffer from module \"myModule\"\n",
},
Expand All @@ -232,6 +240,7 @@ func TestConsoleLogger(t *testing.T) {
DecoratorName: "bytes.NewBuffer()",
OutputTypeNames: []string{"*bytes.Buffer"},
StackTrace: []string{"main.main", "runtime.main"},
ModuleTrace: []string{"main.main"},
},
want: "[Fx] DECORATE *bytes.Buffer <= bytes.NewBuffer()\n",
},
Expand All @@ -242,6 +251,7 @@ func TestConsoleLogger(t *testing.T) {
ModuleName: "myModule",
OutputTypeNames: []string{"*bytes.Buffer"},
StackTrace: []string{"main.main", "runtime.main"},
ModuleTrace: []string{"main.main", "mypackage.GetMyModule"},
},
want: "[Fx] DECORATE *bytes.Buffer <= bytes.NewBuffer() from module \"myModule\"\n",
},
Expand Down
12 changes: 12 additions & 0 deletions fxevent/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ type Supplied struct {
// StackTrace is the stack trace of the call to Supply.
StackTrace []string

// ModuleTrace contains the module locations through which this value was added.
ModuleTrace []string

// ModuleName is the name of the module in which the value was added to.
ModuleName string

Expand All @@ -129,6 +132,9 @@ type Provided struct {
// StackTrace is the stack trace of where the constructor was provided to Fx.
StackTrace []string

// ModuleTrace contains the module locations through which this was provided to Fx.
ModuleTrace []string

// OutputTypeNames is a list of names of types that are produced by
// this constructor.
OutputTypeNames []string
Expand All @@ -152,6 +158,9 @@ type Replaced struct {
// StackTrace is the stack trace of the call to Replace.
StackTrace []string

// ModuleTrace contains the module locations through which this value was added.
ModuleTrace []string

// ModuleName is the name of the module in which the value was added to.
ModuleName string

Expand All @@ -168,6 +177,9 @@ type Decorated struct {
// StackTrace is the stack trace of where the decorator was given to Fx.
StackTrace []string

// ModuleTrace contains the module locations through which this value was added.
ModuleTrace []string

// ModuleName is the name of the module in which the value was added to.
ModuleName string

Expand Down
8 changes: 8 additions & 0 deletions fxevent/zap.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,14 @@ func (l *ZapLogger) LogEvent(event Event) {
l.logError("error encountered while applying options",
zap.String("type", e.TypeName),
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.Error(e.Err))
} else {
l.logEvent("supplied",
zap.String("type", e.TypeName),
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
)
}
Expand All @@ -119,6 +121,7 @@ func (l *ZapLogger) LogEvent(event Event) {
l.logEvent("provided",
zap.String("constructor", e.ConstructorName),
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.String("type", rtype),
maybeBool("private", e.Private),
Expand All @@ -128,19 +131,22 @@ func (l *ZapLogger) LogEvent(event Event) {
l.logError("error encountered while applying options",
moduleField(e.ModuleName),
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
zap.Error(e.Err))
}
case *Replaced:
for _, rtype := range e.OutputTypeNames {
l.logEvent("replaced",
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.String("type", rtype),
)
}
if e.Err != nil {
l.logError("error encountered while replacing",
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.Error(e.Err))
}
Expand All @@ -149,13 +155,15 @@ func (l *ZapLogger) LogEvent(event Event) {
l.logEvent("decorated",
zap.String("decorator", e.DecoratorName),
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.String("type", rtype),
)
}
if e.Err != nil {
l.logError("error encountered while applying options",
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.Error(e.Err))
}
Expand Down
Loading