| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 | package logimport (	"bufio"	"bytes"	"fmt"	"io"	"log"	"os"	"path/filepath"	"strings"	"sync"	"time")func NewLogger(level Level, prefix string, depth int, w ...io.Writer) Logger {	return NewLog(level, w, prefix, depth, 0)}func NewFileWriter(prefix, path string) io.WriteCloser {	return &file{		Prefix: prefix,		Path:   path,	}}func ConsoleWith(level Level, dept int) *Log {	return NewLog(level, []io.Writer{os.Stdout}, "", dept, 0)}func Discard() *Log {	return NewLog(LevelNone, []io.Writer{io.Discard}, "", 0, 0)}func Fork(l Logger, subPath, prefix string) Logger {	return rebuild(l, subPath, prefix, true)}func Part(l Logger, subPath, prefix string) Logger {	return rebuild(l, subPath, prefix, false)}func rebuild(l Logger, subPath, prefix string, withMain bool) Logger {	switch old := l.(type) {	case *Log:		pool := make([]io.Writer, 0, len(old.wPool))		for _, w := range old.wPool {			if f, o := w.(*file); o {				if prefix == "" {					prefix = "log"				}				pool = append(pool,					NewFileWriter(filepath.Base(prefix), filepath.Join(f.Path, subPath)),				)				if withMain {					pool = append(pool, f)				}			} else {				if w == os.Stdout {					pool = append(pool, Console())				} else {					pool = append(pool, w)				}			}		}		return NewLog(old.level, pool, prefix, old.depth, old.buf)	case MultiLogger:		part := make(MultiLogger, len(old))		for i, ol := range old {			if lg, ok := ol.(*Log); ok {				part[i] = rebuild(lg, subPath, prefix, withMain)			} else {				part[i] = ol			}		}		return part	default:		return l	}}func NewSession(l Logger, sessionId string) Logger {	switch old := l.(type) {	case *Log:		return NewLog(old.level, old.wPool, strings.TrimSuffix(old.prefix, " ")+sessionId, old.depth, old.buf)	case MultiLogger:		logs := make(MultiLogger, len(old))		for i, ol := range old {			logs[i] = NewSession(ol, sessionId)		}		return logs	default:		return l	}}var consoleLog = ConsoleWith(LevelDebug, 1)func Console() *Log {	return consoleLog}type Level intconst (	LevelNone Level = 0)const (	LevelError Level = iota + 1	LevelWarn	LevelInfo	LevelDebug)const (	LevelsError = "[E]"	LevelsWarn  = "[W]"	LevelsInfo  = "[I]"	LevelsDebug = "[D]")const (	PrintFlags = log.LstdFlags | log.Llongfile)const (	Ext = ".log")const (	Layout = "2006_01_02")type FileName stringfunc (f FileName) Prefix() string {	return string(f)[:strings.Index(string(f), "_")]}func (f FileName) Date() string {	last := strings.LastIndex(string(f), ".")	idx := len(f) - len(Layout) - len(Ext)	return string(f)[idx:last]}func (f FileName) Ext() string {	return filepath.Ext(string(f))}func (f FileName) String() string { return string(f) }func buildPrefix(s string) string {	return "[" + s + "]"}func spitPrefix(s string) string {	idx := strings.Index(s, " ")	if idx == -1 {		return s	}	s = strings.ToLower(s[:idx])	s = strings.TrimPrefix(s, "[")	s = strings.TrimSuffix(s, "]")	return s}type file struct {	Prefix string    // svc	Path   string    // /var/log	date   time.Time // 2006_01_02	fi     *os.File}func (f *file) Write(b []byte) (n int, err error) {	if err = f.check(); err != nil {		return 0, err	}	return f.fi.Write(b)}func (f *file) Close() error {	return f.fi.Close()}func (f *file) createDir() error {	if _, err := os.Stat(f.Path); err != nil {		if os.IsNotExist(err) {			// 这里文件夹权限即使设置为 ModePerm, Linux 系统权限也是 755			if err = os.MkdirAll(f.Path, os.ModePerm); err != nil {				return err			}		}		return err	}	return nil}func (f *file) openFile(date string) (*os.File, error) {	return os.OpenFile(f.name(date), os.O_WRONLY|os.O_CREATE|os.O_APPEND, os.ModePerm) // 创建文件}func (f *file) name(date string) string {	path := fmt.Sprintf("%s_%s%s", f.Prefix, date, Ext)	if f.Prefix == "" {		path = date + Ext	}	// /var/log/svc_2006_01_02.log	return filepath.Join(f.Path, path)}func (f *file) checkDate(cur time.Time) bool {	curY, curM, curD := cur.Date()	oldY, oldM, oldD := f.date.Date()	if curY == oldY && curM == oldM && curD == oldD {		return true	}	return false}func (f *file) check() error {	if f.fi == nil {		if err := f.createDir(); err != nil {			return err		}	}	cur := time.Now()	if f.checkDate(cur) {		return nil	}	if f.fi != nil {		_ = f.fi.Close()	}	fi, err := f.openFile(cur.Format(Layout))	if err != nil {		return err	}	f.fi = fi	f.date = cur	return nil}type Log struct {	level  Level	depth  int // 2	prefix string	buf    int	wPool  []io.Writer	logs   []*log.Logger	mu sync.Mutex}func NewLog(level Level, writers []io.Writer, prefix string, depth int, buf int) *Log {	if depth < 0 {		depth = 0	}	if prefix != "" {		prefix = prefix + " "	}	l := new(Log)	l.level = level	l.prefix = prefix	l.depth = depth	l.wPool = writers	l.buf = buf	l.logs = make([]*log.Logger, len(l.wPool))	for i := 0; i < len(l.wPool); i++ {		w := l.wPool[i]		if buf > 0 {			w = bufio.NewWriterSize(w, buf)		}		l.logs[i] = log.New(w, prefix, func() int {			if depth <= 0 {				return log.LstdFlags			}			return PrintFlags		}())	}	return l}func (l *Log) CallDepthPlus() {	l.depth++}func (l *Log) CallDepthMinus() {	l.depth--}func (l *Log) Write(b []byte) (int, error) {	if l.level == LevelNone {		return len(b), nil	}	l.mu.Lock()	n, err := bytes.NewReader(b).WriteTo(io.MultiWriter(l.wPool...))	l.mu.Unlock()	return int(n), err}func (l *Log) Prefix(prefix string, f string, v ...any) {	if l.level == LevelNone {		return	}	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, prefix)		_ = lg.Output(l.depth, fmt.Sprintf(l.prefix+f, v...))	}	l.mu.Unlock()}func (l *Log) Println(f string, v ...any) {	if l.level == LevelNone {		return	}	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, "")		_ = lg.Output(l.depth, fmt.Sprintf(l.prefix+f, v...))	}	l.mu.Unlock()}// Logger startfunc (l *Log) Error(f string, v ...any) {	if l.level < LevelError {		return	}	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, LevelsError)		_ = lg.Output(l.depth, fmt.Sprintf(l.prefix+f, v...))	}	l.mu.Unlock()}func (l *Log) Warn(f string, v ...any) {	if l.level < LevelWarn {		return	}	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, LevelsWarn)		_ = lg.Output(l.depth, fmt.Sprintf(l.prefix+f, v...))	}	l.mu.Unlock()}func (l *Log) Info(f string, v ...any) {	if l.level < LevelInfo {		return	}	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, LevelsInfo)		_ = lg.Output(l.depth, fmt.Sprintf(l.prefix+f, v...))	}	l.mu.Unlock()}func (l *Log) Debug(f string, v ...any) {	if l.level < LevelDebug {		return	}	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, LevelsDebug)		_ = lg.Output(l.depth, fmt.Sprintf(l.prefix+f, v...))	}	l.mu.Unlock()}// Logger endfunc (l *Log) setPrefixFmt(logger *log.Logger, s string) {	prefix := s + " "	if logger.Prefix() == prefix {		return	}	logger.SetPrefix(prefix)}
 |