218 lines
6.1 KiB
Go
218 lines
6.1 KiB
Go
|
|
package starlog
|
||
|
|
|
||
|
|
import (
|
||
|
|
"errors"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
"sync"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
const defaultRotateNamePattern = "20060102-150405"
|
||
|
|
|
||
|
|
func normalizeRotateNamePattern(pattern string) string {
|
||
|
|
pattern = strings.TrimSpace(pattern)
|
||
|
|
if pattern == "" {
|
||
|
|
return defaultRotateNamePattern
|
||
|
|
}
|
||
|
|
return pattern
|
||
|
|
}
|
||
|
|
|
||
|
|
func buildRotatePathWithPattern(current string, now time.Time, pattern string) string {
|
||
|
|
pattern = normalizeRotateNamePattern(pattern)
|
||
|
|
dir := filepath.Dir(current)
|
||
|
|
base := filepath.Base(current)
|
||
|
|
ext := filepath.Ext(base)
|
||
|
|
stem := strings.TrimSuffix(base, ext)
|
||
|
|
suffix := now.Format(pattern)
|
||
|
|
if ext == "" {
|
||
|
|
return filepath.Join(dir, stem+"."+suffix)
|
||
|
|
}
|
||
|
|
return filepath.Join(dir, stem+"."+suffix+ext)
|
||
|
|
}
|
||
|
|
|
||
|
|
func resolveEntryTime(entry *Entry) time.Time {
|
||
|
|
if entry != nil && !entry.Time.IsZero() {
|
||
|
|
return entry.Time
|
||
|
|
}
|
||
|
|
return time.Now()
|
||
|
|
}
|
||
|
|
|
||
|
|
type RotateByTimePolicy struct {
|
||
|
|
interval time.Duration
|
||
|
|
pattern string
|
||
|
|
|
||
|
|
mu sync.Mutex
|
||
|
|
lastRotate time.Time
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewRotateByTimePolicy(interval time.Duration) *RotateByTimePolicy {
|
||
|
|
return NewRotateByTimePolicyWithPattern(interval, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewRotateByTimePolicyWithPattern(interval time.Duration, pattern string) *RotateByTimePolicy {
|
||
|
|
if interval <= 0 {
|
||
|
|
interval = 24 * time.Hour
|
||
|
|
}
|
||
|
|
return &RotateByTimePolicy{
|
||
|
|
interval: interval,
|
||
|
|
pattern: normalizeRotateNamePattern(pattern),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (policy *RotateByTimePolicy) ShouldRotate(info FileInfo, entry *Entry) bool {
|
||
|
|
if policy == nil || info == nil {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
now := resolveEntryTime(entry)
|
||
|
|
policy.mu.Lock()
|
||
|
|
defer policy.mu.Unlock()
|
||
|
|
if policy.lastRotate.IsZero() {
|
||
|
|
policy.lastRotate = GetFileCreationTime(info)
|
||
|
|
if policy.lastRotate.IsZero() {
|
||
|
|
policy.lastRotate = now
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
if now.Sub(policy.lastRotate) >= policy.interval {
|
||
|
|
policy.lastRotate = now
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func (policy *RotateByTimePolicy) NextPath(current string, now time.Time) string {
|
||
|
|
if policy == nil {
|
||
|
|
return buildRotatePathWithPattern(current, now, "")
|
||
|
|
}
|
||
|
|
return buildRotatePathWithPattern(current, now, policy.pattern)
|
||
|
|
}
|
||
|
|
|
||
|
|
type RotateBySizePolicy struct {
|
||
|
|
maxSize int64
|
||
|
|
pattern string
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewRotateBySizePolicy(maxSizeBytes int64) *RotateBySizePolicy {
|
||
|
|
return NewRotateBySizePolicyWithPattern(maxSizeBytes, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewRotateBySizePolicyWithPattern(maxSizeBytes int64, pattern string) *RotateBySizePolicy {
|
||
|
|
if maxSizeBytes <= 0 {
|
||
|
|
maxSizeBytes = 100 * 1024 * 1024
|
||
|
|
}
|
||
|
|
return &RotateBySizePolicy{
|
||
|
|
maxSize: maxSizeBytes,
|
||
|
|
pattern: normalizeRotateNamePattern(pattern),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (policy *RotateBySizePolicy) ShouldRotate(info FileInfo, entry *Entry) bool {
|
||
|
|
_ = entry
|
||
|
|
if policy == nil || info == nil {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
return info.Size() >= policy.maxSize
|
||
|
|
}
|
||
|
|
|
||
|
|
func (policy *RotateBySizePolicy) NextPath(current string, now time.Time) string {
|
||
|
|
if policy == nil {
|
||
|
|
return buildRotatePathWithPattern(current, now, "")
|
||
|
|
}
|
||
|
|
return buildRotatePathWithPattern(current, now, policy.pattern)
|
||
|
|
}
|
||
|
|
|
||
|
|
type RotateByTimeSizePolicy struct {
|
||
|
|
interval time.Duration
|
||
|
|
maxSize int64
|
||
|
|
pattern string
|
||
|
|
|
||
|
|
mu sync.Mutex
|
||
|
|
lastRotate time.Time
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewRotateByTimeSizePolicy(interval time.Duration, maxSizeBytes int64) *RotateByTimeSizePolicy {
|
||
|
|
return NewRotateByTimeSizePolicyWithPattern(interval, maxSizeBytes, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewRotateByTimeSizePolicyWithPattern(interval time.Duration, maxSizeBytes int64, pattern string) *RotateByTimeSizePolicy {
|
||
|
|
if interval <= 0 {
|
||
|
|
interval = 24 * time.Hour
|
||
|
|
}
|
||
|
|
if maxSizeBytes <= 0 {
|
||
|
|
maxSizeBytes = 100 * 1024 * 1024
|
||
|
|
}
|
||
|
|
return &RotateByTimeSizePolicy{
|
||
|
|
interval: interval,
|
||
|
|
maxSize: maxSizeBytes,
|
||
|
|
pattern: normalizeRotateNamePattern(pattern),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (policy *RotateByTimeSizePolicy) ShouldRotate(info FileInfo, entry *Entry) bool {
|
||
|
|
if policy == nil || info == nil {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
now := resolveEntryTime(entry)
|
||
|
|
policy.mu.Lock()
|
||
|
|
defer policy.mu.Unlock()
|
||
|
|
if policy.lastRotate.IsZero() {
|
||
|
|
policy.lastRotate = GetFileCreationTime(info)
|
||
|
|
if policy.lastRotate.IsZero() {
|
||
|
|
policy.lastRotate = now
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if info.Size() >= policy.maxSize {
|
||
|
|
policy.lastRotate = now
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
if now.Sub(policy.lastRotate) >= policy.interval {
|
||
|
|
policy.lastRotate = now
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func (policy *RotateByTimeSizePolicy) NextPath(current string, now time.Time) string {
|
||
|
|
if policy == nil {
|
||
|
|
return buildRotatePathWithPattern(current, now, "")
|
||
|
|
}
|
||
|
|
return buildRotatePathWithPattern(current, now, policy.pattern)
|
||
|
|
}
|
||
|
|
|
||
|
|
func StartRotateByTime(logger *StarLogger, interval time.Duration, checkInterval int64) error {
|
||
|
|
return StartRotatePolicy(logger, NewRotateByTimePolicy(interval), checkInterval)
|
||
|
|
}
|
||
|
|
|
||
|
|
func StartRotateBySize(logger *StarLogger, maxSizeBytes int64, checkInterval int64) error {
|
||
|
|
return StartRotatePolicy(logger, NewRotateBySizePolicy(maxSizeBytes), checkInterval)
|
||
|
|
}
|
||
|
|
|
||
|
|
func StartRotateByTimeSize(logger *StarLogger, interval time.Duration, maxSizeBytes int64, checkInterval int64) error {
|
||
|
|
return StartRotatePolicy(logger, NewRotateByTimeSizePolicy(interval, maxSizeBytes), checkInterval)
|
||
|
|
}
|
||
|
|
|
||
|
|
func StartManagedRotatePolicy(logger *StarLogger, policy RotatePolicy, checkInterval int64, options RotateManageOptions) error {
|
||
|
|
if policy == nil {
|
||
|
|
return errors.New("rotate policy is nil")
|
||
|
|
}
|
||
|
|
strategy := buildRotateStrategy(policy, checkInterval)
|
||
|
|
strategy.afterHook = func(logger *StarLogger, archivePath string, currentPath string, info os.FileInfo) error {
|
||
|
|
return ApplyRotateManageOptions(archivePath, currentPath, options)
|
||
|
|
}
|
||
|
|
return startArchiveWithStrategy(logger, strategy)
|
||
|
|
}
|
||
|
|
|
||
|
|
func StartManagedRotateByTime(logger *StarLogger, interval time.Duration, checkInterval int64, options RotateManageOptions) error {
|
||
|
|
return StartManagedRotatePolicy(logger, NewRotateByTimePolicy(interval), checkInterval, options)
|
||
|
|
}
|
||
|
|
|
||
|
|
func StartManagedRotateBySize(logger *StarLogger, maxSizeBytes int64, checkInterval int64, options RotateManageOptions) error {
|
||
|
|
return StartManagedRotatePolicy(logger, NewRotateBySizePolicy(maxSizeBytes), checkInterval, options)
|
||
|
|
}
|
||
|
|
|
||
|
|
func StartManagedRotateByTimeSize(logger *StarLogger, interval time.Duration, maxSizeBytes int64, checkInterval int64, options RotateManageOptions) error {
|
||
|
|
return StartManagedRotatePolicy(logger, NewRotateByTimeSizePolicy(interval, maxSizeBytes), checkInterval, options)
|
||
|
|
}
|