From 519863ecab4db26d33d9a4af8f5284acf4b5ca29 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Wed, 5 Jan 2022 11:25:30 -0300 Subject: [PATCH] fix(core/node): unwrap fx error in node construction --- cmd/ipfs/daemon.go | 1 - core/builder.go | 50 ++++++++++++++++++++++++++++++++++++++++++++-- go.mod | 1 + go.sum | 3 ++- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index a2c65b5b99e..7bf79426542 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -427,7 +427,6 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment node, err := core.NewNode(req.Context, ncfg) if err != nil { - log.Error("error from node construction: ", err) return err } node.IsDaemon = true diff --git a/core/builder.go b/core/builder.go index e93ceddb2e3..c6bb9919206 100644 --- a/core/builder.go +++ b/core/builder.go @@ -2,6 +2,8 @@ package core import ( "context" + "fmt" + "reflect" "sync" "time" @@ -9,6 +11,7 @@ import ( "github.com/ipfs/go-ipfs/core/node" "github.com/ipfs/go-metrics-interface" + "go.uber.org/dig" "go.uber.org/fx" ) @@ -75,11 +78,11 @@ func NewNode(ctx context.Context, cfg *BuildCfg) (*IpfsNode, error) { }() if app.Err() != nil { - return nil, app.Err() + return nil, logAndUnwrapFxError(app.Err()) } if err := app.Start(ctx); err != nil { - return nil, err + return nil, logAndUnwrapFxError(err) } // TODO: How soon will bootstrap move to libp2p? @@ -89,3 +92,46 @@ func NewNode(ctx context.Context, cfg *BuildCfg) (*IpfsNode, error) { return n, n.Bootstrap(bootstrap.DefaultBootstrapConfig) } + +// Log the entire `app.Err()` but return only the innermost one to the user +// given the full error can be very long (as it can expose the entire build +// graph in a single string). +// +// The fx.App error exposed through `app.Err()` normally contains un-exported +// errors from its low-level `dig` package: +// * https://github.com/uber-go/dig/blob/5e5a20d/error.go#L82 +// These usually wrap themselves in many layers to expose where in the build +// chain did the error happen. Although useful for a developer that needs to +// debug it, it can be very confusing for a user that just wants the IPFS error +// that he can probably fix without being aware of the entire chain. +// Unwrapping everything is not the best solution as there can be useful +// information in the intermediate errors, mainly in the next to last error +// that locates which component is the build error coming from, but it's the +// best we can do at the moment given all errors in dig are private and we +// just have the generic `RootCause` API. +func logAndUnwrapFxError(fxAppErr error) error { + if fxAppErr == nil { + return nil + } + + log.Error("constructing the node: ", fxAppErr) + + err := fxAppErr + for { + extractedErr := dig.RootCause(err) + // Note that the `RootCause` name is misleading as it just unwraps only + // *one* error layer at a time, so we need to continuously call it. + if !reflect.TypeOf(extractedErr).Comparable() { + // Some internal errors are not comparable (e.g., `dig.errMissingTypes` + // which is a slice) and we can't go further. + break + } + if extractedErr == err { + // We didn't unwrap any new error in the last call, reached the innermost one. + break + } + err = extractedErr + } + + return fmt.Errorf("constructing the node (see log for full detail): %w", err) +} diff --git a/go.mod b/go.mod index af332571d8c..6dbb86e3a15 100644 --- a/go.mod +++ b/go.mod @@ -104,6 +104,7 @@ require ( github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 go.opencensus.io v0.23.0 + go.uber.org/dig v1.14.0 go.uber.org/fx v1.16.0 go.uber.org/zap v1.21.0 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 diff --git a/go.sum b/go.sum index 49abc3cac6d..e874965cbc0 100644 --- a/go.sum +++ b/go.sum @@ -1418,8 +1418,9 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/dig v1.12.0 h1:l1GQeZpEbss0/M4l/ZotuBndCrkMdjnygzgcuOjAdaY= go.uber.org/dig v1.12.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/dig v1.14.0 h1:VmGvIH45/aapXPQkaOrK5u4B5B7jxZB98HM/utx0eME= +go.uber.org/dig v1.14.0/go.mod h1:jHAn/z1Ld1luVVyGKOAIFYz/uBFqKjjEEdIqVAqfQ2o= go.uber.org/fx v1.16.0 h1:N8i80+X1DCX+qMRiKzM+jPPZiIiyK/bVCysga3+B+1w= go.uber.org/fx v1.16.0/go.mod h1:OMoT5BnXcOaiexlpjtpE4vcAmzyDKyRs9TRYXCzamx8= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=