Browse Source

Merge branch 'logger' of git.dmitriygnatenko.ru:dima/go-common

# Conflicts:
#	logger/logger.go
#	logger/logger_config.go
Dima 6 months ago
parent
commit
866935f3fc
6 changed files with 272 additions and 22 deletions
  1. 9 0
      db/db_config.go
  2. 8 0
      logger/email_writer.go
  3. 138 3
      logger/logger.go
  4. 58 19
      logger/logger_config.go
  5. 28 0
      logger/logger_ctx.go
  6. 31 0
      main.go

+ 9 - 0
db/db_config.go

@@ -36,6 +36,15 @@ func (s *ConfigOptions) Add(option ConfigOption) {
 	*s = append(*s, option)
 }
 
+func NewConfig(opts ...ConfigOption) Config {
+	c := &Config{}
+	for _, opt := range opts {
+		opt(c)
+	}
+
+	return *c
+}
+
 func WithDriver(driver string) ConfigOption {
 	return func(s *Config) {
 		s.driver = driver

+ 8 - 0
logger/email_writer.go

@@ -0,0 +1,8 @@
+package logger
+
+type EmailWriter struct {
+}
+
+func (w EmailWriter) Write(p []byte) (n int, err error) {
+	return 0, err
+}

+ 138 - 3
logger/logger.go

@@ -1,10 +1,145 @@
 package logger
 
 import (
+	"context"
+	"fmt"
 	"log/slog"
+	"os"
+	"sync"
 )
 
-func NewLogger(c Config) *slog.Logger {
-	handler := NewHandler(c)
-	return slog.New(&handler)
+type CtxAttrKey struct{}
+
+var (
+	once      sync.Once
+	ctxAttrMu sync.RWMutex
+	logger    *Logger
+)
+
+type Logger struct {
+	config  Config
+	logFile *os.File
+
+	stdoutLogger *slog.Logger
+	fileLogger   *slog.Logger
+	emailLogger  *slog.Logger
+}
+
+func Init(c Config) error {
+	var err error
+
+	once.Do(func() {
+		logger = &Logger{config: c}
+
+		if c.stdoutLogEnabled {
+			logger.stdoutLogger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
+				AddSource: c.stdoutLogAddSource,
+				Level:     c.stdoutLogLevel,
+			}))
+		}
+
+		if c.fileLogEnabled {
+			logger.logFile, err = os.OpenFile(c.fileLogFilepath, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644)
+			if err != nil {
+				return
+			}
+
+			logger.fileLogger = slog.New(slog.NewJSONHandler(logger.logFile, &slog.HandlerOptions{
+				AddSource: c.fileLogAddSource,
+				Level:     c.fileLogLevel,
+			}))
+		}
+
+		if c.emailLogEnabled {
+
+			ew := EmailWriter{}
+
+			logger.emailLogger = slog.New(slog.NewJSONHandler(ew, &slog.HandlerOptions{
+				AddSource: c.emailLogAddSource,
+				Level:     c.emailLogLevel,
+			}))
+		}
+	})
+
+	return err
+}
+
+func Default() *Logger {
+	if logger == nil {
+		panic("logger not initialised")
+	}
+
+	return logger
+}
+
+func ErrorKV(ctx context.Context, msg string, args ...any) {
+	log(ctx, slog.LevelError, msg, args...)
+}
+
+func WarnKV(ctx context.Context, msg string, args ...any) {
+	log(ctx, slog.LevelWarn, msg, args...)
+}
+
+func InfoKV(ctx context.Context, msg string, args ...any) {
+	log(ctx, slog.LevelInfo, msg, args...)
+}
+
+func DebugKV(ctx context.Context, msg string, args ...any) {
+	log(ctx, slog.LevelDebug, msg, args...)
+}
+
+func Errorf(ctx context.Context, format string, args ...any) {
+	log(ctx, slog.LevelError, fmt.Sprintf(format, args...))
+}
+
+func Warnf(ctx context.Context, format string, args ...any) {
+	log(ctx, slog.LevelWarn, fmt.Sprintf(format, args...))
+}
+
+func Infof(ctx context.Context, format string, args ...any) {
+	log(ctx, slog.LevelInfo, fmt.Sprintf(format, args...))
+}
+
+func Debugf(ctx context.Context, format string, args ...any) {
+	log(ctx, slog.LevelDebug, fmt.Sprintf(format, args...))
+}
+
+func Error(ctx context.Context, msg string) {
+	log(ctx, slog.LevelError, msg)
+}
+
+func Warn(ctx context.Context, msg string) {
+	log(ctx, slog.LevelWarn, msg)
+}
+
+func Info(ctx context.Context, msg string) {
+	log(ctx, slog.LevelInfo, msg)
+}
+
+func Debug(ctx context.Context, msg string) {
+	log(ctx, slog.LevelDebug, msg)
+}
+
+func log(ctx context.Context, level slog.Level, msg string, args ...any) {
+	if Default().stdoutLogger != nil {
+		Default().stdoutLogger.Log(ctx, level, msg, append(args, AttrFromCtx(ctx)...)...)
+	}
+
+	if Default().fileLogger != nil {
+		Default().fileLogger.Log(ctx, level, msg, append(args, AttrFromCtx(ctx)...)...)
+	}
+
+	if Default().emailLogger != nil {
+		Default().emailLogger.Log(ctx, level, msg, append(args, AttrFromCtx(ctx)...)...)
+	}
+}
+
+func Close() error {
+	if Default().logFile != nil {
+		if err := Default().logFile.Close(); err != nil {
+			return err
+		}
+	}
+
+	return nil
 }

