Skip to content

Commit 559b0dd

Browse files
committed
Improve error reporting for Populate()
Show the pretty-printed error from populating the object graph in PrintObjects() and PrintDotGraph(). Add the ErrPopulate so we can add special casing for it in cilium/cilium to also do the pretty-printing of the error there. Will look like this: 2025/03/07 11:30:13 ERROR Invoke failed error="missing type:\n\t- resource.Resource[*github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1.Service] (did you mean to Provide it?)" function="cmd.configureAPIServer (cmd/cells.go:330)" Failed to populate object graph: could not build arguments for function "github.com/cilium/cilium/daemon/cmd".configureAPIServer /home/jussi/go/src/github.com/cilium/cilium/daemon/cmd/cells.go:330: failed to build *server.Server: could not build arguments for function "github.com/cilium/cilium/api/v1/server".newForCell /home/jussi/go/src/github.com/cilium/cilium/api/v1/server/server.go:206: failed to build *restapi.CiliumAPIAPI: could not build arguments for function "github.com/cilium/cilium/api/v1/server".newAPI /home/jussi/go/src/github.com/cilium/cilium/api/v1/server/server.go:125: failed to build endpoint.DeleteEndpointHandler: could not build arguments for function "github.com/cilium/cilium/daemon/cmd".ciliumAPIHandlers /home/jussi/go/src/github.com/cilium/cilium/daemon/cmd/api_handlers.go:81: failed to build promise.Promise[*github.com/cilium/cilium/daemon/cmd.Daemon]: could not build arguments for function "github.com/cilium/cilium/daemon/cmd".newDaemonPromise /home/jussi/go/src/github.com/cilium/cilium/daemon/cmd/daemon_main.go:1585: failed to build *clustermesh.ClusterMesh: could not build arguments for function "github.com/cilium/cilium/pkg/clustermesh".NewClusterMesh /home/jussi/go/src/github.com/cilium/cilium/pkg/clustermesh/clustermesh.go:133: failed to build *dial.ServiceResolver: missing dependencies for function "github.com/cilium/cilium/pkg/dial".newServiceResolver /home/jussi/go/src/github.com/cilium/cilium/pkg/dial/resolver.go:43: missing type: - resource.Resource[*github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1.Service] (did you mean to Provide it?) Signed-off-by: Jussi Maki <[email protected]>
1 parent 08596a8 commit 559b0dd

File tree

4 files changed

+44
-22
lines changed

4 files changed

+44
-22
lines changed

cell/invoke.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func (inv *invoker) invoke(log *slog.Logger, cont container, logThreshold time.D
4949
defer inv.funcs[i].infoMu.Unlock()
5050

5151
if err := cont.Invoke(nf.fn, opts...); err != nil {
52-
log.Error("Invoke failed", "error", err, "function", nf.name)
52+
log.Error("Invoke failed", "error", dig.RootCause(err), "function", nf.name)
5353
return err
5454
}
5555
d := time.Since(t0)

command.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,23 @@ import (
1414
// command can be used to inspect the dependency graph.
1515
func (h *Hive) Command() *cobra.Command {
1616
cmd := &cobra.Command{
17-
Use: "hive",
18-
Short: "Inspect the hive",
19-
Run: func(cmd *cobra.Command, args []string) {
20-
h.PrintObjects(os.Stdout, slog.Default())
17+
Use: "hive",
18+
Short: "Inspect the hive",
19+
SilenceUsage: true,
20+
RunE: func(cmd *cobra.Command, args []string) error {
21+
return h.PrintObjects(os.Stdout, slog.Default())
2122
},
2223
TraverseChildren: false,
2324
}
2425
h.RegisterFlags(cmd.PersistentFlags())
2526

2627
cmd.AddCommand(
2728
&cobra.Command{
28-
Use: "dot-graph",
29-
Short: "Output the dependencies graph in graphviz dot format",
30-
Run: func(cmd *cobra.Command, args []string) {
31-
h.PrintDotGraph()
29+
Use: "dot-graph",
30+
Short: "Output the dependencies graph in graphviz dot format",
31+
SilenceUsage: true,
32+
RunE: func(cmd *cobra.Command, args []string) error {
33+
return h.PrintDotGraph()
3234
},
3335
TraverseChildren: false,
3436
})

hive.go

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ func (h *Hive) Run(log *slog.Logger) error {
229229

230230
var errs error
231231
if err := h.Start(log, startCtx); err != nil {
232+
if errors.Is(err, ErrPopulate{}) {
233+
return err
234+
}
232235
errs = errors.Join(errs, fmt.Errorf("failed to start: %w", err))
233236
}
234237

@@ -326,12 +329,27 @@ func (h *Hive) AppendInvoke(invoke func(*slog.Logger, time.Duration) error) {
326329
h.invokes = append(h.invokes, invoke)
327330
}
328331

332+
type ErrPopulate struct {
333+
err error
334+
}
335+
336+
// Error implements error.
337+
func (e ErrPopulate) Error() string {
338+
return fmt.Sprintf("failed to populate object graph: %s", dig.RootCause(e.err))
339+
}
340+
341+
func (e ErrPopulate) Pretty() string {
342+
return fmt.Sprintf("Failed to populate object graph:\n%+v", e.err)
343+
}
344+
345+
var _ error = ErrPopulate{}
346+
329347
// Start starts the hive. The context allows cancelling the start.
330348
// If context is cancelled and the start hooks do not respect the cancellation
331349
// then after 5 more seconds the process will be terminated forcefully.
332350
func (h *Hive) Start(log *slog.Logger, ctx context.Context) error {
333351
if err := h.Populate(log); err != nil {
334-
return err
352+
return ErrPopulate{err}
335353
}
336354

337355
defer close(h.fatalOnTimeout(ctx))
@@ -393,9 +411,11 @@ func (h *Hive) Shutdown(opts ...ShutdownOption) {
393411
}
394412
}
395413

396-
func (h *Hive) PrintObjects(w io.Writer, log *slog.Logger) {
414+
func (h *Hive) PrintObjects(w io.Writer, log *slog.Logger) error {
397415
if err := h.Populate(log); err != nil {
398-
panic(fmt.Sprintf("Failed to populate object graph: %s", err))
416+
err := ErrPopulate{err}
417+
fmt.Fprintf(w, "ERROR: %s\n", err.Pretty())
418+
return err
399419
}
400420

401421
fmt.Fprintf(w, "Cells:\n\n")
@@ -405,16 +425,16 @@ func (h *Hive) PrintObjects(w io.Writer, log *slog.Logger) {
405425
fmt.Fprintln(w)
406426
}
407427
h.lifecycle.PrintHooks(w)
428+
return nil
408429
}
409430

410-
func (h *Hive) PrintDotGraph() {
431+
func (h *Hive) PrintDotGraph() error {
411432
if err := h.Populate(slog.Default()); err != nil {
412-
panic(fmt.Sprintf("Failed to populate object graph: %s", err))
413-
}
414-
415-
if err := dig.Visualize(h.container, os.Stdout); err != nil {
416-
panic(fmt.Sprintf("Failed to dig.Visualize(): %s", err))
433+
err := ErrPopulate{err}
434+
fmt.Fprintf(os.Stderr, "ERROR: %s\n", err.Pretty())
435+
return err
417436
}
437+
return dig.Visualize(h.container, os.Stdout)
418438
}
419439

420440
// getEnvName returns the environment variable to be used for the given option name.
@@ -434,10 +454,10 @@ func (h *Hive) ScriptCommands(log *slog.Logger) (map[string]script.Cmd, error) {
434454
m["hive/stop"] = hiveStopCmd(h, log)
435455

436456
// Gather the commands from the hive.
437-
h.container.Invoke(func(sc ScriptCmds) {
457+
err := h.container.Invoke(func(sc ScriptCmds) {
438458
for name, cmd := range sc.Map() {
439459
m[name] = cmd
440460
}
441461
})
442-
return m, nil
462+
return m, err
443463
}

script.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ func hiveScriptCmd(h *Hive, log *slog.Logger) script.Cmd {
8282
defer cancel()
8383
return nil, h.Stop(log, ctx)
8484
default:
85-
h.PrintObjects(s.LogWriter(), log)
86-
return nil, nil
85+
err := h.PrintObjects(s.LogWriter(), log)
86+
return nil, err
8787
}
8888
},
8989
)

0 commit comments

Comments
 (0)