Add structured logging and centralized error handling
- Initialize slog in the serve command with terminal/file support - Introduce `AppError` with HTTP status for unified service-layer errors - Replace ad-hoc `api.Error` calls with `api.RespondError` - Wrap internal errors with `model.NewInternalError` and add reference IDs - Add `RequestID` middleware and switch router from `gin.Default` to `gin.New`
This commit is contained in:
@@ -3,6 +3,7 @@ package config
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
@@ -12,6 +13,7 @@ type Config struct {
|
||||
Database DatabaseConfig `mapstructure:"database"`
|
||||
Storage StorageConfig `mapstructure:"storage"`
|
||||
JWT JWTConfig `mapstructure:"jwt"`
|
||||
Log LogConfig `mapstructure:"log"`
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
@@ -54,6 +56,30 @@ type JWTConfig struct {
|
||||
RefreshTTL time.Duration `mapstructure:"refresh_ttl"`
|
||||
}
|
||||
|
||||
type LogConfig struct {
|
||||
Level string `mapstructure:"level"`
|
||||
FilePath string `mapstructure:"file_path"`
|
||||
FileLevel string `mapstructure:"file_level"`
|
||||
}
|
||||
|
||||
// ParseLogLevel converts a string to slog.Level.
|
||||
func ParseLogLevel(s string) (slog.Level, error) {
|
||||
if s == "" {
|
||||
return slog.LevelInfo, nil
|
||||
}
|
||||
switch s {
|
||||
case "debug":
|
||||
return slog.LevelDebug, nil
|
||||
case "info":
|
||||
return slog.LevelInfo, nil
|
||||
case "warn":
|
||||
return slog.LevelWarn, nil
|
||||
case "error":
|
||||
return slog.LevelError, nil
|
||||
default:
|
||||
return slog.LevelInfo, fmt.Errorf("unknown log level: %q (use debug, info, warn, or error)", s)
|
||||
}
|
||||
}
|
||||
func (c *Config) Validate() error {
|
||||
var errs []error
|
||||
|
||||
@@ -107,5 +133,17 @@ func (c *Config) Validate() error {
|
||||
errs = append(errs, errors.New("jwt.refresh_ttl: must be positive"))
|
||||
}
|
||||
|
||||
if c.Log.Level != "" {
|
||||
if _, err := ParseLogLevel(c.Log.Level); err != nil {
|
||||
errs = append(errs, fmt.Errorf("log.level: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
if c.Log.FileLevel != "" {
|
||||
if _, err := ParseLogLevel(c.Log.FileLevel); err != nil {
|
||||
errs = append(errs, fmt.Errorf("log.file_level: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user