feat(glog): add log rotation support for short-running process (#2658)

This commit is contained in:
xuyue86
2023-06-29 20:29:33 +08:00
committed by GitHub
parent 5804547bc5
commit 3fab7a341d
2 changed files with 65 additions and 60 deletions

View File

@ -27,7 +27,6 @@ import (
"github.com/gogf/gf/v2/os/gfpool"
"github.com/gogf/gf/v2/os/gmlock"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/util/gconv"
)
@ -100,7 +99,7 @@ func (l *Logger) print(ctx context.Context, level int, stack string, values ...i
// It just initializes once for each logger.
if l.config.RotateSize > 0 || l.config.RotateExpire > 0 {
if !l.config.rotatedHandlerInitialized.Val() && l.config.rotatedHandlerInitialized.Cas(false, true) {
gtimer.AddOnce(context.Background(), l.config.RotateCheckInterval, l.rotateChecksTimely)
l.rotateChecksTimely(ctx)
intlog.Printf(ctx, "logger rotation initialized: every %s", l.config.RotateCheckInterval.String())
}
}

View File

@ -10,6 +10,7 @@ import (
"context"
"fmt"
"runtime"
"strings"
"time"
"github.com/gogf/gf/v2/container/garray"
@ -137,6 +138,11 @@ func (l *Logger) rotateChecksTimely(ctx context.Context) {
intlog.Errorf(ctx, `%+v`, err)
}
intlog.Printf(ctx, "logging rotation start checks: %+v", files)
// get file name regex pattern
// access-{y-m-d}-test.log => access-$-test.log => access-\$-test\.log => access-(.+?)-test\.log
fileNameRegexPattern, _ := gregex.ReplaceString(`{.+?}`, "$", l.config.File)
fileNameRegexPattern = gregex.Quote(fileNameRegexPattern)
fileNameRegexPattern = strings.ReplaceAll(fileNameRegexPattern, "\\$", "(.+?)")
// =============================================================
// Rotation of expired file checks.
// =============================================================
@ -147,7 +153,12 @@ func (l *Logger) rotateChecksTimely(ctx context.Context) {
expireRotated bool
)
for _, file := range files {
if gfile.ExtName(file) == "gz" {
// ignore backup file
if gregex.IsMatchString(`.+\.\d{20}\.log`, gfile.Basename(file)) {
continue
}
// ignore not matching file
if !gregex.IsMatchString(fileNameRegexPattern, file) {
continue
}
mtime = gfile.MTime(file)
@ -159,19 +170,16 @@ func (l *Logger) rotateChecksTimely(ctx context.Context) {
return
}
defer gmlock.Unlock(memoryLockFileKey)
fp := l.getOpenedFilePointer(ctx, file)
if fp == nil {
intlog.Errorf(ctx, `got nil file pointer for: %s`, file)
return
}
if runtime.GOOS == "windows" {
fp := l.getOpenedFilePointer(ctx, file)
if fp == nil {
intlog.Errorf(ctx, `got nil file pointer for: %s`, file)
return
}
if err := fp.Close(true); err != nil {
intlog.Errorf(ctx, `%+v`, err)
}
}
expireRotated = true
intlog.Printf(
ctx,
@ -203,6 +211,11 @@ func (l *Logger) rotateChecksTimely(ctx context.Context) {
if gfile.ExtName(file) == "gz" {
continue
}
// ignore not matching file
originalLoggingFilePath, _ := gregex.ReplaceString(`\.\d{20}`, "", file)
if !gregex.IsMatchString(fileNameRegexPattern, originalLoggingFilePath) {
continue
}
// Eg:
// access.20200326101301899002.log
if gregex.IsMatchString(`.+\.\d{20}\.log`, gfile.Basename(file)) {
@ -233,42 +246,37 @@ func (l *Logger) rotateChecksTimely(ctx context.Context) {
// =============================================================
// Backups count limitation and expiration checks.
// =============================================================
var (
backupFilesMap = make(map[string]*garray.SortedArray)
originalLoggingFilePath string
)
backupFiles := garray.NewSortedArray(func(a, b interface{}) int {
// Sorted by rotated/backup file mtime.
// The older rotated/backup file is put in the head of array.
var (
file1 = a.(string)
file2 = b.(string)
result = gfile.MTimestampMilli(file1) - gfile.MTimestampMilli(file2)
)
if result <= 0 {
return -1
}
return 1
})
if l.config.RotateBackupLimit > 0 || l.config.RotateBackupExpire > 0 {
for _, file := range files {
originalLoggingFilePath, _ = gregex.ReplaceString(`\.\d{20}`, "", file)
if backupFilesMap[originalLoggingFilePath] == nil {
backupFilesMap[originalLoggingFilePath] = garray.NewSortedArray(func(a, b interface{}) int {
// Sorted by rotated/backup file mtime.
// The older rotated/backup file is put in the head of array.
var (
file1 = a.(string)
file2 = b.(string)
result = gfile.MTimestampMilli(file1) - gfile.MTimestampMilli(file2)
)
if result <= 0 {
return -1
}
return 1
})
// ignore not matching file
originalLoggingFilePath, _ := gregex.ReplaceString(`\.\d{20}`, "", file)
if !gregex.IsMatchString(fileNameRegexPattern, originalLoggingFilePath) {
continue
}
// Check if this file a rotated/backup file.
if gregex.IsMatchString(`.+\.\d{20}\.log`, gfile.Basename(file)) {
backupFilesMap[originalLoggingFilePath].Add(file)
backupFiles.Add(file)
}
}
intlog.Printf(ctx, `calculated backup files map: %+v`, backupFilesMap)
for _, array := range backupFilesMap {
diff := array.Len() - l.config.RotateBackupLimit
for i := 0; i < diff; i++ {
path, _ := array.PopLeft()
intlog.Printf(ctx, `remove exceeded backup limit file: %s`, path)
if err := gfile.Remove(path.(string)); err != nil {
intlog.Errorf(ctx, `%+v`, err)
}
intlog.Printf(ctx, `calculated backup files array: %+v`, backupFiles)
diff := backupFiles.Len() - l.config.RotateBackupLimit
for i := 0; i < diff; i++ {
path, _ := backupFiles.PopLeft()
intlog.Printf(ctx, `remove exceeded backup limit file: %s`, path)
if err := gfile.Remove(path.(string)); err != nil {
intlog.Errorf(ctx, `%+v`, err)
}
}
// Backups expiration checking.
@ -277,26 +285,24 @@ func (l *Logger) rotateChecksTimely(ctx context.Context) {
mtime time.Time
subDuration time.Duration
)
for _, array := range backupFilesMap {
array.Iterator(func(_ int, v interface{}) bool {
path := v.(string)
mtime = gfile.MTime(path)
subDuration = now.Sub(mtime)
if subDuration > l.config.RotateBackupExpire {
intlog.Printf(
ctx,
`%v - %v = %v > %v, remove expired backup file: %s`,
now, mtime, subDuration, l.config.RotateBackupExpire, path,
)
if err := gfile.Remove(path); err != nil {
intlog.Errorf(ctx, `%+v`, err)
}
return true
} else {
return false
backupFiles.Iterator(func(_ int, v interface{}) bool {
path := v.(string)
mtime = gfile.MTime(path)
subDuration = now.Sub(mtime)
if subDuration > l.config.RotateBackupExpire {
intlog.Printf(
ctx,
`%v - %v = %v > %v, remove expired backup file: %s`,
now, mtime, subDuration, l.config.RotateBackupExpire, path,
)
if err := gfile.Remove(path); err != nil {
intlog.Errorf(ctx, `%+v`, err)
}
})
}
return true
} else {
return false
}
})
}
}
}