feat: add config to truncate long log content (#2767)

master
Kevin Wan 2 years ago committed by GitHub
parent 0defb7522f
commit 74e0676617
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -8,6 +8,7 @@ type LogConf struct {
TimeFormat string `json:",optional"` TimeFormat string `json:",optional"`
Path string `json:",default=logs"` Path string `json:",default=logs"`
Level string `json:",default=info,options=[debug,info,error,severe]"` Level string `json:",default=info,options=[debug,info,error,severe]"`
MaxContentLength uint32 `json:",optional"`
Compress bool `json:",optional"` Compress bool `json:",optional"`
Stat bool `json:",default=true"` Stat bool `json:",default=true"`
KeepDays int `json:",optional"` KeepDays int `json:",optional"`

@ -20,6 +20,8 @@ var (
timeFormat = "2006-01-02T15:04:05.000Z07:00" timeFormat = "2006-01-02T15:04:05.000Z07:00"
logLevel uint32 logLevel uint32
encoding uint32 = jsonEncodingType encoding uint32 = jsonEncodingType
// maxContentLength is used to truncate the log content, 0 for not truncating.
maxContentLength uint32
// use uint32 for atomic operations // use uint32 for atomic operations
disableLog uint32 disableLog uint32
disableStat uint32 disableStat uint32
@ -238,6 +240,8 @@ func SetUp(c LogConf) (err error) {
timeFormat = c.TimeFormat timeFormat = c.TimeFormat
} }
atomic.StoreUint32(&maxContentLength, c.MaxContentLength)
switch c.Encoding { switch c.Encoding {
case plainEncoding: case plainEncoding:
atomic.StoreUint32(&encoding, plainEncodingType) atomic.StoreUint32(&encoding, plainEncodingType)

@ -16,13 +16,13 @@ const (
const ( const (
jsonEncodingType = iota jsonEncodingType = iota
plainEncodingType plainEncodingType
)
const (
plainEncoding = "plain" plainEncoding = "plain"
plainEncodingSep = '\t' plainEncodingSep = '\t'
sizeRotationRule = "size" sizeRotationRule = "size"
)
const (
accessFilename = "access.log" accessFilename = "access.log"
errorFilename = "error.log" errorFilename = "error.log"
severeFilename = "severe.log" severeFilename = "severe.log"
@ -53,6 +53,7 @@ const (
spanKey = "span" spanKey = "span"
timestampKey = "@timestamp" timestampKey = "@timestamp"
traceKey = "trace" traceKey = "trace"
truncatedKey = "truncated"
) )
var ( var (
@ -60,4 +61,6 @@ var (
ErrLogPathNotSet = errors.New("log path must be set") ErrLogPathNotSet = errors.New("log path must be set")
// ErrLogServiceNameNotSet is an error that indicates that the service name is not set. // ErrLogServiceNameNotSet is an error that indicates that the service name is not set.
ErrLogServiceNameNotSet = errors.New("log service name must be set") ErrLogServiceNameNotSet = errors.New("log service name must be set")
truncatedField = Field(truncatedKey, true)
) )

@ -278,6 +278,15 @@ func combineGlobalFields(fields []LogField) []LogField {
} }
func output(writer io.Writer, level string, val interface{}, fields ...LogField) { func output(writer io.Writer, level string, val interface{}, fields ...LogField) {
// only truncate string content, don't know how to truncate the values of other types.
if v, ok := val.(string); ok {
maxLen := atomic.LoadUint32(&maxContentLength)
if maxLen > 0 && len(v) > int(maxLen) {
val = v[:maxLen]
fields = append(fields, truncatedField)
}
}
fields = combineGlobalFields(fields) fields = combineGlobalFields(fields)
switch atomic.LoadUint32(&encoding) { switch atomic.LoadUint32(&encoding) {

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"log" "log"
"sync/atomic"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -157,9 +158,40 @@ func TestWritePlainAny(t *testing.T) {
} }
func TestLogWithLimitContentLength(t *testing.T) {
maxLen := atomic.LoadUint32(&maxContentLength)
atomic.StoreUint32(&maxContentLength, 10)
t.Cleanup(func() {
atomic.StoreUint32(&maxContentLength, maxLen)
})
t.Run("alert", func(t *testing.T) {
var buf bytes.Buffer
w := NewWriter(&buf)
w.Info("1234567890")
var v1 mockedEntry
if err := json.Unmarshal(buf.Bytes(), &v1); err != nil {
t.Fatal(err)
}
assert.Equal(t, "1234567890", v1.Content)
assert.False(t, v1.Truncated)
buf.Reset()
var v2 mockedEntry
w.Info("12345678901")
if err := json.Unmarshal(buf.Bytes(), &v2); err != nil {
t.Fatal(err)
}
assert.Equal(t, "1234567890", v2.Content)
assert.True(t, v2.Truncated)
})
}
type mockedEntry struct { type mockedEntry struct {
Level string `json:"level"` Level string `json:"level"`
Content string `json:"content"` Content string `json:"content"`
Truncated bool `json:"truncated"`
} }
type easyToCloseWriter struct{} type easyToCloseWriter struct{}

@ -89,6 +89,7 @@ func NewClientWithTarget(target string, opts ...ClientOption) (Client, error) {
Breaker: true, Breaker: true,
Timeout: true, Timeout: true,
} }
return internal.NewClient(target, middlewares, opts...) return internal.NewClient(target, middlewares, opts...)
} }

Loading…
Cancel
Save