You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
4.6 KiB
Go
193 lines
4.6 KiB
Go
// Package logging provides structured logging for the KnowFoolery application.
|
|
package logging
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog"
|
|
)
|
|
|
|
// Config holds the configuration for the logger.
|
|
type Config struct {
|
|
Level string
|
|
Environment string
|
|
ServiceName string
|
|
Version string
|
|
Output io.Writer
|
|
}
|
|
|
|
// DefaultConfig returns a default configuration.
|
|
func DefaultConfig() Config {
|
|
return Config{
|
|
Level: "info",
|
|
Environment: "development",
|
|
ServiceName: "knowfoolery",
|
|
Version: "0.0.0",
|
|
Output: os.Stdout,
|
|
}
|
|
}
|
|
|
|
// Logger wraps zerolog.Logger with application-specific methods.
|
|
type Logger struct {
|
|
logger zerolog.Logger
|
|
}
|
|
|
|
// NewLogger creates a new Logger.
|
|
func NewLogger(config Config) *Logger {
|
|
// Parse log level
|
|
level, err := zerolog.ParseLevel(config.Level)
|
|
if err != nil {
|
|
level = zerolog.InfoLevel
|
|
}
|
|
|
|
// Set global level
|
|
zerolog.SetGlobalLevel(level)
|
|
zerolog.TimeFieldFormat = time.RFC3339Nano
|
|
|
|
var logger zerolog.Logger
|
|
output := config.Output
|
|
if output == nil {
|
|
output = os.Stdout
|
|
}
|
|
|
|
if config.Environment == "development" {
|
|
// Human-readable console output for development
|
|
logger = zerolog.New(zerolog.ConsoleWriter{
|
|
Out: output,
|
|
TimeFormat: "15:04:05",
|
|
}).With().Timestamp().Logger()
|
|
} else {
|
|
// JSON output for production
|
|
logger = zerolog.New(output).With().Timestamp().Logger()
|
|
}
|
|
|
|
// Add service metadata
|
|
logger = logger.With().
|
|
Str("service", config.ServiceName).
|
|
Str("version", config.Version).
|
|
Str("environment", config.Environment).
|
|
Logger()
|
|
|
|
return &Logger{logger: logger}
|
|
}
|
|
|
|
// Debug logs a debug message.
|
|
func (l *Logger) Debug(msg string) {
|
|
l.logger.Debug().Msg(msg)
|
|
}
|
|
|
|
// Info logs an info message.
|
|
func (l *Logger) Info(msg string) {
|
|
l.logger.Info().Msg(msg)
|
|
}
|
|
|
|
// Warn logs a warning message.
|
|
func (l *Logger) Warn(msg string) {
|
|
l.logger.Warn().Msg(msg)
|
|
}
|
|
|
|
// Error logs an error message.
|
|
func (l *Logger) Error(msg string) {
|
|
l.logger.Error().Msg(msg)
|
|
}
|
|
|
|
// Fatal logs a fatal message and exits.
|
|
func (l *Logger) Fatal(msg string) {
|
|
l.logger.Fatal().Msg(msg)
|
|
}
|
|
|
|
// WithError adds an error to the log entry.
|
|
func (l *Logger) WithError(err error) *Logger {
|
|
return &Logger{
|
|
logger: l.logger.With().Err(err).Logger(),
|
|
}
|
|
}
|
|
|
|
// WithField adds a field to the log entry.
|
|
func (l *Logger) WithField(key string, value interface{}) *Logger {
|
|
return &Logger{
|
|
logger: l.logger.With().Interface(key, value).Logger(),
|
|
}
|
|
}
|
|
|
|
// WithFields adds multiple fields to the log entry.
|
|
func (l *Logger) WithFields(fields map[string]interface{}) *Logger {
|
|
ctx := l.logger.With()
|
|
for k, v := range fields {
|
|
ctx = ctx.Interface(k, v)
|
|
}
|
|
return &Logger{
|
|
logger: ctx.Logger(),
|
|
}
|
|
}
|
|
|
|
// GameEvent logs a game-related event.
|
|
func (l *Logger) GameEvent(event string, gameSessionID, userID string, properties map[string]interface{}) {
|
|
l.logger.Info().
|
|
Str("event_type", "game").
|
|
Str("event", event).
|
|
Str("game_session_id", gameSessionID).
|
|
Str("user_id", userID).
|
|
Fields(properties).
|
|
Msg("Game event occurred")
|
|
}
|
|
|
|
// APIRequest logs an API request.
|
|
func (l *Logger) APIRequest(method, path string, statusCode int, duration time.Duration, userID string) {
|
|
l.logger.Info().
|
|
Str("event_type", "api_request").
|
|
Str("method", method).
|
|
Str("path", path).
|
|
Int("status_code", statusCode).
|
|
Dur("duration_ms", duration).
|
|
Str("user_id", userID).
|
|
Msg("API request processed")
|
|
}
|
|
|
|
// DatabaseOperation logs a database operation.
|
|
func (l *Logger) DatabaseOperation(operation, table string, duration time.Duration, rowsAffected int64) {
|
|
l.logger.Debug().
|
|
Str("event_type", "database").
|
|
Str("operation", operation).
|
|
Str("table", table).
|
|
Dur("duration_ms", duration).
|
|
Int64("rows_affected", rowsAffected).
|
|
Msg("Database operation completed")
|
|
}
|
|
|
|
// AuthenticationEvent logs an authentication event.
|
|
func (l *Logger) AuthenticationEvent(event, userID, userType string, success bool, details map[string]string) {
|
|
logEntry := l.logger.Info()
|
|
if !success {
|
|
logEntry = l.logger.Warn()
|
|
}
|
|
|
|
logEntry.
|
|
Str("event_type", "authentication").
|
|
Str("event", event).
|
|
Str("user_id", userID).
|
|
Str("user_type", userType).
|
|
Bool("success", success).
|
|
Fields(details).
|
|
Msg("Authentication event")
|
|
}
|
|
|
|
// SecurityEvent logs a security event.
|
|
func (l *Logger) SecurityEvent(event, userID, ipAddress string, severity string, details map[string]interface{}) {
|
|
l.logger.Warn().
|
|
Str("event_type", "security").
|
|
Str("event", event).
|
|
Str("user_id", userID).
|
|
Str("ip_address", ipAddress).
|
|
Str("severity", severity).
|
|
Fields(details).
|
|
Msg("Security event detected")
|
|
}
|
|
|
|
// Zerolog returns the underlying zerolog.Logger for advanced usage.
|
|
func (l *Logger) Zerolog() zerolog.Logger {
|
|
return l.logger
|
|
}
|