diff --git a/go.mod b/go.mod index f96f3ff..31a9967 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/pterodactyl/wings go 1.13 require ( + emperror.dev/errors v0.8.0 github.com/AlecAivazis/survey/v2 v2.1.0 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/Jeffail/gabs/v2 v2.5.1 diff --git a/go.sum b/go.sum index 686af03..03b36ad 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +emperror.dev/errors v0.8.0 h1:4lycVEx0sdJkwDUfQ9pdu6SR0x7rgympt5f4+ok8jDk= +emperror.dev/errors v0.8.0/go.mod h1:YcRvLPh626Ubn2xqtoprejnA5nFha+TJ+2vew48kWuE= github.com/AlecAivazis/survey/v2 v2.1.0 h1:AT4+23hOFopXYZaNGugbk7MWItkz0SfTmH/Hk92KeeE= github.com/AlecAivazis/survey/v2 v2.1.0/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0Ttd6q3Vl2fahjk= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= @@ -561,9 +563,13 @@ go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= diff --git a/loggers/cli/cli.go b/loggers/cli/cli.go index 93d3dfd..181d094 100644 --- a/loggers/cli/cli.go +++ b/loggers/cli/cli.go @@ -1,14 +1,13 @@ package cli import ( + "emperror.dev/errors" "fmt" "github.com/apex/log" "github.com/apex/log/handlers/cli" color2 "github.com/fatih/color" "github.com/mattn/go-colorable" - "github.com/pkg/errors" "io" - "math" "os" "sync" "time" @@ -42,10 +41,6 @@ func New(w io.Writer, useColors bool) *Handler { return &Handler{Writer: colorable.NewNonColorable(w), Padding: 2} } -type tracer interface { - StackTrace() errors.StackTrace -} - // HandleLog implements log.Handler. func (h *Handler) HandleLog(e *log.Entry) error { color := cli.Colors[e.Level] @@ -71,13 +66,10 @@ func (h *Handler) HandleLog(e *log.Entry) error { continue } if err, ok := e.Fields.Get("error").(error); ok { - if e, ok := errors.Cause(err).(tracer); ok { - st := e.StackTrace() - l := math.Min(float64(len(st)), 10) - fmt.Fprintf(h.Writer, "\n%s%+v\n\n", boldred.Sprintf("Stacktrace:"), st[0:int(l)]) - } else { - fmt.Fprintf(h.Writer, "\n%s\n%+v\n\n", boldred.Sprintf("Stacktrace:"), err) - } + // Attach the stacktrace if it is missing at this point, but don't point + // it specifically to this line since that is irrelevant. + err = errors.WithStackDepthIf(err, 1) + fmt.Fprintf(h.Writer, "\n%s\n%+v\n\n", boldred.Sprintf("Stacktrace:"), err) } } diff --git a/router/error.go b/router/error.go index 551d6ab..deea8f6 100644 --- a/router/error.go +++ b/router/error.go @@ -1,11 +1,11 @@ package router import ( + "emperror.dev/errors" "fmt" "github.com/apex/log" "github.com/gin-gonic/gin" "github.com/google/uuid" - "github.com/pkg/errors" "github.com/pterodactyl/wings/server" "github.com/pterodactyl/wings/server/filesystem" "net/http" @@ -20,6 +20,15 @@ type RequestError struct { server *server.Server } +// Attaches an error to the gin.Context object for the request and ensures that it +// has a proper stacktrace associated with it when doing so. +// +// If you just call c.Error(err) without using this function you'll likely end up +// with an error that has no annotated stack on it. +func WithError(c *gin.Context, err error) error { + return c.Error(errors.WithStackDepthIf(err, 1)) +} + // Generates a new tracked error, which simply tracks the specific error that // is being passed in, and also assigned a UUID to the error so that it can be // cross referenced in the logs. @@ -42,9 +51,9 @@ func NewServerError(err error, s *server.Server) *RequestError { func (e *RequestError) logger() *log.Entry { if e.server != nil { - return e.server.Log().WithField("error_id", e.uuid) + return e.server.Log().WithField("error_id", e.uuid).WithField("error", e.err) } - return log.WithField("error_id", e.uuid) + return log.WithField("error_id", e.uuid).WithField("error", e.err) } // Sets the output message to display to the user in the error. @@ -67,7 +76,7 @@ func (e *RequestError) AbortWithStatus(status int, c *gin.Context) { // If this error is because the resource does not exist, we likely do not need to log // the error anywhere, just return a 404 and move on with our lives. if errors.Is(e.err, os.ErrNotExist) { - e.logger().WithField("error", e.err).Debug("encountered os.IsNotExist error while handling request") + e.logger().Debug("encountered os.IsNotExist error while handling request") c.AbortWithStatusJSON(http.StatusNotFound, gin.H{ "error": "The requested resource was not found on the system.", }) @@ -84,9 +93,9 @@ func (e *RequestError) AbortWithStatus(status int, c *gin.Context) { // Otherwise, log the error to zap, and then report the error back to the user. if status >= 500 { - e.logger().WithField("error", e.err).Error("unexpected error while handling HTTP request") + e.logger().Error("unexpected error while handling HTTP request") } else { - e.logger().WithField("error", e.err).Debug("non-server error encountered while handling HTTP request") + e.logger().Debug("non-server error encountered while handling HTTP request") } if e.message == "" { diff --git a/router/middleware.go b/router/middleware.go index 2fd1e70..7635f5b 100644 --- a/router/middleware.go +++ b/router/middleware.go @@ -1,9 +1,9 @@ package router import ( + "emperror.dev/errors" "github.com/gin-gonic/gin" "github.com/google/uuid" - "github.com/pkg/errors" "github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/server" "io" diff --git a/router/router_server_files.go b/router/router_server_files.go index 44fcd15..0c10393 100644 --- a/router/router_server_files.go +++ b/router/router_server_files.go @@ -57,14 +57,11 @@ func getServerFileContents(c *gin.Context) { // Returns the contents of a directory for a server. func getServerListDirectory(c *gin.Context) { s := ExtractServer(c) - - stats, err := s.Filesystem().ListDirectory(c.Query("directory")) - if err != nil { - NewServerError(err, s).AbortFilesystemError(c) - return + if stats, err := s.Filesystem().ListDirectory(c.Query("directory")); err != nil { + WithError(c, err) + } else { + c.JSON(http.StatusOK, stats) } - - c.JSON(http.StatusOK, stats) } type renameFile struct {