github.com/zooyer/miskit@v1.0.71/log/log.go (about)

     1  package log
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/zooyer/miskit/trace"
    12  )
    13  
    14  type Config struct {
    15  	Filename string // 文件名
    16  	Output   string // stdout/stderr/file
    17  	Level    string
    18  	Align    bool
    19  	Interval time.Duration
    20  }
    21  
    22  type Logger struct {
    23  	config    *Config
    24  	tag       []interface{}
    25  	keep      []interface{}
    26  	recorder  Recorder
    27  	recorders map[string]Recorder
    28  }
    29  
    30  type Tag struct {
    31  	Key   string      `json:"key"`
    32  	Value interface{} `json:"value"`
    33  }
    34  
    35  type Record struct {
    36  	Time    time.Time `json:"time"`
    37  	Level   string    `json:"level"`
    38  	Tag     []Tag     `json:"tag,omitempty"`
    39  	Message string    `json:"message"`
    40  }
    41  
    42  var recordPool = sync.Pool{
    43  	New: func() interface{} {
    44  		return new(Record)
    45  	},
    46  }
    47  
    48  var levels = map[string]int{
    49  	"TRACE":   0,
    50  	"DEBUG":   1,
    51  	"INFO":    2,
    52  	"WARNING": 3,
    53  	"ERROR":   4,
    54  	"FATAL":   5,
    55  }
    56  
    57  func New(config Config, formatter Formatter) (*Logger, error) {
    58  	var logger = new(Logger)
    59  	logger.config = &config
    60  
    61  	switch config.Output {
    62  	case "stdout":
    63  		logger.recorder = NewStdoutRecorder(formatter)
    64  	case "stderr":
    65  		logger.recorder = NewStderrRecorder(formatter)
    66  	case "file":
    67  		rotating := NewFileTimeRotating(config.Interval, config.Align)
    68  		recorder, err := NewFileRecorder(config.Filename, formatter, rotating)
    69  		if err != nil {
    70  			return nil, err
    71  		}
    72  		logger.recorder = recorder
    73  	}
    74  
    75  	return logger, nil
    76  }
    77  
    78  func (l *Logger) SetRecorder(level string, recorder Recorder) {
    79  	if l.recorders == nil {
    80  		l.recorders = make(map[string]Recorder)
    81  	}
    82  	l.recorders[level] = recorder
    83  }
    84  
    85  func (l *Logger) SetDefaultRecorder(recorder Recorder) {
    86  	l.recorder = recorder
    87  }
    88  
    89  func (l *Logger) New() *Logger {
    90  	var recorders = make(map[string]Recorder)
    91  	for level, recorder := range l.recorders {
    92  		recorders[level] = recorder
    93  	}
    94  
    95  	var keep = make([]interface{}, 0, len(l.keep))
    96  	for _, tag := range l.keep {
    97  		keep = append(keep, tag)
    98  	}
    99  
   100  	return &Logger{
   101  		config:    l.config,
   102  		tag:       nil,
   103  		keep:      keep,
   104  		recorder:  l.recorder,
   105  		recorders: recorders,
   106  	}
   107  }
   108  
   109  func (l *Logger) Tag(keep bool, kv ...interface{}) *Logger {
   110  	if len(kv) == 0 {
   111  		return l
   112  	}
   113  
   114  	if keep {
   115  		l.keep = append(l.keep, kv...)
   116  	} else {
   117  		l.tag = append(l.tag, kv...)
   118  	}
   119  
   120  	return l
   121  }
   122  
   123  func (l *Logger) trace(ctx context.Context, record *Record) {
   124  	if record == nil {
   125  		return
   126  	}
   127  
   128  	if t := trace.Get(ctx); t != nil {
   129  		if t.TraceID != "" {
   130  			record.Tag = append(record.Tag, Tag{Key: "trace_id", Value: t.TraceID})
   131  		}
   132  		if t.SpanID != "" {
   133  			record.Tag = append(record.Tag, Tag{Key: "span_id", Value: t.SpanID})
   134  		}
   135  		if t.Lang != "" {
   136  			record.Tag = append(record.Tag, Tag{Key: "lang", Value: t.Lang})
   137  		}
   138  		if t.Tag != "" {
   139  			record.Tag = append(record.Tag, Tag{Key: "tag", Value: t.Tag})
   140  		}
   141  		if len(t.Content) != 0 {
   142  			record.Tag = append(record.Tag, Tag{Key: "content", Value: t.Content})
   143  		}
   144  	}
   145  }
   146  
   147  func (l *Logger) format(v ...interface{}) string {
   148  	if len(v) == 0 {
   149  		return ""
   150  	}
   151  
   152  	var builder = pool.Get().(*strings.Builder)
   153  	defer pool.Put(builder)
   154  	defer builder.Reset()
   155  
   156  	for i, arg := range v {
   157  		if i > 0 {
   158  			builder.WriteByte(' ')
   159  		}
   160  		builder.WriteString(fmt.Sprint(arg))
   161  	}
   162  
   163  	return builder.String()
   164  }
   165  
   166  func (l *Logger) canRecord(level string) bool {
   167  	if len(l.recorders) == 0 && l.recorder == nil {
   168  		return false
   169  	}
   170  
   171  	if levels[level] >= levels[l.config.Level] {
   172  		return true
   173  	}
   174  
   175  	return false
   176  }
   177  
   178  func (l *Logger) toTag(kv []interface{}) []Tag {
   179  	if len(kv) == 0 {
   180  		return nil
   181  	}
   182  
   183  	tag := make([]Tag, 0, len(kv))
   184  
   185  	var key string
   186  	for i := 0; i < len(kv)-1; i += 2 {
   187  		switch k := kv[i].(type) {
   188  		case string:
   189  			key = k
   190  		default:
   191  			key = fmt.Sprint(k)
   192  		}
   193  		if val := kv[i+1]; val != nil && key != "" {
   194  			tag = append(tag, Tag{
   195  				Key:   key,
   196  				Value: val,
   197  			})
   198  		}
   199  	}
   200  
   201  	return tag
   202  }
   203  
   204  func (l *Logger) output(ctx context.Context, level string, v ...interface{}) {
   205  	if !l.canRecord(level) {
   206  		return
   207  	}
   208  
   209  	var record = recordPool.Get().(*Record)
   210  	defer recordPool.Put(record)
   211  	defer record.Reset()
   212  
   213  	record.Time = time.Now()
   214  	record.Level = level
   215  	record.Message = l.format(v...)
   216  	l.trace(ctx, record)
   217  	record.Tag = append(record.Tag, l.toTag(l.keep)...)
   218  	record.Tag = append(record.Tag, l.toTag(l.tag)...)
   219  	l.tag = l.tag[:0]
   220  
   221  	l.record(record)
   222  }
   223  
   224  func (l *Logger) record(record *Record) {
   225  	recorder, ok := l.recorders[record.Level]
   226  	if !ok {
   227  		recorder = l.recorder
   228  	}
   229  	if recorder != nil {
   230  		recorder.Record(record)
   231  	}
   232  }
   233  
   234  func (l *Logger) Debug(ctx context.Context, v ...interface{}) {
   235  	l.output(ctx, "DEBUG", v...)
   236  }
   237  
   238  func (l *Logger) Info(ctx context.Context, v ...interface{}) {
   239  	l.output(ctx, "INFO", v...)
   240  }
   241  
   242  func (l *Logger) Warning(ctx context.Context, v ...interface{}) {
   243  	l.output(ctx, "WARNING", v...)
   244  }
   245  
   246  func (l *Logger) Error(ctx context.Context, v ...interface{}) {
   247  	l.output(ctx, "ERROR", v...)
   248  }
   249  
   250  func (l *Logger) Fatal(ctx context.Context, v ...interface{}) {
   251  	l.output(ctx, "FATAL", v...)
   252  	os.Exit(0)
   253  }