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 }