| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 | package logimport (	"bufio"	"bytes"	"fmt"	"io"	"log"	"os"	"path/filepath"	"strings"	"sync"	"time")func NewFileWriter(tag, path string) io.WriteCloser {	return &file{		Tag:  tag,		Path: path,	}}func NewLogger(dept int, w ...io.Writer) *Log {	return New("", dept+2, w...)}func New(prefix string, dept int, w ...io.Writer) *Log {	if len(w) == 0 {		return Discard()	}	if prefix != "" {		prefix = buildPrefix(prefix) + " "	}	return NewLog(w, prefix, dept, 0)}func Console() *Log {	return ConsoleWith("", 0)}func ConsoleWith(prefix string, dept int) *Log {	return NewLog([]io.Writer{os.Stdout}, prefix, dept+2, 0)}func Discard() *Log {	return NewLog([]io.Writer{io.Discard}, "", 0, 0)}func Fork(l Logger, subPath, tag string) Logger {	return rebuild(l, subPath, tag, true)}func Part(l Logger, subPath, tag string) Logger {	return rebuild(l, subPath, tag, false)}func rebuild(l Logger, subPath, tag 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 {				pool = append(pool,					NewFileWriter(tag, filepath.Join(f.Path, subPath)),				)				if withMain {					pool = append(pool, f)				}			} else {				pool = append(pool, w)			}		}		return NewLog(pool, old.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, tag, withMain)			} else {				part[i] = ol			}		}		return part	default:		return l	}}const (	LevelError uint8 = iota	LevelWarn	LevelInfo	LevelDebug)const (	LevelsError = "[E]"	LevelsWarn  = "[W]"	LevelsInfo  = "[I]"	LevelsDebug = "[D]")const (	PrintFlags = log.LstdFlags | log.Llongfile)const (	dateLayout = "2006_01_02")func buildPrefix(s string) string {	return "[" + strings.ToUpper(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 {	Tag  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.Tag, date, ".log")	if f.Tag == "" {		path = date + ".log"	}	// /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(dateLayout))	if err != nil {		return err	}	f.fi = fi	f.date = cur	return nil}type Log struct {	depth  int // 2	prefix string	buf    int	wPool  []io.Writer	logs   []*log.Logger	mu sync.Mutex}func NewLog(writers []io.Writer, prefix string, depth int, buf int) *Log {	if len(writers) == 0 {		writers = []io.Writer{io.Discard}	}	if depth < 0 {		depth = 2	}	l := new(Log)	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) {	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) {	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, prefix)		_ = lg.Output(l.depth, fmt.Sprintf(f, v...))	}	l.mu.Unlock()}func (l *Log) Println(f string, v ...any) {	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, "")		_ = lg.Output(l.depth, fmt.Sprintf(f, v...))	}	l.mu.Unlock()}// Logger startfunc (l *Log) Error(f string, v ...any) {	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, LevelsError)		_ = lg.Output(l.depth, fmt.Sprintf(f, v...))	}	l.mu.Unlock()}func (l *Log) Warn(f string, v ...any) {	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, LevelsWarn)		_ = lg.Output(l.depth, fmt.Sprintf(f, v...))	}	l.mu.Unlock()}func (l *Log) Info(f string, v ...any) {	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, LevelsInfo)		_ = lg.Output(l.depth, fmt.Sprintf(f, v...))	}	l.mu.Unlock()}func (l *Log) Debug(f string, v ...any) {	l.mu.Lock()	for _, lg := range l.logs {		l.setPrefixFmt(lg, LevelsDebug)		_ = lg.Output(l.depth, fmt.Sprintf(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)}
 |