ec8bfe6b94
Updates https://github.com/storj/storj/issues/5349 Change-Id: I426f38c0ae0f93d498317e3f66ba4f5724620758
124 lines
2.6 KiB
Go
124 lines
2.6 KiB
Go
// Copyright (C) 2023 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package lazyfilewalker
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
type zapWrapper struct {
|
|
Log *zap.Logger
|
|
}
|
|
|
|
var _ io.Writer = (*zapWrapper)(nil)
|
|
|
|
// Write writes the provided bytes to the underlying logger
|
|
// returns the length of the bytes.
|
|
//
|
|
// Write will split the input on newlines, parse, and post each line as a new log entry
|
|
// to the logger.
|
|
func (w *zapWrapper) Write(p []byte) (n int, err error) {
|
|
n = len(p)
|
|
for len(p) > 0 {
|
|
p, err = w.writeLine(p)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
}
|
|
|
|
return n, nil
|
|
}
|
|
|
|
type zapLogger struct {
|
|
Caller string `json:"C"`
|
|
Level zapcore.Level `json:"L"`
|
|
Message string `json:"M"`
|
|
Stack string `json:"S"`
|
|
Name string `json:"N"`
|
|
Time time.Time `json:"T"`
|
|
|
|
LogMap map[string]interface{} `json:"-"`
|
|
}
|
|
|
|
// writeLine writes a single line from the input and returns the remaining bytes.
|
|
func (w *zapWrapper) writeLine(b []byte) (remaining []byte, err error) {
|
|
idx := bytes.IndexByte(b, '\n')
|
|
if idx < 0 {
|
|
// If there are no newlines, log the entire string.
|
|
return nil, w.log(b)
|
|
}
|
|
// Split on the newline, log the left.
|
|
b, remaining = b[:idx], b[idx+1:]
|
|
|
|
return remaining, w.log(b)
|
|
}
|
|
|
|
func (w *zapWrapper) log(b []byte) error {
|
|
logger := zapLogger{}
|
|
if err := json.Unmarshal(b, &logger); err != nil {
|
|
return err
|
|
}
|
|
// parse the unknown fields into a map
|
|
if err := json.Unmarshal(b, &logger.LogMap); err != nil {
|
|
return err
|
|
}
|
|
// remove the known fields that are already parsed from the map
|
|
delete(logger.LogMap, "C")
|
|
delete(logger.LogMap, "L")
|
|
delete(logger.LogMap, "M")
|
|
delete(logger.LogMap, "S")
|
|
delete(logger.LogMap, "N")
|
|
delete(logger.LogMap, "T")
|
|
|
|
log := w.Log.Named(logger.Name)
|
|
if ce := log.Check(logger.Level, logger.Message); ce != nil {
|
|
if logger.Stack != "" {
|
|
ce.Stack = logger.Stack
|
|
}
|
|
if caller := newEntryCaller(logger.Caller); caller != nil {
|
|
ce.Caller = *caller
|
|
}
|
|
|
|
if !logger.Time.IsZero() {
|
|
ce.Time = logger.Time
|
|
}
|
|
|
|
var fields []zapcore.Field
|
|
for key, val := range logger.LogMap {
|
|
fields = append(fields, zap.Any(key, val))
|
|
}
|
|
|
|
ce.Write(fields...)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func newEntryCaller(caller string) *zapcore.EntryCaller {
|
|
if caller == "" {
|
|
return nil
|
|
}
|
|
|
|
idx := strings.IndexByte(caller, ':')
|
|
if idx <= 0 {
|
|
return nil
|
|
}
|
|
|
|
file, line := caller[:idx], caller[idx+1:]
|
|
lineNum, err := strconv.Atoi(line)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
entryCaller := zapcore.NewEntryCaller(0, file, lineNum, true)
|
|
return &entryCaller
|
|
}
|