mirror of
https://github.com/status-im/status-go.git
synced 2025-01-28 23:47:02 +00:00
38308d48f2
* feat_: log error and stacktrace when panic in goroutine * test_: add test TestSafeGo * chore_: rename logAndCall to call * chore_: rename SafeGo to Go * chore_: make lint-fix * chore_: use t.Cleanup * chore_: Revert "chore_: use t.Cleanup" This reverts commit 4eb420d179cc0e208e84c13cb941e6b3d1ed9819. * chore_: Revert "chore_: make lint-fix" This reverts commit fcc995f157e671a4229b47419c3a0e4004b5fdab. * chore_: Revert "chore_: rename SafeGo to Go" This reverts commit a6d73d6df583f313032d79aac62f66328039cb55. * chore_: Revert "chore_: rename logAndCall to call" This reverts commit 8fbe993bedb9fbba67349a44f151e2dd5e3bc4cc. * chore_: Revert "test_: add test TestSafeGo" This reverts commit a1fa91839f3960398980c6bf456e6462ec944819. * chore_: Revert "feat_: log error and stacktrace when panic in goroutine" This reverts commit f612dd828fa2ce410d0e806fe773ecbe3e86a68a. * feat_: log error and stacktrace when panic in goroutine * chore_: make lint-fix * chore_: rename logAndCall to call * chore_: renaming LogOnPanic * chore_: update rest goroutine function calls * chore_: make lint-fix
103 lines
2.9 KiB
Go
103 lines
2.9 KiB
Go
package statusgo
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"regexp"
|
|
"runtime"
|
|
"runtime/debug"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/status-im/status-go/logutils/requestlog"
|
|
)
|
|
|
|
var sensitiveRegex = regexp.MustCompile(`(?i)(".*?(password|mnemonic|openseaAPIKey|poktToken|alchemyArbitrumMainnetToken|raribleTestnetAPIKey|alchemyOptimismMainnetToken|statusProxyBlockchainUser|alchemyEthereumSepoliaToken|alchemyArbitrumSepoliaToken|infuraToken|raribleMainnetAPIKey|alchemyEthereumMainnetToken).*?")\s*:\s*("[^"]*")`)
|
|
|
|
func getFunctionName(fn any) string {
|
|
return runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
|
|
}
|
|
|
|
func getShortFunctionName(fn any) string {
|
|
fullName := getFunctionName(fn)
|
|
parts := strings.Split(fullName, ".")
|
|
return parts[len(parts)-1]
|
|
}
|
|
|
|
// call executes the given function and logs request details if logging is enabled
|
|
//
|
|
// Parameters:
|
|
// - fn: The function to be executed
|
|
// - params: A variadic list of parameters to be passed to the function
|
|
//
|
|
// Returns:
|
|
// - The result of the function execution (if any)
|
|
//
|
|
// Functionality:
|
|
// 1. Sets up panic recovery to log and re-panic
|
|
// 2. Records start time if request logging is enabled
|
|
// 3. Uses reflection to call the given function
|
|
// 4. If request logging is enabled, logs method name, parameters, response, and execution duration
|
|
// 5. Removes sensitive information before logging
|
|
func call(fn any, params ...any) any {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
// we're not sure if request logging is enabled here, so we log it use default logger
|
|
log.Error("panic found in call", "error", r, "stacktrace", string(debug.Stack()))
|
|
panic(r)
|
|
}
|
|
}()
|
|
|
|
var startTime time.Time
|
|
|
|
if requestlog.IsRequestLoggingEnabled() {
|
|
startTime = time.Now()
|
|
}
|
|
|
|
fnValue := reflect.ValueOf(fn)
|
|
fnType := fnValue.Type()
|
|
if fnType.Kind() != reflect.Func {
|
|
panic("fn must be a function")
|
|
}
|
|
|
|
args := make([]reflect.Value, len(params))
|
|
for i, param := range params {
|
|
args[i] = reflect.ValueOf(param)
|
|
}
|
|
|
|
results := fnValue.Call(args)
|
|
|
|
var resp any
|
|
|
|
if len(results) > 0 {
|
|
resp = results[0].Interface()
|
|
}
|
|
|
|
if requestlog.IsRequestLoggingEnabled() {
|
|
duration := time.Since(startTime)
|
|
methodName := getShortFunctionName(fn)
|
|
paramsString := removeSensitiveInfo(fmt.Sprintf("%+v", params))
|
|
respString := removeSensitiveInfo(fmt.Sprintf("%+v", resp))
|
|
requestlog.GetRequestLogger().Debug(methodName, "params", paramsString, "resp", respString, "duration", duration)
|
|
}
|
|
|
|
return resp
|
|
}
|
|
|
|
func callWithResponse(fn any, params ...any) string {
|
|
resp := call(fn, params...)
|
|
if resp == nil {
|
|
return ""
|
|
}
|
|
return resp.(string)
|
|
}
|
|
|
|
func removeSensitiveInfo(jsonStr string) string {
|
|
// see related test for the usage of this function
|
|
return sensitiveRegex.ReplaceAllStringFunc(jsonStr, func(match string) string {
|
|
parts := sensitiveRegex.FindStringSubmatch(match)
|
|
return fmt.Sprintf(`%s:"***"`, parts[1])
|
|
})
|
|
}
|