You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
285 lines
7.3 KiB
Go
285 lines
7.3 KiB
Go
2 years ago
|
package starlog
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"time"
|
||
|
|
||
|
"b612.me/staros"
|
||
|
|
||
|
"b612.me/starmap"
|
||
|
)
|
||
|
|
||
|
var archMap starmap.StarMapKV
|
||
|
|
||
|
func init() {
|
||
|
archMap = starmap.NewStarMap()
|
||
|
}
|
||
|
|
||
|
type Archive interface {
|
||
|
ShouldArchiveNow(string, os.FileInfo) bool
|
||
|
NextLogFilePath(string, os.FileInfo) string
|
||
|
Interval() int64
|
||
|
HookBeforArchive() func(string, os.FileInfo) error
|
||
|
HookAfterArchive() func(string, string, os.FileInfo) error
|
||
|
}
|
||
|
|
||
|
type logfileinfo struct {
|
||
|
fullpath string
|
||
|
pointer *os.File
|
||
|
}
|
||
|
|
||
|
func SetLogFile(path string, logger *StarLogger, appendMode bool) error {
|
||
|
var fileMode int
|
||
|
if appendMode {
|
||
|
fileMode = os.O_APPEND | os.O_CREATE | os.O_WRONLY
|
||
|
} else {
|
||
|
fileMode = os.O_CREATE | os.O_WRONLY | os.O_TRUNC
|
||
|
}
|
||
|
fullpath, err := filepath.Abs(path)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if !appendMode && staros.Exists(fullpath) {
|
||
|
os.Remove(fullpath)
|
||
|
}
|
||
|
fp, err := os.OpenFile(fullpath, fileMode, 0644)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if archMap.MustGet(logger.logcore.id) != nil {
|
||
|
logger.SetSwitching(true)
|
||
|
err := archMap.MustGet(logger.logcore.id).(logfileinfo).pointer.Close()
|
||
|
if err != nil {
|
||
|
logger.logcore.output = nil
|
||
|
logger.SetSwitching(false)
|
||
|
return err
|
||
|
}
|
||
|
err = archMap.Delete(logger.logcore.id)
|
||
|
if err != nil {
|
||
|
logger.logcore.output = nil
|
||
|
logger.SetSwitching(false)
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
err = archMap.Store(logger.logcore.id, logfileinfo{
|
||
|
fullpath: fullpath,
|
||
|
pointer: fp,
|
||
|
})
|
||
|
if err != nil {
|
||
|
fp.Close()
|
||
|
logger.logcore.output = nil
|
||
|
logger.SetSwitching(false)
|
||
|
return err
|
||
|
}
|
||
|
logger.SetSwitching(true)
|
||
|
logger.logcore.output = fp
|
||
|
logger.SetSwitching(false)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func CloseWithSwitching(logger *StarLogger) error {
|
||
|
if archMap.MustGet(logger.logcore.id) != nil {
|
||
|
logger.SetSwitching(true)
|
||
|
err := archMap.MustGet(logger.logcore.id).(logfileinfo).pointer.Close()
|
||
|
if err != nil {
|
||
|
logger.logcore.output = nil
|
||
|
return err
|
||
|
}
|
||
|
err = archMap.Delete(logger.logcore.id)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func Close(logger *StarLogger) error {
|
||
|
defer logger.SetSwitching(false)
|
||
|
return CloseWithSwitching(logger)
|
||
|
}
|
||
|
|
||
|
func GetLogFileInfo(logger *StarLogger) (os.FileInfo, error) {
|
||
|
if archMap.MustGet(logger.logcore.id) != nil {
|
||
|
return archMap.MustGet(logger.logcore.id).(logfileinfo).pointer.Stat()
|
||
|
}
|
||
|
return nil, errors.New("logger don't have a register logfile")
|
||
|
}
|
||
|
|
||
|
func StartArchive(logger *StarLogger, arch Archive) error {
|
||
|
if archMap.MustGet("arch"+logger.logcore.id) != nil {
|
||
|
return errors.New("already running")
|
||
|
}
|
||
|
stopChan := make(chan int)
|
||
|
archMap.Store("arch"+logger.logcore.id, stopChan)
|
||
|
go func(stopChan chan int, arch Archive, logger *StarLogger) {
|
||
|
for {
|
||
|
select {
|
||
|
case <-stopChan:
|
||
|
return
|
||
|
case <-time.After(time.Second * time.Duration(arch.Interval())):
|
||
|
}
|
||
|
fileinfo, err := GetLogFileInfo(logger)
|
||
|
if err != nil {
|
||
|
logger.Errorf("cannot get log file info,reason is %v\n", err)
|
||
|
continue
|
||
|
}
|
||
|
if archMap.MustGet(logger.logcore.id) == nil {
|
||
|
logger.Errorf("cannot get log core info from the map:no such keys\n")
|
||
|
continue
|
||
|
}
|
||
|
fullpath := archMap.MustGet(logger.logcore.id).(logfileinfo).fullpath
|
||
|
if !arch.ShouldArchiveNow(fullpath, fileinfo) {
|
||
|
continue
|
||
|
}
|
||
|
newLogPath := arch.NextLogFilePath(fullpath, fileinfo)
|
||
|
if arch.HookBeforArchive() != nil {
|
||
|
if err := arch.HookBeforArchive()(fullpath, fileinfo); err != nil {
|
||
|
logger.Errorf("error occur while executing hook before archive,detail is %v\n", err)
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
if err := SetLogFile(newLogPath, logger, false); err != nil {
|
||
|
logger.Errorf("error occur while executing coverting new log file,detail is %v\n", err)
|
||
|
continue
|
||
|
} else {
|
||
|
logger.Debugln("Set Log Success")
|
||
|
}
|
||
|
fileinfo, err = GetLogFileInfo(logger)
|
||
|
if err != nil {
|
||
|
logger.Errorf("cannot get new log core info from the map:no such keys\n")
|
||
|
continue
|
||
|
}
|
||
|
if arch.HookAfterArchive() != nil {
|
||
|
if err := arch.HookAfterArchive()(fullpath, newLogPath, fileinfo); err != nil {
|
||
|
logger.Errorf("error occur while executing hook after archive,detail is %v\n", err)
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}(stopChan, arch, logger)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func IsArchiveRun(logger *StarLogger) bool {
|
||
|
if archMap.MustGet("arch"+logger.logcore.id) == nil {
|
||
|
return false
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func StopArchive(logger *StarLogger) {
|
||
|
if archMap.MustGet("arch"+logger.logcore.id) == nil {
|
||
|
return
|
||
|
}
|
||
|
archMap.MustGet("arch" + logger.logcore.id).(chan int) <- 1
|
||
|
}
|
||
|
|
||
|
type ArchiveByDate struct {
|
||
|
interval int64
|
||
|
checkInterval int64
|
||
|
newFileNameStyle string
|
||
|
hookBefor func(string, os.FileInfo) error
|
||
|
hookAfter func(string, string, os.FileInfo) error
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveByDate) ShouldArchiveNow(fullpath string, info os.FileInfo) bool {
|
||
|
if time.Now().Unix()-staros.GetFileCreationTime(info).Unix() > abd.interval {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveByDate) NextLogFilePath(oldpath string, info os.FileInfo) string {
|
||
|
dir := filepath.Dir(oldpath)
|
||
|
newName := time.Now().Format(abd.newFileNameStyle)
|
||
|
return filepath.Join(dir, newName)
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveByDate) Interval() int64 {
|
||
|
return abd.checkInterval
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveByDate) HookBeforArchive() func(string, os.FileInfo) error {
|
||
|
|
||
|
return abd.hookBefor
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveByDate) HookAfterArchive() func(string, string, os.FileInfo) error {
|
||
|
return abd.hookAfter
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveByDate) SetHookBeforArchive(f func(string, os.FileInfo) error) {
|
||
|
|
||
|
abd.hookBefor = f
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveByDate) SetHookAfterArchive(f func(string, string, os.FileInfo) error) {
|
||
|
abd.hookAfter = f
|
||
|
}
|
||
|
|
||
|
func NewArchiveByDate(archInterval int64, checkInterval int64, fileStyle string, hookbefor func(string, os.FileInfo) error, hookafter func(string, string, os.FileInfo) error) *ArchiveByDate {
|
||
|
return &ArchiveByDate{
|
||
|
interval: archInterval,
|
||
|
checkInterval: checkInterval,
|
||
|
newFileNameStyle: fileStyle,
|
||
|
hookBefor: hookbefor,
|
||
|
hookAfter: hookafter,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type ArchiveBySize struct {
|
||
|
size int64
|
||
|
checkInterval int64
|
||
|
newFileNameStyle string
|
||
|
hookBefor func(string, os.FileInfo) error
|
||
|
hookAfter func(string, string, os.FileInfo) error
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveBySize) ShouldArchiveNow(fullpath string, info os.FileInfo) bool {
|
||
|
if info.Size() > abd.size {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveBySize) NextLogFilePath(oldpath string, info os.FileInfo) string {
|
||
|
dir := filepath.Dir(oldpath)
|
||
|
newName := time.Now().Format(abd.newFileNameStyle)
|
||
|
return filepath.Join(dir, newName)
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveBySize) Interval() int64 {
|
||
|
return abd.checkInterval
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveBySize) HookBeforArchive() func(string, os.FileInfo) error {
|
||
|
|
||
|
return abd.hookBefor
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveBySize) HookAfterArchive() func(string, string, os.FileInfo) error {
|
||
|
return abd.hookAfter
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveBySize) SetHookBeforArchive(f func(string, os.FileInfo) error) {
|
||
|
|
||
|
abd.hookBefor = f
|
||
|
}
|
||
|
|
||
|
func (abd *ArchiveBySize) SetHookAfterArchive(f func(string, string, os.FileInfo) error) {
|
||
|
abd.hookAfter = f
|
||
|
}
|
||
|
|
||
|
func NewArchiveBySize(size int64, checkInterval int64, fileStyle string, hookbefor func(string, os.FileInfo) error, hookafter func(string, string, os.FileInfo) error) *ArchiveBySize {
|
||
|
return &ArchiveBySize{
|
||
|
size: size,
|
||
|
checkInterval: checkInterval,
|
||
|
newFileNameStyle: fileStyle,
|
||
|
hookBefor: hookbefor,
|
||
|
hookAfter: hookafter,
|
||
|
}
|
||
|
}
|