diff --git a/apiserver/database/database.go b/apiserver/database/database.go index 52d300718..279bdc96e 100644 --- a/apiserver/database/database.go +++ b/apiserver/database/database.go @@ -1,6 +1,7 @@ package database import ( + nativeerrors "errors" "fmt" "github.com/pkg/errors" "os" @@ -76,11 +77,11 @@ func buildConnectionString(cfg *config.Config) string { func isCurrent(migrator *migrate.Migrate, driver source.Driver) (bool, uint, error) { // Get the current version version, isDirty, err := migrator.Version() - if err == migrate.ErrNilVersion { + if nativeerrors.Is(err, migrate.ErrNilVersion) { return false, 0, nil } if err != nil { - return false, 0, err + return false, 0, errors.WithStack(err) } if isDirty { return false, 0, errors.Errorf("Database is dirty") diff --git a/apiserver/main.go b/apiserver/main.go index 6a2dba294..1c51c43a3 100644 --- a/apiserver/main.go +++ b/apiserver/main.go @@ -18,7 +18,7 @@ import ( ) func main() { - defer panics.HandlePanic(log, logger.BackendLog) + defer panics.HandlePanic(log, logger.BackendLog, nil) cfg, err := config.Parse() if err != nil { diff --git a/btcd.go b/btcd.go index 67e75ba86..b169fa1cf 100644 --- a/btcd.go +++ b/btcd.go @@ -57,7 +57,7 @@ func btcdMain(serverChan chan<- *server.Server) error { return err } cfg = config.ActiveConfig() - defer panics.HandlePanic(btcdLog, logger.BackendLog) + defer panics.HandlePanic(btcdLog, logger.BackendLog, nil) // Get a channel that will be closed when a shutdown signal has been // triggered either from an OS signal such as SIGINT (Ctrl+C) or from diff --git a/cmd/txgen/main.go b/cmd/txgen/main.go index a72870da5..f3d5bcb47 100644 --- a/cmd/txgen/main.go +++ b/cmd/txgen/main.go @@ -23,7 +23,7 @@ func privateKeyToP2pkhAddress(key *btcec.PrivateKey, net *dagconfig.Params) (uti } func main() { - defer panics.HandlePanic(log, backendLog) + defer panics.HandlePanic(log, backendLog, nil) cfg, err := parseConfig() if err != nil { diff --git a/dnsseeder/dnsseed.go b/dnsseeder/dnsseed.go index 1dc087639..b32bb340c 100644 --- a/dnsseeder/dnsseed.go +++ b/dnsseeder/dnsseed.go @@ -156,7 +156,7 @@ func creep() { } func main() { - defer panics.HandlePanic(log, backendLog) + defer panics.HandlePanic(log, backendLog, nil) cfg, err := loadConfig() if err != nil { fmt.Fprintf(os.Stderr, "loadConfig: %v\n", err) diff --git a/faucet/database/database.go b/faucet/database/database.go index 6bbd3ed93..c32b5c5a1 100644 --- a/faucet/database/database.go +++ b/faucet/database/database.go @@ -1,6 +1,7 @@ package database import ( + nativeerrors "errors" "fmt" "github.com/pkg/errors" "os" @@ -83,7 +84,7 @@ func buildConnectionString() (string, error) { func isCurrent(migrator *migrate.Migrate, driver source.Driver) (bool, uint, error) { // Get the current version version, isDirty, err := migrator.Version() - if err == migrate.ErrNilVersion { + if nativeerrors.Is(err, migrate.ErrNilVersion) { return false, 0, nil } if err != nil { diff --git a/faucet/main.go b/faucet/main.go index 827d7b6a7..3c5d50d8b 100644 --- a/faucet/main.go +++ b/faucet/main.go @@ -27,7 +27,7 @@ var ( ) func main() { - defer panics.HandlePanic(log, logger.BackendLog) + defer panics.HandlePanic(log, logger.BackendLog, nil) err := config.Parse() if err != nil { diff --git a/httpserverutils/middlewares.go b/httpserverutils/middlewares.go index dc4ec1e53..1e2aeefb5 100644 --- a/httpserverutils/middlewares.go +++ b/httpserverutils/middlewares.go @@ -1,7 +1,6 @@ package httpserverutils import ( - "fmt" "github.com/pkg/errors" "net/http" "runtime/debug" @@ -45,8 +44,7 @@ func RecoveryMiddleware(h http.Handler) http.Handler { } else { recoveryErrAsError = errors.Errorf("%s", recoveryErr) } - recoveryErrStr := fmt.Sprintf("%s", recoveryErr) - log.Criticalf("Fatal error: %+v", recoveryErrStr) + log.Criticalf("Fatal error: %+v", recoveryErrAsError) log.Criticalf("Stack trace: %s", debug.Stack()) SendErr(ctx, w, recoveryErrAsError) } diff --git a/mining/simulator/main.go b/mining/simulator/main.go index ccf79d932..3bb5923f1 100644 --- a/mining/simulator/main.go +++ b/mining/simulator/main.go @@ -10,7 +10,7 @@ import ( ) func main() { - defer panics.HandlePanic(log, backendLog) + defer panics.HandlePanic(log, backendLog, nil) cfg, err := parseConfig() if err != nil { fmt.Fprintf(os.Stderr, "Error parsing command-line arguments: %s", err) diff --git a/mining/simulator/mineloop.go b/mining/simulator/mineloop.go index 90438e4f9..2e415c0e6 100644 --- a/mining/simulator/mineloop.go +++ b/mining/simulator/mineloop.go @@ -2,6 +2,8 @@ package main import ( "encoding/hex" + nativeerrors "errors" + "github.com/daglabs/btcd/rpcclient" "github.com/pkg/errors" "math/rand" "strconv" @@ -10,7 +12,6 @@ import ( "github.com/daglabs/btcd/blockdag" "github.com/daglabs/btcd/btcjson" - "github.com/daglabs/btcd/rpcclient" "github.com/daglabs/btcd/util" "github.com/daglabs/btcd/util/daghash" "github.com/daglabs/btcd/wire" @@ -97,7 +98,7 @@ func templatesLoop(client *simulatorClient, newTemplateChan chan *btcjson.GetBlo log.Infof("Requesting template without longPollID from %s", client.Host()) } template, err := getBlockTemplate(client, longPollID) - if err == rpcclient.ErrResponseTimedOut { + if nativeerrors.Is(err, rpcclient.ErrResponseTimedOut) { log.Infof("Got timeout while requesting template '%s' from %s", longPollID, client.Host()) return } else if err != nil { diff --git a/rpcclient/infrastructure.go b/rpcclient/infrastructure.go index cf418c9ca..0a6fbc63b 100644 --- a/rpcclient/infrastructure.go +++ b/rpcclient/infrastructure.go @@ -11,6 +11,7 @@ import ( "crypto/x509" "encoding/base64" "encoding/json" + nativeerrors "errors" "fmt" "github.com/pkg/errors" "io" @@ -841,7 +842,7 @@ func (c *Client) sendRequest(data *jsonRequestData) chan *response { select { case <-c.connEstablished: default: - jReq.responseChan <- &response{err: ErrClientNotConnected} + jReq.responseChan <- &response{err: errors.WithStack(ErrClientNotConnected)} return } @@ -860,7 +861,7 @@ func (c *Client) sendRequest(data *jsonRequestData) chan *response { spawn(func() { select { case <-time.Tick(c.config.RequestTimeout): - responseChan <- &response{err: ErrResponseTimedOut} + responseChan <- &response{err: errors.WithStack(ErrResponseTimedOut)} case resp := <-jReq.responseChan: responseChan <- resp } @@ -1209,21 +1210,21 @@ func dial(config *ConnConfig) (*websocket.Conn, error) { url := fmt.Sprintf("%s://%s/%s", scheme, config.Host, config.Endpoint) wsConn, resp, err := dialer.Dial(url, requestHeader) if err != nil { - if err != websocket.ErrBadHandshake || resp == nil { + if !nativeerrors.Is(err, websocket.ErrBadHandshake) || resp == nil { return nil, err } // Detect HTTP authentication error status codes. if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden { - return nil, ErrInvalidAuth + return nil, errors.WithStack(ErrInvalidAuth) } // The connection was authenticated and the status response was // ok, but the websocket handshake still failed, so the endpoint // is invalid in some way. if resp.StatusCode == http.StatusOK { - return nil, ErrInvalidEndpoint + return nil, errors.WithStack(ErrInvalidEndpoint) } // Return the status text from the server if none of the special diff --git a/testutil/testutil.go b/testutil/testutil.go index f9e9ed1c4..b2d25f83f 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -1,6 +1,8 @@ package testutil -import "fmt" +import ( + "fmt" +) // AreErrorsEqual returns whether errors have the same type // and same error string from .Error(). diff --git a/util/panics/panics.go b/util/panics/panics.go index 1a09a5c4d..812d71345 100644 --- a/util/panics/panics.go +++ b/util/panics/panics.go @@ -7,9 +7,12 @@ import ( ) // HandlePanic recovers panics, log them, and then exits the process. -func HandlePanic(log logs.Logger, backendLog *logs.Backend) { +func HandlePanic(log logs.Logger, backendLog *logs.Backend, goroutineStackTrace []byte) { if err := recover(); err != nil { log.Criticalf("Fatal error: %+v", err) + if goroutineStackTrace != nil { + log.Criticalf("goroutine stack trance: %s", goroutineStackTrace) + } log.Criticalf("Stack trace: %s", debug.Stack()) if backendLog != nil { backendLog.Close() @@ -21,8 +24,9 @@ func HandlePanic(log logs.Logger, backendLog *logs.Backend) { // GoroutineWrapperFunc returns a goroutine wrapper function that handles panics and write them to the log. func GoroutineWrapperFunc(log logs.Logger, backendLog *logs.Backend) func(func()) { return func(f func()) { + stackTrace := debug.Stack() go func() { - defer HandlePanic(log, backendLog) + defer HandlePanic(log, backendLog, stackTrace) f() }() }