logger.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package logger
  2. import (
  3. "context"
  4. "fmt"
  5. "log/slog"
  6. "os"
  7. "sync"
  8. "git.dmitriygnatenko.ru/dima/go-common/smtp"
  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. AddSource: c.stdoutLogAddSource,
  30. Level: c.stdoutLogLevel,
  31. }))
  32. }
  33. if c.fileLogEnabled {
  34. logger.logFile, err = os.OpenFile(c.filepath, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644)
  35. if err != nil {
  36. return
  37. }
  38. logger.fileLogger = slog.New(slog.NewJSONHandler(logger.logFile, &slog.HandlerOptions{
  39. AddSource: c.fileLogAddSource,
  40. Level: c.fileLogLevel,
  41. }))
  42. }
  43. if c.emailLogEnabled {
  44. smtpClient, smtpErr := smtp.NewSMTP(
  45. smtp.NewConfig(
  46. smtp.WithHost(c.smtpHost),
  47. smtp.WithUsername(c.smtpUsername),
  48. smtp.WithPassword(c.smtpPassword),
  49. smtp.WithPort(c.smtpPort),
  50. ),
  51. )
  52. if smtpErr != nil {
  53. err = smtpErr
  54. return
  55. }
  56. ew, ewErr := NewEmailWriter(smtpClient, c.emailRecipient, c.emailSubject)
  57. if ewErr != nil {
  58. err = ewErr
  59. return
  60. }
  61. logger.emailLogger = slog.New(slog.NewJSONHandler(ew, &slog.HandlerOptions{
  62. AddSource: c.emailLogAddSource,
  63. Level: c.emailLogLevel,
  64. }))
  65. }
  66. })
  67. return err
  68. }
  69. func Default() *Logger {
  70. if logger == nil {
  71. panic("logger not initialised")
  72. }
  73. return logger
  74. }
  75. func ErrorKV(ctx context.Context, msg string, args ...any) {
  76. log(ctx, slog.LevelError, msg, args...)
  77. }
  78. func WarnKV(ctx context.Context, msg string, args ...any) {
  79. log(ctx, slog.LevelWarn, msg, args...)
  80. }
  81. func InfoKV(ctx context.Context, msg string, args ...any) {
  82. log(ctx, slog.LevelInfo, msg, args...)
  83. }
  84. func DebugKV(ctx context.Context, msg string, args ...any) {
  85. log(ctx, slog.LevelDebug, msg, args...)
  86. }
  87. func Errorf(ctx context.Context, format string, args ...any) {
  88. log(ctx, slog.LevelError, fmt.Sprintf(format, args...))
  89. }
  90. func Warnf(ctx context.Context, format string, args ...any) {
  91. log(ctx, slog.LevelWarn, fmt.Sprintf(format, args...))
  92. }
  93. func Infof(ctx context.Context, format string, args ...any) {
  94. log(ctx, slog.LevelInfo, fmt.Sprintf(format, args...))
  95. }
  96. func Debugf(ctx context.Context, format string, args ...any) {
  97. log(ctx, slog.LevelDebug, fmt.Sprintf(format, args...))
  98. }
  99. func Error(ctx context.Context, msg string) {
  100. log(ctx, slog.LevelError, msg)
  101. }
  102. func Warn(ctx context.Context, msg string) {
  103. log(ctx, slog.LevelWarn, msg)
  104. }
  105. func Info(ctx context.Context, msg string) {
  106. log(ctx, slog.LevelInfo, msg)
  107. }
  108. func Debug(ctx context.Context, msg string) {
  109. log(ctx, slog.LevelDebug, msg)
  110. }
  111. func log(ctx context.Context, level slog.Level, msg string, args ...any) {
  112. if Default().stdoutLogger != nil {
  113. Default().stdoutLogger.Log(ctx, level, msg, append(args, AttrFromCtx(ctx)...)...)
  114. }
  115. if Default().fileLogger != nil {
  116. Default().fileLogger.Log(ctx, level, msg, append(args, AttrFromCtx(ctx)...)...)
  117. }
  118. if Default().emailLogger != nil {
  119. Default().emailLogger.Log(ctx, level, msg, append(args, AttrFromCtx(ctx)...)...)
  120. }
  121. }
  122. func Close() error {
  123. if Default().logFile != nil {
  124. if err := Default().logFile.Close(); err != nil {
  125. return err
  126. }
  127. }
  128. return nil
  129. }