logger.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package logger
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "log/slog"
  7. "os"
  8. "sync"
  9. )
  10. type CtxAttrKey struct{}
  11. var (
  12. once sync.Once
  13. ctxAttrMu sync.RWMutex
  14. logger *Logger
  15. )
  16. type Logger struct {
  17. config Config
  18. logFile *os.File
  19. stdoutLogger *slog.Logger
  20. fileLogger *slog.Logger
  21. emailLogger *slog.Logger
  22. }
  23. func Init(c Config) error {
  24. var err error
  25. once.Do(func() {
  26. logger = &Logger{config: c}
  27. if c.stdoutLogEnabled {
  28. logger.stdoutLogger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
  29. Level: c.stdoutLogLevel,
  30. }))
  31. }
  32. if c.fileLogEnabled {
  33. logger.logFile, err = os.OpenFile(c.filepath, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644)
  34. if err != nil {
  35. return
  36. }
  37. logger.fileLogger = slog.New(slog.NewJSONHandler(logger.logFile, &slog.HandlerOptions{
  38. Level: c.fileLogLevel,
  39. }))
  40. }
  41. if c.emailLogEnabled {
  42. if c.smtpClient == nil {
  43. err = errors.New("empty SMTP client")
  44. return
  45. }
  46. ew, ewErr := NewEmailWriter(c.smtpClient, c.emailRecipient, c.emailSubject)
  47. if ewErr != nil {
  48. err = ewErr
  49. return
  50. }
  51. logger.emailLogger = slog.New(slog.NewJSONHandler(ew, &slog.HandlerOptions{
  52. Level: c.emailLogLevel,
  53. }))
  54. }
  55. })
  56. return err
  57. }
  58. func Default() *Logger {
  59. if logger == nil {
  60. logger = &Logger{}
  61. }
  62. return logger
  63. }
  64. func ErrorKV(ctx context.Context, msg string, args ...any) {
  65. log(ctx, slog.LevelError, msg, args...)
  66. }
  67. func WarnKV(ctx context.Context, msg string, args ...any) {
  68. log(ctx, slog.LevelWarn, msg, args...)
  69. }
  70. func InfoKV(ctx context.Context, msg string, args ...any) {
  71. log(ctx, slog.LevelInfo, msg, args...)
  72. }
  73. func DebugKV(ctx context.Context, msg string, args ...any) {
  74. log(ctx, slog.LevelDebug, msg, args...)
  75. }
  76. func Errorf(ctx context.Context, format string, args ...any) {
  77. log(ctx, slog.LevelError, fmt.Sprintf(format, args...))
  78. }
  79. func Warnf(ctx context.Context, format string, args ...any) {
  80. log(ctx, slog.LevelWarn, fmt.Sprintf(format, args...))
  81. }
  82. func Infof(ctx context.Context, format string, args ...any) {
  83. log(ctx, slog.LevelInfo, fmt.Sprintf(format, args...))
  84. }
  85. func Debugf(ctx context.Context, format string, args ...any) {
  86. log(ctx, slog.LevelDebug, fmt.Sprintf(format, args...))
  87. }
  88. func Error(ctx context.Context, msg string) {
  89. log(ctx, slog.LevelError, msg)
  90. }
  91. func Warn(ctx context.Context, msg string) {
  92. log(ctx, slog.LevelWarn, msg)
  93. }
  94. func Info(ctx context.Context, msg string) {
  95. log(ctx, slog.LevelInfo, msg)
  96. }
  97. func Debug(ctx context.Context, msg string) {
  98. log(ctx, slog.LevelDebug, msg)
  99. }
  100. func log(ctx context.Context, level slog.Level, msg string, args ...any) {
  101. if Default().stdoutLogger != nil {
  102. Default().stdoutLogger.Log(ctx, level, msg, append(args, AttrFromCtx(ctx)...)...)
  103. }
  104. if Default().fileLogger != nil {
  105. Default().fileLogger.Log(ctx, level, msg, append(args, AttrFromCtx(ctx)...)...)
  106. }
  107. if Default().emailLogger != nil {
  108. Default().emailLogger.Log(ctx, level, msg, append(args, AttrFromCtx(ctx)...)...)
  109. }
  110. }
  111. func Close() error {
  112. if Default().logFile != nil {
  113. if err := Default().logFile.Close(); err != nil {
  114. return err
  115. }
  116. }
  117. return nil
  118. }