+ 58 - 19
logger/logger_config.go

@@ -1,22 +1,23 @@
 package logger
 
-import (
-	"log/slog"
-)
-
-const (
-	defaultStdoutLogEnabled = true
-)
+import "log/slog"
 
 type Config struct {
-	stdoutLogEnabled bool
+	// stdout config
+	stdoutLogEnabled   bool
+	stdoutLogLevel     slog.Level // INFO by default
+	stdoutLogAddSource bool
+
+	// file config
 	fileLogEnabled   bool
-	emailLogEnabled  bool
+	fileLogLevel     slog.Level // INFO by default
+	fileLogAddSource bool
+	fileLogFilepath  string
 
-	// INFO by default
-	stdoutLogLevel slog.Level
-	fileLogLevel   slog.Level
-	emailLogLevel  slog.Level
+	// email config
+	emailLogEnabled   bool
+	emailLogLevel     slog.Level // INFO by default
+	emailLogAddSource bool
 }
 
 type ConfigOption func(*Config)
@@ -27,33 +28,65 @@ func (s *ConfigOptions) Add(option ConfigOption) {
 	*s = append(*s, option)
 }
 
+func NewConfig(opts ...ConfigOption) Config {
+	c := &Config{}
+	for _, opt := range opts {
+		opt(c)
+	}
+
+	return *c
+}
+
+// stdout log
+
 func WithStdoutLogEnabled(enabled bool) ConfigOption {
 	return func(s *Config) {
 		s.stdoutLogEnabled = enabled
 	}
 }
 
+func WithStdoutLogLevel(level slog.Level) ConfigOption {
+	return func(s *Config) {
+		s.stdoutLogLevel = level
+	}
+}
+func WithStdoutLogAddSource(add bool) ConfigOption {
+	return func(s *Config) {
+		s.stdoutLogAddSource = add
+	}
+}
+
+// file log
+
 func WithFileLogEnabled(enabled bool) ConfigOption {
 	return func(s *Config) {
 		s.fileLogEnabled = enabled
 	}
 }
 
-func WithEmailLogEnabled(enabled bool) ConfigOption {
+func WithFileLogLevel(level slog.Level) ConfigOption {
 	return func(s *Config) {
-		s.emailLogEnabled = enabled
+		s.fileLogLevel = level
 	}
 }
 
-func WithStdoutLogLevel(level slog.Level) ConfigOption {
+func WithFileLogAddSource(add bool) ConfigOption {
 	return func(s *Config) {
-		s.stdoutLogLevel = level
+		s.fileLogAddSource = add
 	}
 }
 
-func WithFileLogLevel(level slog.Level) ConfigOption {
+func WithFileLogFilepath(path string) ConfigOption {
 	return func(s *Config) {
-		s.fileLogLevel = level
+		s.fileLogFilepath = path
+	}
+}
+
+// email log
+
+func WithEmailLogEnabled(enabled bool) ConfigOption {
+	return func(s *Config) {
+		s.emailLogEnabled = enabled
 	}
 }
 
@@ -62,3 +95,9 @@ func WithEmailLogLevel(level slog.Level) ConfigOption {
 		s.emailLogLevel = level
 	}
 }
+
+func WithEmailLogAddSource(add bool) ConfigOption {
+	return func(s *Config) {
+		s.emailLogAddSource = add
+	}
+}

+ 28 - 0
logger/logger_ctx.go

@@ -0,0 +1,28 @@
+package logger
+
+import "context"
+
+func With(ctx context.Context, key string, value any) context.Context {
+	ctxAttrMu.Lock()
+	defer ctxAttrMu.Unlock()
+
+	if ctx.Value(CtxAttrKey{}) == nil {
+		ctx = context.WithValue(ctx, CtxAttrKey{}, make([]any, 0))
+	}
+
+	kv, ok := ctx.Value(CtxAttrKey{}).([]any)
+	if !ok {
+		return ctx
+	}
+
+	return context.WithValue(ctx, CtxAttrKey{}, append(kv, key, value))
+}
+
+func AttrFromCtx(ctx context.Context) []any {
+	ctxAttrMu.RLock()
+	defer ctxAttrMu.RUnlock()
+
+	kv, _ := ctx.Value(CtxAttrKey{}).([]any)
+
+	return kv
+}

+ 31 - 0
main.go

@@ -0,0 +1,31 @@
+package main
+
+import (
+	"context"
+	"log/slog"
+
+	"git.dmitriygnatenko.ru/dima/go-common/logger"
+)
+
+func main() {
+
+	err := logger.Init(logger.NewConfig(
+		logger.WithStdoutLogAddSource(true),
+		logger.WithStdoutLogEnabled(true),
+		logger.WithFileLogLevel(slog.LevelError),
+		logger.WithEmailLogEnabled(true),
+		logger.WithFileLogEnabled(true),
+		logger.WithFileLogFilepath("test_log.txt"),
+	))
+
+	_ = err
+
+	ctx := context.Background()
+
+	ctx = logger.With(ctx, "test111", 74658743)
+
+	logger.InfoKV(ctx, "dfgdgdfgdssg", "dsfsd", "val333", "dfgdf", 11)
+
+	// logger.Error(ctx, "dsfdsf dsf dsfs")
+
+}