forked from ebhomengo/niki
feat(niki): add logger
This commit is contained in:
parent
7bc597a09c
commit
370ca1da1f
|
@ -23,5 +23,4 @@ bin
|
|||
#env
|
||||
*.env
|
||||
|
||||
|
||||
|
||||
logs/
|
||||
|
|
2
go.mod
2
go.mod
|
@ -1,3 +1,5 @@
|
|||
module git.gocasts.ir/ebhomengo/niki
|
||||
|
||||
go 1.21.3
|
||||
|
||||
require gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
|
@ -0,0 +1,58 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultFilePath = "logs/logs.json"
|
||||
defaultUseLocalTime = false
|
||||
defaultFileMaxSizeInMB = 10
|
||||
defaultFileAgeInDays = 30
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
FilePath string
|
||||
UseLocalTime bool
|
||||
FileMaxSizeInMB int
|
||||
FileMaxAgeInDays int
|
||||
}
|
||||
|
||||
var l *slog.Logger
|
||||
|
||||
// init is default logger and Singleton that lets you ensure that a logger has only one instance, while providing a global access point to this instance.
|
||||
func init() {
|
||||
fileWriter := &lumberjack.Logger{
|
||||
Filename: defaultFilePath,
|
||||
LocalTime: defaultUseLocalTime,
|
||||
MaxSize: defaultFileMaxSizeInMB,
|
||||
MaxAge: defaultFileAgeInDays,
|
||||
}
|
||||
l = slog.New(
|
||||
slog.NewJSONHandler(io.MultiWriter(fileWriter, os.Stdout), &slog.HandlerOptions{}),
|
||||
)
|
||||
}
|
||||
|
||||
func L() *slog.Logger {
|
||||
return l
|
||||
}
|
||||
|
||||
// New is constructor logger with special settings
|
||||
func New(cfg Config, opt *slog.HandlerOptions) *slog.Logger {
|
||||
fileWriter := &lumberjack.Logger{
|
||||
Filename: cfg.FilePath,
|
||||
LocalTime: cfg.UseLocalTime,
|
||||
MaxSize: cfg.FileMaxSizeInMB,
|
||||
MaxAge: cfg.FileMaxAgeInDays,
|
||||
}
|
||||
|
||||
logger := slog.New(
|
||||
slog.NewJSONHandler(io.MultiWriter(fileWriter, os.Stdout), opt),
|
||||
)
|
||||
|
||||
return logger
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package logger_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"git.gocasts.ir/ebhomengo/niki/logger"
|
||||
)
|
||||
|
||||
func TestLogger(t *testing.T) {
|
||||
cfg := logger.Config{
|
||||
FilePath: "./logs.json",
|
||||
UseLocalTime: false,
|
||||
FileMaxSizeInMB: 10,
|
||||
FileMaxAgeInDays: 1,
|
||||
}
|
||||
opt := slog.HandlerOptions{
|
||||
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
|
||||
if a.Key == slog.TimeKey {
|
||||
// remove time because it makes test wrong `time is so fast :)`
|
||||
return slog.Attr{}
|
||||
}
|
||||
|
||||
return a
|
||||
},
|
||||
}
|
||||
|
||||
l := logger.New(cfg, &opt)
|
||||
tests := []struct {
|
||||
f func()
|
||||
want string
|
||||
}{
|
||||
{
|
||||
f: func() {
|
||||
l.Info("INFO", "key", "value")
|
||||
},
|
||||
want: `{"level":"INFO","msg":"INFO","key":"value"}`,
|
||||
},
|
||||
{
|
||||
f: func() {
|
||||
l.Warn("WARN", "key", "value")
|
||||
},
|
||||
want: `{"level":"WARN","msg":"WARN","key":"value"}`,
|
||||
},
|
||||
{
|
||||
f: func() {
|
||||
l.Error("ERROR", "key", "value")
|
||||
},
|
||||
want: `{"level":"ERROR","msg":"ERROR","key":"value"}`,
|
||||
},
|
||||
{
|
||||
f: func() {
|
||||
l.With(
|
||||
slog.Group("user",
|
||||
slog.String("id", "user-123"),
|
||||
),
|
||||
).
|
||||
With("environment", "dev").
|
||||
With("error", fmt.Errorf("an error")).
|
||||
Error("A message")
|
||||
},
|
||||
want: `{"level":"ERROR","msg":"A message","user":{"id":"user-123"},"environment":"dev","error":"an error"}`,
|
||||
},
|
||||
}
|
||||
|
||||
// first run logs
|
||||
for _, test := range tests {
|
||||
test.f()
|
||||
}
|
||||
|
||||
f, err := os.Open(cfg.FilePath)
|
||||
defer f.Close()
|
||||
defer os.Remove(cfg.FilePath)
|
||||
if err != nil {
|
||||
t.Fatalf("can't open file: %s", err)
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
|
||||
var logs []string
|
||||
|
||||
for scanner.Scan() {
|
||||
logs = append(logs, scanner.Text())
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
if test.want != logs[i] {
|
||||
t.Fatalf("want: %+v, got: %+v", test.want, logs[i])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue