github.com/status-im/status-go@v1.1.0/mobile/status_request_log.go (about)

     1  package statusgo
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"regexp"
     7  	"runtime"
     8  	"runtime/debug"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/ethereum/go-ethereum/log"
    13  	"github.com/status-im/status-go/logutils/requestlog"
    14  )
    15  
    16  var sensitiveRegex = regexp.MustCompile(`(?i)(".*?(password|mnemonic|openseaAPIKey|poktToken|alchemyArbitrumMainnetToken|raribleTestnetAPIKey|alchemyOptimismMainnetToken|statusProxyBlockchainUser|alchemyEthereumSepoliaToken|alchemyArbitrumSepoliaToken|infuraToken|raribleMainnetAPIKey|alchemyEthereumMainnetToken).*?")\s*:\s*("[^"]*")`)
    17  
    18  func getFunctionName(fn any) string {
    19  	return runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
    20  }
    21  
    22  func getShortFunctionName(fn any) string {
    23  	fullName := getFunctionName(fn)
    24  	parts := strings.Split(fullName, ".")
    25  	return parts[len(parts)-1]
    26  }
    27  
    28  // logAndCall logs request call details and executes the fn function if logging is enabled
    29  func logAndCall(fn any, params ...any) any {
    30  	defer func() {
    31  		if r := recover(); r != nil {
    32  			// we're not sure if request logging is enabled here, so we log it use default logger
    33  			log.Error("panic found in logAndCall", "error", r, "stacktrace", string(debug.Stack()))
    34  			panic(r)
    35  		}
    36  	}()
    37  
    38  	var startTime time.Time
    39  
    40  	if requestlog.IsRequestLoggingEnabled() {
    41  		startTime = time.Now()
    42  	}
    43  
    44  	fnValue := reflect.ValueOf(fn)
    45  	fnType := fnValue.Type()
    46  	if fnType.Kind() != reflect.Func {
    47  		panic("fn must be a function")
    48  	}
    49  
    50  	args := make([]reflect.Value, len(params))
    51  	for i, param := range params {
    52  		args[i] = reflect.ValueOf(param)
    53  	}
    54  
    55  	results := fnValue.Call(args)
    56  
    57  	var resp any
    58  
    59  	if len(results) > 0 {
    60  		resp = results[0].Interface()
    61  	}
    62  
    63  	if requestlog.IsRequestLoggingEnabled() {
    64  		duration := time.Since(startTime)
    65  		methodName := getShortFunctionName(fn)
    66  		paramsString := removeSensitiveInfo(fmt.Sprintf("%+v", params))
    67  		respString := removeSensitiveInfo(fmt.Sprintf("%+v", resp))
    68  		requestlog.GetRequestLogger().Debug(methodName, "params", paramsString, "resp", respString, "duration", duration)
    69  	}
    70  
    71  	return resp
    72  }
    73  
    74  func logAndCallString(fn any, params ...any) string {
    75  	resp := logAndCall(fn, params...)
    76  	if resp == nil {
    77  		return ""
    78  	}
    79  	return resp.(string)
    80  }
    81  
    82  func removeSensitiveInfo(jsonStr string) string {
    83  	// see related test for the usage of this function
    84  	return sensitiveRegex.ReplaceAllStringFunc(jsonStr, func(match string) string {
    85  		parts := sensitiveRegex.FindStringSubmatch(match)
    86  		return fmt.Sprintf(`%s:"***"`, parts[1])
    87  	})
    88  }