You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, the events that the [fxevent
package](https://pkg.go.dev/go.uber.org/fx/fxevent) emits for
[provides](https://pkg.go.dev/go.uber.org/fx/fxevent#Provided)/[decorates](https://pkg.go.dev/go.uber.org/fx/fxevent#Decorated)/[supplies](https://pkg.go.dev/go.uber.org/fx/fxevent#Supplied)/[replaces](https://pkg.go.dev/go.uber.org/fx/fxevent#Replaced)
include stack traces of where the Fx call was made.
These stack traces often look something like this:
```
somepkg.init (/path/to/some/distant/package/module.go:14)
runtime.doInit1 (/opt/homebrew/Cellar/go/1.21.1/libexec/src/runtime/proc.go:6740)
runtime.doInit (/opt/homebrew/Cellar/go/1.21.1/libexec/src/runtime/proc.go:6707)
runtime.main (/opt/homebrew/Cellar/go/1.21.1/libexec/src/runtime/proc.go:249)
```
While these do show exactly where the provide/decorate/supply/replace
statement lives, for larger codebases where a single app may include a
wide variety of modules, each with their own chain of sub-modules, this
stack trace does a bad job of answering: "How did this constructor get
included in my app in the first place?"
This PR proposes module traces, an attempt to alleviate this issue by
providing a trace through the module chain by which a
provide/decorate/supply/replace found its way to the top-level app
declaration.
For this example,
```
9 func getThing() thing {
10 return thing{}
11 }
12
13 var ThingModule = fx.Module(
14 "ThingFx",
15 fx.Provide(getThing),
16 )
17
18 var ServiceModule = fx.Module(
19 "ServiceFx",
20 ThingModule,
21 )
22
23 func main() {
24 app := fx.New(
25 ServiceModule,
26 fx.Invoke(useThing),
27 )
28 }
```
The provide event for `getThing` will include the following module
trace:
```
main.init (/Users/joaks/go/src/scratch/mod_stacks_scratch/main.go:15)
main.init (/Users/joaks/go/src/scratch/mod_stacks_scratch/main.go:13) (ThingFx)
main.init (/Users/joaks/go/src/scratch/mod_stacks_scratch/main.go:18) (ServiceFx)
main.run (/Users/joaks/go/src/scratch/mod_stacks_scratch/main.go:24)
```
Which shows exactly how `getThing` got included in `app` in order:
* getThing is provided at `main.go:15`
* ThingFx is declared at `main.go:13`
* ServiceFx is declared at `main.go:18`
* The app is declared at `main.go:24`
This makes it more clear to the developer how functions are getting
included, especially for large codebase where modules may be distributed
all over.
0 commit comments