func (log *sLogger) Destroy(ignore bool) error {
	if log.Logger != nil {
		_ = log.Logger.Sync()  
		log.Logger = nil
		close(log.cancel)
	}
	return nil
}
Destroy Destroy Dot
ignore When calling other Lifer, if true erred then continue, if false erred then return directly
package demo
import (
	"fmt"
	"sync"
	"time"
	"github.com/scryinfo/dot/dot"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)
var (
	_ dot.SLogger = (*sLogger)(nil)
)
func (log *sLogger) updateLogFile() {
	timer := time.NewTimer(log.interval)
	for {
		select {
		case <-log.cancel:
			timer.Stop()  
			return
		case <-timer.C:
			m := sync.Mutex{}
			m.Lock()
			{
				encoderCfg := zapcore.EncoderConfig{
					TimeKey:        "T",
					LevelKey:       "L",
					NameKey:        "N",
					CallerKey:      "C",
					MessageKey:     "M",
					StacktraceKey:  "S",
					LineEnding:     zapcore.DefaultLineEnding,
					EncodeLevel:    zapcore.CapitalLevelEncoder,
					EncodeTime:     timeEncoder,
					EncodeDuration: zapcore.StringDurationEncoder,
					EncodeCaller:   zapcore.ShortCallerEncoder,
				}
				atom := zap.NewAtomicLevel()
				atom.SetLevel(log.GetLevel())
				log.level = atom
				customCfg := zap.Config{
					Level:            log.level,
					Development:      true,
					Encoding:         "console",
					EncoderConfig:    encoderCfg,
					OutputPaths:      []string{"stderr", time.Now().Format(log.formatPrefix) + log.conf.File},
					ErrorOutputPaths: []string{"stderr"},
				}
				logger, err := customCfg.Build(zap.AddCallerSkip(1))
				if err == nil {
					log.Logger = logger
				} else {
					fmt.Print(err)
				}
			}
			m.Unlock()
		}
		timer.Reset(log.interval)
	}
}
const funLog = "Fun Log"
func NewSLogger(conf *dot.LogConfig, l dot.Line) dot.SLogger {
	if conf == nil {
		conf = &dot.LogConfig{
			File: "log.log",
		}
	}
	if len(conf.Level) < 1 {
		conf.Level = zapcore.DebugLevel.String()
	}
	if len(conf.File) < 1 {
		conf.File = "log.log"
	}
	re := &sLogger{
		conf: *conf,
	}
	switch conf.Time {
	case "h", "H", "hour", "HOUR":
		re.interval = time.Hour
		re.formatPrefix = "2006-01-02 15 "
	case "d", "D", "day", "DAY":
		re.interval = time.Hour * 24
		re.formatPrefix = "2006-01-02 "
	case "m", "M", "month", "MONTH":
		re.interval = time.Hour * 24 * 31
		re.formatPrefix = "2006-01 "
	case "y", "Y", "year", "YEAR":
		re.interval = time.Hour * 24 * 31 * 12
		re.formatPrefix = "2006 "
	default:
		re.interval = time.Hour * 24 * 31 * 12
		re.formatPrefix = "2006 "
	}
	_ = re.Create(l)
	return re
}
type sLogger struct {
	cancel       chan bool
	level        zap.AtomicLevel
	Logger       *zap.Logger
	conf         dot.LogConfig
	interval     time.Duration
	formatPrefix string
}
func (log *sLogger) GetLevel() dot.Level {
	l := zap.InfoLevel
	_ = (&l).UnmarshalText([]byte(log.conf.Level))
	return l
}
func (log *sLogger) SetLevel(levels dot.Level) {
	log.conf.Level = levels.String()
	log.level.SetLevel(levels)
}
func (log *sLogger) Debugln(msg string, fields ...zap.Field) {
	log.Logger.Debug(msg, fields...)
}
func (log *sLogger) Debug(mstr dot.MakeStringer) {
	if dot.DebugLevel <= log.GetLevel() {
		log.Logger.Debug(funLog, zap.String("", mstr()))
	}
}
func (log *sLogger) Infoln(msg string, fields ...zap.Field) {
	log.Logger.Info(msg, fields...)
}
func (log *sLogger) Info(mstr dot.MakeStringer) {
	if dot.InfoLevel <= log.GetLevel() {
		log.Logger.Info(funLog, zap.String("", mstr()))
	}
}
func (log *sLogger) Warnln(msg string, fields ...zap.Field) {
	log.Logger.Warn(msg, fields...)
}
func (log *sLogger) Warn(mstr dot.MakeStringer) {
	if dot.WarnLevel <= log.GetLevel() {
		log.Logger.Warn(funLog, zap.String("", mstr()))
	}
}
func (log *sLogger) Errorln(msg string, fields ...zap.Field) {
	log.Logger.Error(msg, fields...)
}
func (log *sLogger) Error(mstr dot.MakeStringer) {
	if dot.ErrorLevel <= log.GetLevel() {
		log.Logger.Error(funLog, zap.String("", mstr()))
	}
}
func (log *sLogger) Fatalln(msg string, fields ...zap.Field) {
	log.Logger.Fatal(msg, fields...)
}
func (log *sLogger) Fatal(mstr dot.MakeStringer) {
	if dot.FatalLevel <= log.GetLevel() {
		log.Logger.Fatal(funLog, zap.String("", mstr()))
	}
}
func (log *sLogger) NewLogger(callerSkip int) dot.SLogger {
	log.Logger = log.Logger.WithOptions(zap.AddCallerSkip(callerSkip))
	return log
}
func (log *sLogger) Create(l dot.Line) (err error) {
	encoderCfg := zapcore.EncoderConfig{
		TimeKey:        "T",
		LevelKey:       "L",
		NameKey:        "N",
		CallerKey:      "C",
		MessageKey:     "M",
		StacktraceKey:  "S",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.CapitalLevelEncoder,
		EncodeTime:     timeEncoder,
		EncodeDuration: zapcore.StringDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
	atom := zap.NewAtomicLevel()
	atom.SetLevel(log.GetLevel())
	log.level = atom
	customCfg := zap.Config{
		Level:            log.level,
		Development:      true,
		Encoding:         "console",
		EncoderConfig:    encoderCfg,
		OutputPaths:      []string{"stderr", time.Now().Format(log.formatPrefix) + log.conf.File},
		ErrorOutputPaths: []string{"stderr"},
	}
	logger, err := customCfg.Build(zap.AddCallerSkip(1))
	if err == nil {
		log.Logger = logger
	}
	go log.updateLogFile()
	return err
}