mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-10-01 19:20:31 +00:00
fix(race): make make test-race pass across ./pkg/...
Add a test-race target and run test-unit over ./pkg/... Production races: - logger: guard Logger/errorTracker with an RWMutex - security: copy UserContext for the async session-activity goroutine and track it with a WaitGroup Test fixes: - eventbroker, websocketspec: use atomics for state shared with workers - security: wait for async activity updates before touching sqlmock - mqttspec: build full HookContext, set SubscriptionID, pin the in-memory SQLite to one connection Update the cross-cutting audit (X1) with status and findings.
This commit is contained in:
+59
-23
@@ -6,15 +6,40 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
errortracking "github.com/bitechdev/ResolveSpec/pkg/errortracking"
|
||||
)
|
||||
|
||||
// Logger is the active logger. It is kept exported for compatibility, but
|
||||
// inside this package it must only be accessed through getLogger/setLogger.
|
||||
var Logger *zap.SugaredLogger
|
||||
var errorTracker errortracking.Provider
|
||||
|
||||
// stateMu guards Logger and errorTracker, which may be replaced while other
|
||||
// goroutines are logging.
|
||||
var stateMu sync.RWMutex
|
||||
|
||||
func getLogger() *zap.SugaredLogger {
|
||||
stateMu.RLock()
|
||||
defer stateMu.RUnlock()
|
||||
return Logger
|
||||
}
|
||||
|
||||
func setLogger(l *zap.SugaredLogger) {
|
||||
stateMu.Lock()
|
||||
defer stateMu.Unlock()
|
||||
Logger = l
|
||||
}
|
||||
|
||||
func getErrorTracker() errortracking.Provider {
|
||||
stateMu.RLock()
|
||||
defer stateMu.RUnlock()
|
||||
return errorTracker
|
||||
}
|
||||
|
||||
func Init(dev bool) {
|
||||
|
||||
if dev {
|
||||
@@ -49,28 +74,30 @@ func UpdateLogger(config *zap.Config) {
|
||||
return
|
||||
}
|
||||
|
||||
Logger = logger.Sugar()
|
||||
setLogger(logger.Sugar())
|
||||
Info("ResolveSpec Logger initialized")
|
||||
}
|
||||
|
||||
// InitErrorTracking initializes the error tracking provider
|
||||
func InitErrorTracking(provider errortracking.Provider) {
|
||||
stateMu.Lock()
|
||||
errorTracker = provider
|
||||
if errorTracker != nil {
|
||||
stateMu.Unlock()
|
||||
if provider != nil {
|
||||
Info("Error tracking initialized")
|
||||
}
|
||||
}
|
||||
|
||||
// GetErrorTracker returns the current error tracking provider
|
||||
func GetErrorTracker() errortracking.Provider {
|
||||
return errorTracker
|
||||
return getErrorTracker()
|
||||
}
|
||||
|
||||
// CloseErrorTracking flushes and closes the error tracking provider
|
||||
func CloseErrorTracking() error {
|
||||
if errorTracker != nil {
|
||||
errorTracker.Flush(5)
|
||||
return errorTracker.Close()
|
||||
if tracker := getErrorTracker(); tracker != nil {
|
||||
tracker.Flush(5)
|
||||
return tracker.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -98,53 +125,59 @@ func extractContext(args ...interface{}) (ctx context.Context, filteredArgs []in
|
||||
}
|
||||
|
||||
func Info(template string, args ...interface{}) {
|
||||
if Logger == nil {
|
||||
lg := getLogger()
|
||||
if lg == nil {
|
||||
log.Printf(template, args...)
|
||||
return
|
||||
}
|
||||
Logger.Infow(fmt.Sprintf(template, args...), "process_id", os.Getpid())
|
||||
lg.Infow(fmt.Sprintf(template, args...), "process_id", os.Getpid())
|
||||
}
|
||||
|
||||
func Warn(template string, args ...interface{}) {
|
||||
lg := getLogger()
|
||||
tracker := getErrorTracker()
|
||||
ctx, remainingArgs := extractContext(args...)
|
||||
message := fmt.Sprintf(template, remainingArgs...)
|
||||
if Logger == nil {
|
||||
if lg == nil {
|
||||
log.Printf("%s", message)
|
||||
} else {
|
||||
Logger.Warnw(message, "process_id", os.Getpid())
|
||||
lg.Warnw(message, "process_id", os.Getpid())
|
||||
}
|
||||
|
||||
// Send to error tracker
|
||||
if errorTracker != nil {
|
||||
errorTracker.CaptureMessage(ctx, message, errortracking.SeverityWarning, map[string]interface{}{
|
||||
if tracker != nil {
|
||||
tracker.CaptureMessage(ctx, message, errortracking.SeverityWarning, map[string]interface{}{
|
||||
"process_id": os.Getpid(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Error(template string, args ...interface{}) {
|
||||
lg := getLogger()
|
||||
tracker := getErrorTracker()
|
||||
ctx, remainingArgs := extractContext(args...)
|
||||
message := fmt.Sprintf(template, remainingArgs...)
|
||||
if Logger == nil {
|
||||
if lg == nil {
|
||||
log.Printf("%s", message)
|
||||
} else {
|
||||
Logger.Errorw(message, "process_id", os.Getpid())
|
||||
lg.Errorw(message, "process_id", os.Getpid())
|
||||
}
|
||||
|
||||
// Send to error tracker
|
||||
if errorTracker != nil {
|
||||
errorTracker.CaptureMessage(ctx, message, errortracking.SeverityError, map[string]interface{}{
|
||||
if tracker != nil {
|
||||
tracker.CaptureMessage(ctx, message, errortracking.SeverityError, map[string]interface{}{
|
||||
"process_id": os.Getpid(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Debug(template string, args ...interface{}) {
|
||||
if Logger == nil {
|
||||
lg := getLogger()
|
||||
if lg == nil {
|
||||
log.Printf(template, args...)
|
||||
return
|
||||
}
|
||||
Logger.Debugw(fmt.Sprintf(template, args...), "process_id", os.Getpid())
|
||||
lg.Debugw(fmt.Sprintf(template, args...), "process_id", os.Getpid())
|
||||
}
|
||||
|
||||
// CatchPanic - Handle panic
|
||||
@@ -155,8 +188,10 @@ func CatchPanicCallback(location string, cb func(err any), args ...interface{})
|
||||
return func() {
|
||||
if err := recover(); err != nil {
|
||||
callstack := debug.Stack()
|
||||
lg := getLogger()
|
||||
tracker := getErrorTracker()
|
||||
|
||||
if Logger != nil {
|
||||
if lg != nil {
|
||||
Error("Panic in %s : %v", location, err, ctx) // Pass context implicitly
|
||||
} else {
|
||||
fmt.Printf("%s:PANIC->%+v", location, err)
|
||||
@@ -164,8 +199,8 @@ func CatchPanicCallback(location string, cb func(err any), args ...interface{})
|
||||
}
|
||||
|
||||
// Send to error tracker
|
||||
if errorTracker != nil {
|
||||
errorTracker.CapturePanic(ctx, err, callstack, map[string]interface{}{
|
||||
if tracker != nil {
|
||||
tracker.CapturePanic(ctx, err, callstack, map[string]interface{}{
|
||||
"location": location,
|
||||
"process_id": os.Getpid(),
|
||||
})
|
||||
@@ -195,13 +230,14 @@ func CatchPanic(location string, args ...interface{}) func() {
|
||||
// }
|
||||
// }()
|
||||
func HandlePanic(methodName string, r any, args ...interface{}) error {
|
||||
tracker := getErrorTracker()
|
||||
ctx, _ := extractContext(args...)
|
||||
stack := debug.Stack()
|
||||
Error("Panic in %s: %v\nStack trace:\n%s", methodName, r, string(stack), ctx) // Pass context implicitly
|
||||
|
||||
// Send to error tracker
|
||||
if errorTracker != nil {
|
||||
errorTracker.CapturePanic(ctx, r, stack, map[string]interface{}{
|
||||
if tracker != nil {
|
||||
tracker.CapturePanic(ctx, r, stack, map[string]interface{}{
|
||||
"method": methodName,
|
||||
"process_id": os.Getpid(),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user