mirror of
https://github.com/zeromicro/go-zero.git
synced 2025-02-02 16:28:39 +08:00
feat: add config to truncate long log content (#2767)
This commit is contained in:
parent
0defb7522f
commit
74e0676617
@ -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
|
||||||
|
|
||||||
plainEncoding = "plain"
|
|
||||||
plainEncodingSep = '\t'
|
|
||||||
sizeRotationRule = "size"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
plainEncoding = "plain"
|
||||||
|
plainEncodingSep = '\t'
|
||||||
|
sizeRotationRule = "size"
|
||||||
|
|
||||||
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…
Reference in New Issue
Block a user