package monitoring import ( "encoding/json" "sync/atomic" "time" "github.com/google/uuid" ) // RedisLogWriter implements io.Writer to capture zerolog output to Redis type RedisLogWriter struct { buffer *LogBuffer process string enabled atomic.Bool } // NewRedisLogWriter creates a new writer that captures logs to Redis func NewRedisLogWriter(buffer *LogBuffer, process string) *RedisLogWriter { w := &RedisLogWriter{ buffer: buffer, process: process, } w.enabled.Store(true) // enabled by default return w } // SetEnabled enables or disables log capture to Redis func (w *RedisLogWriter) SetEnabled(enabled bool) { w.enabled.Store(enabled) } // IsEnabled returns whether log capture is enabled func (w *RedisLogWriter) IsEnabled() bool { return w.enabled.Load() } // Write implements io.Writer interface // It parses zerolog JSON output and writes to Redis asynchronously func (w *RedisLogWriter) Write(p []byte) (n int, err error) { // Skip if monitoring is disabled if !w.enabled.Load() { return len(p), nil } // Parse zerolog JSON output var raw map[string]any if err := json.Unmarshal(p, &raw); err != nil { // Not valid JSON, skip (could be console writer output) return len(p), nil } // Build log entry entry := LogEntry{ ID: uuid.NewString(), Timestamp: time.Now().UTC(), Process: w.process, Fields: make(map[string]any), } // Extract standard zerolog fields if lvl, ok := raw["level"].(string); ok { entry.Level = lvl } if msg, ok := raw["message"].(string); ok { entry.Message = msg } if caller, ok := raw["caller"].(string); ok { entry.Caller = caller } // Extract timestamp if present (zerolog may include it) if ts, ok := raw["time"].(string); ok { if parsed, err := time.Parse(time.RFC3339, ts); err == nil { entry.Timestamp = parsed } } // Copy additional fields (excluding standard ones) for k, v := range raw { switch k { case "level", "message", "caller", "time": // Skip standard fields default: entry.Fields[k] = v } } // Write to Redis asynchronously to avoid blocking go func() { _ = w.buffer.Push(entry) // Ignore errors to avoid blocking log output }() return len(p), nil }