Skip to content

Commit

Permalink
Merge branch 'master' into logging-module
Browse files Browse the repository at this point in the history
  • Loading branch information
sywhang committed Mar 22, 2022
2 parents 466d9df + 24f6f50 commit 659d644
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 51 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/go.yml
Expand Up @@ -14,9 +14,9 @@ jobs:
strategy:
matrix:
os: ["ubuntu-latest", "windows-latest"]
go: ["1.15.x", "1.16.x", "1.17.x"]
go: ["1.17.x", "1.18.x"]
include:
- go: 1.17.x
- go: 1.18.x
os: "ubuntu-latest"
latest: true

Expand All @@ -28,7 +28,7 @@ jobs:

- name: Checkout code
uses: actions/checkout@v2

- name: Load cached dependencies
uses: actions/cache@v1
with:
Expand Down
126 changes: 108 additions & 18 deletions decorate.go
Expand Up @@ -29,41 +29,82 @@ import (
)

// Decorate specifies one or more decorator functions to an Fx application.
// Decorator functions let users augment objects in the graph. They can take in
// zero or more dependencies that must be provided to the application with fx.Provide,
// and produce one or more values that can be used by other invoked values.
//
// An example decorator is the following function which accepts a value, augments that value,
// and returns the replacement value.
// Decorator functions
//
// Decorator functions let users augment objects in the graph.
// They can take in zero or more dependencies that must be provided to the
// application with fx.Provide, and produce one or more values that can be used
// by other fx.Provide and fx.Invoke calls.
//
// fx.Decorate(func(log *zap.Logger) *zap.Logger {
// return log.Named("myapp")
// })
// fx.Invoke(func(log *zap.Logger) {
// log.Info("hello")
// // Output:
// // {"level": "info","logger":"myapp","msg":"hello"}
// })
//
// The following decorator accepts multiple dependencies from the graph, augments and returns
// one of them.
// The following decorator accepts multiple dependencies from the graph,
// augments and returns one of them.
//
// fx.Decorate(func(log *zap.Logger, cfg *Config) *zap.Logger {
// return log.Named(cfg.Name)
// })
//
// Similar to fx.Provide, functions passed to fx.Decorate may optionally return an error
// as their last result. If a decorator returns a non-nil error, it will halt application startup.
// Similar to fx.Provide, functions passed to fx.Decorate may optionally return
// an error as their last result.
// If a decorator returns a non-nil error, it will halt application startup.
//
// fx.Decorate(func(conn *sql.DB, cfg *Config) (*sql.DB, error) {
// if err := conn.Ping(); err != nil {
// return sql.Open("driver-name", cfg.FallbackDB)
// }
// return conn, nil
// })
//
// Decorators support both, fx.In and fx.Out structs, similar to fx.Provide and
// fx.Invoke.
//
// type Params struct {
// fx.In
//
// Client usersvc.Client `name:"readOnly"`
// }
//
// All modifications in the object graph due to a decorator are scoped to the fx.Module it was
// specified from. Decorations specified in the top-level fx.New call apply across the application.
// type Result struct {
// fx.Out
//
// Client usersvc.Client `name:"readOnly"`
// }
//
// Decorators can be annotated using fx.Annotate, but not with fx.Annotated. Refer to documentation
// on fx.Annotate() to learn how to use it for annotating functions.
// fx.Decorate(func(p Params) Result {
// ...
// })
//
// Decorators support fx.In and fx.Out structs, similar to fx.Provide and fx.Invoke.
// Decorators can be annotated with the fx.Annotate function, but not with the
// fx.Annotated type. Refer to documentation on fx.Annotate() to learn how to
// use it for annotating functions.
//
// fx.Decorate(
// fx.Annotate(
// func(client usersvc.Client) usersvc.Client {
// // ...
// },
// fx.ParamTags(`name:"readOnly"`),
// fx.ResultTags(`name:"readOnly"`),
// ),
// )
//
// Decorators support value groups as well. For example, the following code shows a decorator
// which takes in a value group using fx.In struct, and returns another value group.
// Decorators support augmenting, filtering, or replacing value groups.
// To decorate a value group, expect the entire value group slice and produce
// the new slice.
//
// type HandlerParam struct {
// fx.In
//
// Log *zap.Logger
// Handlers []Handler `group:"server"
// }
//
Expand All @@ -73,11 +114,60 @@ import (
// Handlers []Handler `group:"server"
// }
//
// fx.Decorate(func(p HandlerParam) HandlerResult {
// var r HandlerResult
// for _, handler := range p.Handlers {
// r.Handlers = append(r.Handlers, wrapWithLogger(p.Log, handler))
// }
// return r
// }),
//
// Decorator scope
//
// Modifications made to the Fx graph with fx.Decorate are scoped to the
// deepest fx.Module inside which the decorator was specified.
//
// fx.Module("mymodule",
// fx.Decorate(func(log *zap.Logger) *zap.Logger {
// return log.Named("myapp")
// }),
// fx.Invoke(func(log *zap.Logger) {
// log.Info("decorated logger")
// // Output:
// // {"level": "info","logger":"myapp","msg":"decorated logger"}
// }),
// ),
// fx.Invoke(func(log *zap.Logger) {
// log.Info("plain logger")
// // Output:
// // {"level": "info","msg":"plain logger"}
// }),
//
// Decorations specified in the top-level fx.New call apply across the
// application and chain with module-specific decorators.
//
// fx.New(
// // ...
// fx.Decorate(func(p HandlerParam) HandlerResult {
// // ...
// fx.Decorate(func(log *zap.Logger) *zap.Logger {
// return log.With(zap.Field("service", "myservice"))
// }),
// // ...
// fx.Invoke(func(log *zap.Logger) {
// log.Info("outer decorator")
// // Output:
// // {"level": "info","service":"myservice","msg":"outer decorator"}
// }),
// // ...
// fx.Module("mymodule",
// fx.Decorate(func(log *zap.Logger) *zap.Logger {
// return log.Named("myapp")
// }),
// fx.Invoke(func(log *zap.Logger) {
// log.Info("inner decorator")
// // Output:
// // {"level": "info","logger":"myapp","service":"myservice","msg":"inner decorator"}
// }),
// ),
// )
func Decorate(decorators ...interface{}) Option {
return decorateOption{
Expand Down
9 changes: 8 additions & 1 deletion go.mod
@@ -1,6 +1,6 @@
module go.uber.org/fx

go 1.13
go 1.17

require (
github.com/benbjohnson/clock v1.3.0
Expand All @@ -11,3 +11,10 @@ require (
go.uber.org/zap v1.16.0
golang.org/x/sys v0.0.0-20210903071746-97244b99971b
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/atomic v1.6.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
44 changes: 41 additions & 3 deletions replace.go
Expand Up @@ -28,14 +28,52 @@ import (
"go.uber.org/fx/internal/fxreflect"
)

// Replace provides instantiated values for graph modification. Similar to
// what fx.Supply is to fx.Provide, values provided by fx.Replace behaves
// similarly to values produced by decorators specified with fx.Decorate.
// Replace provides instantiated values for graph modification as if
// they had been provided using a decorator with fx.Decorate.
// The most specific type of each value (as determined by reflection) is used.
//
// Refer to the documentation on fx.Decorate to see how graph modifications
// work with fx.Module.
//
// This serves a purpose similar to what fx.Supply does for fx.Provide.
//
// For example, given,
//
// var log *zap.Logger = ...
//
// The following two forms are equivalent.
//
// fx.Replace(log)
//
// fx.Decorate(
// func() *zap.Logger {
// return log
// },
// )
//
// Replace panics if a value (or annotation target) is an untyped nil or an error.
//
// Replace Caveats
//
// As mentioned above, Replace uses the most specific type of the provided
// value. For interface values, this refers to the type of the implementation,
// not the interface. So if you try to replace an io.Writer, fx.Replace will
// use the type of the implementation.
//
// var stderr io.Writer = os.Stderr
// fx.Replace(stderr)
//
// Is equivalent to,
//
// fx.Decorate(func() *os.File { return os.Stderr })
//
// This is typically NOT what you intended. To replace the io.Writer in the
// container with the value above, we need to use the fx.Annotate function with
// the fx.As annotation.
//
// fx.Replace(
// fx.Annotate(os.Stderr, fx.As(new(io.Writer)))
// )
func Replace(values ...interface{}) Option {
decorators := make([]interface{}, len(values)) // one function per value
types := make([]reflect.Type, len(values))
Expand Down
24 changes: 24 additions & 0 deletions supply.go
Expand Up @@ -32,6 +32,8 @@ import (
// they had been provided using a constructor that simply returns them.
// The most specific type of each value (as determined by reflection) is used.
//
// This serves a purpose similar to what fx.Replace does for fx.Decorate.
//
// For example, given:
//
// type (
Expand All @@ -53,6 +55,28 @@ import (
// )
//
// Supply panics if a value (or annotation target) is an untyped nil or an error.
//
// Supply Caveats
//
// As mentioned above, Supply uses the most specific type of the provided
// value. For interface values, this refers to the type of the implementation,
// not the interface. So if you supply an http.Handler, fx.Supply will use the
// type of the implementation.
//
// var handler http.Handler = http.HandlerFunc(f)
// fx.Supply(handler)
//
// Is equivalent to,
//
// fx.Provide(func() http.HandlerFunc { return f })
//
// This is typically NOT what you intended. To supply the handler above as an
// http.Handler, we need to use the fx.Annotate function with the fx.As
// annotation.
//
// fx.Supply(
// fx.Annotate(handler, fx.As(new(http.Handler))),
// )
func Supply(values ...interface{}) Option {
constructors := make([]interface{}, len(values)) // one function per value
types := make([]reflect.Type, len(values))
Expand Down
15 changes: 11 additions & 4 deletions tools/go.mod
@@ -1,10 +1,17 @@
module go.uber.org/fx/tools

go 1.16
go 1.17

require (
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
golang.org/x/tools v0.1.4
honnef.co/go/tools v0.2.0
golang.org/x/tools v0.1.10
honnef.co/go/tools v0.3.0-0.dev.0.20220306074811-23e1086441d2
)

require (
github.com/BurntSushi/toml v1.0.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20220314205449-43aec2f8a4e7 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)
47 changes: 25 additions & 22 deletions tools/go.sum
@@ -1,44 +1,47 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU=
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20220314205449-43aec2f8a4e7 h1:mzVEuUhnztMdHb426A1o6cjz5ha6YV3t6zFTBXqSon4=
golang.org/x/exp/typeparams v0.0.0-20220314205449-43aec2f8a4e7/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.4 h1:cVngSRcfgyZCzys3KYOpCFa+4dqX/Oub9tAq00ttGVs=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
honnef.co/go/tools v0.2.0 h1:ws8AfbgTX3oIczLPNPCu5166oBg9ST2vNs0rcht+mDE=
honnef.co/go/tools v0.2.0/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
honnef.co/go/tools v0.3.0-0.dev.0.20220306074811-23e1086441d2 h1:utiSabORbG/JeX7MlmKMdmsjwom2+v8zmdb6SoBe4UY=
honnef.co/go/tools v0.3.0-0.dev.0.20220306074811-23e1086441d2/go.mod h1:dZI0HmIvwDMW8owtLBJxTHoeX48yuF5p5pDy3y73jGU=

0 comments on commit 659d644

Please sign in to comment.