package logjson import ( "encoding/json" "fmt" "io" "os" "git.blauwelle.com/go/crate/log/logsdk" "git.blauwelle.com/go/crate/runtimehelper" "git.blauwelle.com/go/crate/synchelper" ) var _ logsdk.EntryProcessor = &Processor{} // New 返回日志处理对象, // 返回的对象是 [logsdk.EntryProcessor]. func New(opts ...Option) *Processor { cfg := newConfig(opts...) return &Processor{ bufferPool: cfg.pool, output: cfg.output, timeFormat: cfg.timestampFormat, disableTime: cfg.disableTime, disableHTMLEscape: cfg.disableHTMLEscape, prettyPrint: cfg.prettyPrint, } } // Processor 日志处理对象, 把日志处理成 JSON. type Processor struct { bufferPool synchelper.BytesBufferPool output io.Writer timeFormat string disableTime bool disableHTMLEscape bool prettyPrint bool } // Process 处理日志 func (processor *Processor) Process(entry logsdk.ReadonlyEntry) { m := Entry{ Stack: entry.Stack, Fields: entry.Fields, Level: entry.Level, Message: entry.Message, } if !processor.disableTime { m.Time = entry.Time.Format(processor.timeFormat) // 1次分配 } if entry.Caller.IsValid() { // 1次分配 // 直接取 &entry.Caller 会增加堆内存分配 m.Caller = &runtimehelper.Frame{ Function: entry.Caller.Function, File: entry.Caller.File, Line: entry.Caller.Line, } } buf := processor.bufferPool.Get() buf.Reset() defer processor.bufferPool.Put(buf) encoder := json.NewEncoder(buf) if processor.prettyPrint { encoder.SetIndent("", " ") } encoder.SetEscapeHTML(!processor.disableHTMLEscape) // Encode 2次分配 if err := encoder.Encode(m); err != nil { _, _ = fmt.Fprintf(os.Stderr, "JSON processor cannot encode log %#v: %s\n", m, err.Error()) } if _, err := buf.WriteTo(processor.output); err != nil { _, _ = fmt.Fprintf(os.Stderr, "JSON processor cannot write log: %s\n", err.Error()) } } // Entry 被用来 JSON 序列化 type Entry struct { Message string `json:"msg"` Time string `json:"time,omitempty"` Caller *runtimehelper.Frame `json:"caller,omitempty"` Stack []runtimehelper.Frame `json:"stack,omitempty"` Fields []logsdk.KV `json:"fields,omitempty"` Level logsdk.Level `json:"level"` }