chore_: use zap logger as request logger

iterates: status-im/status-desktop#16536
This commit is contained in:
Patryk Osmaczko 2024-10-24 23:46:23 +02:00 committed by osmaczko
parent 153c5dbdf4
commit 2c1b321e58
4 changed files with 69 additions and 47 deletions

View File

@ -1,6 +1,7 @@
package logutils
import (
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
"github.com/ethereum/go-ethereum/log"
@ -28,3 +29,13 @@ func FileHandlerWithRotation(opts FileOptions, format log.Format) log.Handler {
}
return log.StreamHandler(logger, format)
}
// ZapSyncerWithRotation creates a zapcore.WriteSyncer with a configured rotation
func ZapSyncerWithRotation(opts FileOptions) zapcore.WriteSyncer {
return zapcore.AddSync(&lumberjack.Logger{
Filename: opts.Filename,
MaxSize: opts.MaxSize,
MaxBackups: opts.MaxBackups,
Compress: opts.Compress,
})
}

View File

@ -2,58 +2,49 @@ package requestlog
import (
"errors"
"sync/atomic"
"github.com/ethereum/go-ethereum/log"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/status-im/status-go/logutils"
"github.com/status-im/status-go/protocol/zaputil"
)
var (
// requestLogger is the request logger object
requestLogger log.Logger
// isRequestLoggingEnabled controls whether request logging is enabled
isRequestLoggingEnabled atomic.Bool
requestLogger *zap.Logger
)
// NewRequestLogger creates a new request logger object
func NewRequestLogger(ctx ...interface{}) log.Logger {
requestLogger = log.New(ctx...)
return requestLogger
}
// EnableRequestLogging enables or disables RPC logging
func EnableRequestLogging(enable bool) {
if enable {
isRequestLoggingEnabled.Store(true)
} else {
isRequestLoggingEnabled.Store(false)
}
}
// IsRequestLoggingEnabled returns whether RPC logging is enabled
func IsRequestLoggingEnabled() bool {
return isRequestLoggingEnabled.Load()
return requestLogger != nil
}
// GetRequestLogger returns the RPC logger object
func GetRequestLogger() log.Logger {
func GetRequestLogger() *zap.Logger {
return requestLogger
}
func ConfigureAndEnableRequestLogging(file string) error {
log.Info("initialising request logger", "log file", file)
requestLogger := NewRequestLogger()
if file == "" {
return errors.New("log file path is required")
if len(file) == 0 {
return errors.New("file is required")
}
if IsRequestLoggingEnabled() {
return errors.New("request logging is already enabled")
}
fileOpts := logutils.FileOptions{
Filename: file,
MaxBackups: 1,
}
handler := logutils.FileHandlerWithRotation(fileOpts, log.LogfmtFormat())
filteredHandler := log.LvlFilterHandler(log.LvlDebug, handler)
requestLogger.SetHandler(filteredHandler)
EnableRequestLogging(true)
core := zapcore.NewCore(
zaputil.NewConsoleHexEncoder(zap.NewDevelopmentEncoderConfig()),
zapcore.AddSync(logutils.ZapSyncerWithRotation(fileOpts)),
zap.DebugLevel,
)
requestLogger = zap.New(core).Named("RequestLogger")
return nil
}

View File

@ -65,7 +65,6 @@ func getShortFunctionName(fn any) string {
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
logutils.ZapLogger().Error("panic found in call", zap.Any("error", r), zap.Stack("stacktrace"))
panic(r)
}
@ -73,7 +72,8 @@ func call(fn any, params ...any) any {
var startTime time.Time
if requestlog.IsRequestLoggingEnabled() {
requestLoggingEnabled := requestlog.IsRequestLoggingEnabled()
if requestLoggingEnabled {
startTime = time.Now()
}
@ -96,12 +96,18 @@ func call(fn any, params ...any) any {
resp = results[0].Interface()
}
if requestlog.IsRequestLoggingEnabled() {
if requestLoggingEnabled {
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)
requestlog.GetRequestLogger().Debug("call",
zap.String("method", methodName),
zap.String("params", paramsString),
zap.String("resp", respString),
zap.Duration("duration", duration),
)
}
return resp

View File

@ -3,17 +3,18 @@ package statusgo
import (
"encoding/json"
"fmt"
"os"
"strings"
"testing"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
"github.com/status-im/status-go/logutils/requestlog"
"github.com/status-im/status-go/multiaccounts"
"github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/signal"
"github.com/ethereum/go-ethereum/log"
)
func TestRemoveSensitiveInfo(t *testing.T) {
@ -60,17 +61,17 @@ func TestRemoveSensitiveInfo(t *testing.T) {
}
func TestCall(t *testing.T) {
// Enable request logging
requestlog.EnableRequestLogging(true)
// Create a temporary file for logging
tempLogFile, err := os.CreateTemp(t.TempDir(), "TestCall*.log")
require.NoError(t, err)
// Create a mock logger to capture log output
var logOutput string
mockLogger := log.New()
mockLogger.SetHandler(log.FuncHandler(func(r *log.Record) error {
logOutput += r.Msg + fmt.Sprintf("%s", r.Ctx...)
return nil
}))
requestlog.NewRequestLogger().SetHandler(mockLogger.GetHandler())
// Enable request logging
err = requestlog.ConfigureAndEnableRequestLogging(tempLogFile.Name())
require.NoError(t, err)
// Logger must not be nil after enabling
logger := requestlog.GetRequestLogger()
require.NotNil(t, logger)
// Test case 1: Normal execution
testFunc := func(param string) string {
@ -86,6 +87,11 @@ func TestCall(t *testing.T) {
t.Errorf("Expected result %s, got %s", expectedResult, result)
}
// Read the log file
logData, err := os.ReadFile(tempLogFile.Name())
require.NoError(t, err)
logOutput := string(logData)
// Check if the log contains expected information
expectedLogParts := []string{getShortFunctionName(testFunc), "params", testParam, "resp", expectedResult}
for _, part := range expectedLogParts {
@ -94,12 +100,20 @@ func TestCall(t *testing.T) {
}
}
// Create a mock logger to capture log output
mockLogger := log.New()
mockLogger.SetHandler(log.FuncHandler(func(r *log.Record) error {
logOutput += r.Msg + fmt.Sprintf("%s", r.Ctx...)
return nil
}))
// Test case 2: Panic -> recovery -> re-panic
oldRootHandler := log.Root().GetHandler()
defer log.Root().SetHandler(oldRootHandler)
log.Root().SetHandler(mockLogger.GetHandler())
// Clear log output for next test
logOutput = ""
e := "test panic"
panicFunc := func() {
panic(e)