From 71ef3a290ecd7953a7f58180199a4d514e7f73ff Mon Sep 17 00:00:00 2001 From: Tom Wiesing Date: Wed, 15 Nov 2023 11:06:30 +0100 Subject: [PATCH] Better error tracing --- internal/dis/component/server/admin/index.go | 6 +++- .../component/server/admin/instance_data.go | 4 +-- .../component/server/admin/instance_drupal.go | 2 +- .../server/admin/instance_snapshots.go | 2 +- .../component/server/admin/instance_ssh.go | 2 +- .../component/server/admin/instance_stats.go | 2 +- internal/dis/component/server/server.go | 4 ++- .../dis/component/server/templating/base.go | 30 +++++++++++++++---- internal/wisski/ingredient/info/info.go | 16 ++++++++-- 9 files changed, 52 insertions(+), 16 deletions(-) diff --git a/internal/dis/component/server/admin/index.go b/internal/dis/component/server/admin/index.go index ccc6ea3..34e84c2 100644 --- a/internal/dis/component/server/admin/index.go +++ b/internal/dis/component/server/admin/index.go @@ -2,6 +2,7 @@ package admin import ( "context" + "fmt" "net/http" "time" @@ -36,7 +37,10 @@ func (admin *Admin) Status(ctx context.Context, QuickInformation bool) (target s // store the info for this group! group.Go(func() (err error) { information[i], err = instance.Info().Information(ctx, true) - return err + if err != nil { + return fmt.Errorf("instance %q: %w", instance.Slug, err) + } + return }) } } diff --git a/internal/dis/component/server/admin/instance_data.go b/internal/dis/component/server/admin/instance_data.go index adf83f0..35da680 100644 --- a/internal/dis/component/server/admin/instance_data.go +++ b/internal/dis/component/server/admin/instance_data.go @@ -57,14 +57,14 @@ func (admin *Admin) instanceData(ctx context.Context) http.Handler { ctx.Pathbuilders, err = ctx.Instance.Pathbuilder().GetAll(r.Context(), server) if err != nil { - return ctx, nil, httpx.ErrInternalServerError + return ctx, nil, err } prefixes := ctx.Instance.Prefixes() ctx.NoPrefixes = prefixes.NoPrefix() ctx.Prefixes, err = prefixes.All(r.Context(), server) if err != nil { - return ctx, nil, httpx.ErrInternalServerError + return ctx, nil, err } return ctx, []templating.FlagFunc{ diff --git a/internal/dis/component/server/admin/instance_drupal.go b/internal/dis/component/server/admin/instance_drupal.go index a710a12..c5768e2 100644 --- a/internal/dis/component/server/admin/instance_drupal.go +++ b/internal/dis/component/server/admin/instance_drupal.go @@ -86,7 +86,7 @@ func (admin *Admin) instanceDrupal(ctx context.Context) http.Handler { }) if err = eg.Wait(); err != nil { - return ctx, nil, httpx.ErrInternalServerError + return ctx, nil, err } return ctx, []templating.FlagFunc{ diff --git a/internal/dis/component/server/admin/instance_snapshots.go b/internal/dis/component/server/admin/instance_snapshots.go index b266644..a655fc0 100644 --- a/internal/dis/component/server/admin/instance_snapshots.go +++ b/internal/dis/component/server/admin/instance_snapshots.go @@ -53,7 +53,7 @@ func (admin *Admin) instanceSnapshots(ctx context.Context) http.Handler { ctx.Snapshots, err = ctx.Instance.Snapshots(r.Context()) if err != nil { - return ctx, nil, httpx.ErrInternalServerError + return ctx, nil, err } return ctx, []templating.FlagFunc{ diff --git a/internal/dis/component/server/admin/instance_ssh.go b/internal/dis/component/server/admin/instance_ssh.go index 2fb691d..5e1be64 100644 --- a/internal/dis/component/server/admin/instance_ssh.go +++ b/internal/dis/component/server/admin/instance_ssh.go @@ -62,7 +62,7 @@ func (admin *Admin) instanceSSH(ctx context.Context) http.Handler { keys, err := ctx.Instance.SSH().Keys(r.Context()) if err != nil { - return ctx, nil, httpx.ErrInternalServerError + return ctx, nil, err } ctx.SSHKeys = make([]string, len(keys)) diff --git a/internal/dis/component/server/admin/instance_stats.go b/internal/dis/component/server/admin/instance_stats.go index 3f75fd4..447672c 100644 --- a/internal/dis/component/server/admin/instance_stats.go +++ b/internal/dis/component/server/admin/instance_stats.go @@ -54,7 +54,7 @@ func (admin *Admin) instanceStats(ctx context.Context) http.Handler { // read statistics ctx.Statistics, err = ctx.Instance.Stats().Get(r.Context(), nil) if err != nil { - return ctx, nil, httpx.ErrInternalServerError + return ctx, nil, err } return ctx, []templating.FlagFunc{ diff --git a/internal/dis/component/server/server.go b/internal/dis/component/server/server.go index 649d856..452376a 100644 --- a/internal/dis/component/server/server.go +++ b/internal/dis/component/server/server.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + "runtime/debug" "github.com/FAU-CDI/wisski-distillery/internal/dis/component" "github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating" @@ -145,6 +146,7 @@ func WithCSP(handler http.Handler, policy string) http.Handler { func init() { httpx.InterceptorOnFallback = func(req *http.Request, err error) { - zerolog.Ctx(req.Context()).Err(err).Msg("unknown error intercepted") + stack := debug.Stack() + zerolog.Ctx(req.Context()).Err(err).Str("stack", string(stack)).Msg("unknown error intercepted") } } diff --git a/internal/dis/component/server/templating/base.go b/internal/dis/component/server/templating/base.go index 34b1916..5799eba 100644 --- a/internal/dis/component/server/templating/base.go +++ b/internal/dis/component/server/templating/base.go @@ -7,6 +7,7 @@ import ( "html/template" "net/http" "reflect" + "runtime/debug" "strings" "time" @@ -165,6 +166,7 @@ func (ctx *tContext[C]) Footer() (template.HTML, error) { } const renderSafeError = "Error displaying page. See server log for details. " +const renderPanicError = "Panic displaying page. See server log for details. " func (ctx *tContext[C]) renderSafe(name string, t *template.Template, c any) (template.HTML, error) { @@ -173,16 +175,19 @@ func (ctx *tContext[C]) renderSafe(name string, t *template.Template, c any) (te return "", err } - value, err, panicked := func() (value template.HTML, err error, panicked bool) { + value, panicked, panik, stack, err := func() (value template.HTML, panicked bool, panik any, stack []byte, err error) { var builder strings.Builder defer func() { if panicked { - r := recover() + panik = recover() + stack = debug.Stack() + zerolog.Ctx(ctx.ctx).Error(). Str("uri", ctx.Runtime.RequestURI). Str("name", name). - Str("panic", fmt.Sprint(r)). + Str("panic", fmt.Sprint(panik)). + Str("stack", string(stack)). Msg("renderSafe: template panic()ed") } }() @@ -198,11 +203,24 @@ func (ctx *tContext[C]) renderSafe(name string, t *template.Template, c any) (te Msg("template errored") } - return template.HTML(builder.String()), err, false + return template.HTML(builder.String()), false, nil, nil, err }() - if err != nil || panicked { - return renderSafeError, httpx.ErrInternalServerError + if err != nil { + return renderSafeError, err + } + if panicked { + return renderPanicError, panicErr{value: panik, stack: stack} } return value, nil } + +// panicErr is returned by renderSafe when a panic occurs +type panicErr struct { + value any + stack []byte +} + +func (pe panicErr) Error() string { + return fmt.Sprintf("panic: %v", pe.value) +} diff --git a/internal/wisski/ingredient/info/info.go b/internal/wisski/ingredient/info/info.go index f908f42..604accc 100644 --- a/internal/wisski/ingredient/info/info.go +++ b/internal/wisski/ingredient/info/info.go @@ -2,6 +2,8 @@ package info import ( "context" + "fmt" + "reflect" "sync/atomic" "time" @@ -68,14 +70,24 @@ func (wisski *Info) Information(ctx context.Context, quick bool) (info status.Wi // quick: don't need to create servers if flags.Quick { defer recordTime(i)() - return fetcher.Fetch(flags, &info) + + err := fetcher.Fetch(flags, &info) + if err != nil { + return fmt.Errorf("fetcher %s (quick): %w", reflect.TypeOf(fetcher), err) + } + return nil } // complete: need to use a server from the pool return pool.Use(func(s *phpx.Server) error { defer recordTime(i)() flags.Server = s - return fetcher.Fetch(flags, &info) + + err := fetcher.Fetch(flags, &info) + if err != nil { + return fmt.Errorf("fetcher %s (pool): %w", reflect.TypeOf(fetcher), err) + } + return nil }) }) }