Better error tracing

This commit is contained in:
Tom Wiesing 2023-11-15 11:06:30 +01:00
parent e968f0a5b9
commit 71ef3a290e
No known key found for this signature in database
9 changed files with 52 additions and 16 deletions

View file

@ -2,6 +2,7 @@ package admin
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
"time" "time"
@ -36,7 +37,10 @@ func (admin *Admin) Status(ctx context.Context, QuickInformation bool) (target s
// store the info for this group! // store the info for this group!
group.Go(func() (err error) { group.Go(func() (err error) {
information[i], err = instance.Info().Information(ctx, true) information[i], err = instance.Info().Information(ctx, true)
return err if err != nil {
return fmt.Errorf("instance %q: %w", instance.Slug, err)
}
return
}) })
} }
} }

View file

@ -57,14 +57,14 @@ func (admin *Admin) instanceData(ctx context.Context) http.Handler {
ctx.Pathbuilders, err = ctx.Instance.Pathbuilder().GetAll(r.Context(), server) ctx.Pathbuilders, err = ctx.Instance.Pathbuilder().GetAll(r.Context(), server)
if err != nil { if err != nil {
return ctx, nil, httpx.ErrInternalServerError return ctx, nil, err
} }
prefixes := ctx.Instance.Prefixes() prefixes := ctx.Instance.Prefixes()
ctx.NoPrefixes = prefixes.NoPrefix() ctx.NoPrefixes = prefixes.NoPrefix()
ctx.Prefixes, err = prefixes.All(r.Context(), server) ctx.Prefixes, err = prefixes.All(r.Context(), server)
if err != nil { if err != nil {
return ctx, nil, httpx.ErrInternalServerError return ctx, nil, err
} }
return ctx, []templating.FlagFunc{ return ctx, []templating.FlagFunc{

View file

@ -86,7 +86,7 @@ func (admin *Admin) instanceDrupal(ctx context.Context) http.Handler {
}) })
if err = eg.Wait(); err != nil { if err = eg.Wait(); err != nil {
return ctx, nil, httpx.ErrInternalServerError return ctx, nil, err
} }
return ctx, []templating.FlagFunc{ return ctx, []templating.FlagFunc{

View file

@ -53,7 +53,7 @@ func (admin *Admin) instanceSnapshots(ctx context.Context) http.Handler {
ctx.Snapshots, err = ctx.Instance.Snapshots(r.Context()) ctx.Snapshots, err = ctx.Instance.Snapshots(r.Context())
if err != nil { if err != nil {
return ctx, nil, httpx.ErrInternalServerError return ctx, nil, err
} }
return ctx, []templating.FlagFunc{ return ctx, []templating.FlagFunc{

View file

@ -62,7 +62,7 @@ func (admin *Admin) instanceSSH(ctx context.Context) http.Handler {
keys, err := ctx.Instance.SSH().Keys(r.Context()) keys, err := ctx.Instance.SSH().Keys(r.Context())
if err != nil { if err != nil {
return ctx, nil, httpx.ErrInternalServerError return ctx, nil, err
} }
ctx.SSHKeys = make([]string, len(keys)) ctx.SSHKeys = make([]string, len(keys))

View file

@ -54,7 +54,7 @@ func (admin *Admin) instanceStats(ctx context.Context) http.Handler {
// read statistics // read statistics
ctx.Statistics, err = ctx.Instance.Stats().Get(r.Context(), nil) ctx.Statistics, err = ctx.Instance.Stats().Get(r.Context(), nil)
if err != nil { if err != nil {
return ctx, nil, httpx.ErrInternalServerError return ctx, nil, err
} }
return ctx, []templating.FlagFunc{ return ctx, []templating.FlagFunc{

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"runtime/debug"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component" "github.com/FAU-CDI/wisski-distillery/internal/dis/component"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating" "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() { func init() {
httpx.InterceptorOnFallback = func(req *http.Request, err error) { 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")
} }
} }

View file

@ -7,6 +7,7 @@ import (
"html/template" "html/template"
"net/http" "net/http"
"reflect" "reflect"
"runtime/debug"
"strings" "strings"
"time" "time"
@ -165,6 +166,7 @@ func (ctx *tContext[C]) Footer() (template.HTML, error) {
} }
const renderSafeError = "Error displaying page. See server log for details. " 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) { 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 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 var builder strings.Builder
defer func() { defer func() {
if panicked { if panicked {
r := recover() panik = recover()
stack = debug.Stack()
zerolog.Ctx(ctx.ctx).Error(). zerolog.Ctx(ctx.ctx).Error().
Str("uri", ctx.Runtime.RequestURI). Str("uri", ctx.Runtime.RequestURI).
Str("name", name). Str("name", name).
Str("panic", fmt.Sprint(r)). Str("panic", fmt.Sprint(panik)).
Str("stack", string(stack)).
Msg("renderSafe: template panic()ed") 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") Msg("template errored")
} }
return template.HTML(builder.String()), err, false return template.HTML(builder.String()), false, nil, nil, err
}() }()
if err != nil || panicked { if err != nil {
return renderSafeError, httpx.ErrInternalServerError return renderSafeError, err
}
if panicked {
return renderPanicError, panicErr{value: panik, stack: stack}
} }
return value, nil 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)
}

View file

@ -2,6 +2,8 @@ package info
import ( import (
"context" "context"
"fmt"
"reflect"
"sync/atomic" "sync/atomic"
"time" "time"
@ -68,14 +70,24 @@ func (wisski *Info) Information(ctx context.Context, quick bool) (info status.Wi
// quick: don't need to create servers // quick: don't need to create servers
if flags.Quick { if flags.Quick {
defer recordTime(i)() 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 // complete: need to use a server from the pool
return pool.Use(func(s *phpx.Server) error { return pool.Use(func(s *phpx.Server) error {
defer recordTime(i)() defer recordTime(i)()
flags.Server = s 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
}) })
}) })
} }