summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/logr/v2/formatters
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mattermost/logr/v2/formatters')
-rw-r--r--vendor/github.com/mattermost/logr/v2/formatters/gelf.go152
-rw-r--r--vendor/github.com/mattermost/logr/v2/formatters/json.go273
-rw-r--r--vendor/github.com/mattermost/logr/v2/formatters/plain.go146
3 files changed, 571 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/logr/v2/formatters/gelf.go b/vendor/github.com/mattermost/logr/v2/formatters/gelf.go
new file mode 100644
index 00000000..9dece13c
--- /dev/null
+++ b/vendor/github.com/mattermost/logr/v2/formatters/gelf.go
@@ -0,0 +1,152 @@
+package formatters
+
+import (
+ "bytes"
+ "fmt"
+ "net"
+ "os"
+ "strings"
+
+ "github.com/francoispqt/gojay"
+ "github.com/mattermost/logr/v2"
+)
+
+const (
+ GelfVersion = "1.1"
+ GelfVersionKey = "version"
+ GelfHostKey = "host"
+ GelfShortKey = "short_message"
+ GelfFullKey = "full_message"
+ GelfTimestampKey = "timestamp"
+ GelfLevelKey = "level"
+)
+
+// Gelf formats log records as GELF rcords (https://docs.graylog.org/en/4.0/pages/gelf.html).
+type Gelf struct {
+ // Hostname allows a custom hostname, otherwise os.Hostname is used
+ Hostname string `json:"hostname"`
+
+ // EnableCaller enables output of the file and line number that emitted a log record.
+ EnableCaller bool `json:"enable_caller"`
+
+ // FieldSorter allows custom sorting for the context fields.
+ FieldSorter func(fields []logr.Field) []logr.Field `json:"-"`
+}
+
+func (g *Gelf) CheckValid() error {
+ return nil
+}
+
+// IsStacktraceNeeded returns true if a stacktrace is needed so we can output the `Caller` field.
+func (g *Gelf) IsStacktraceNeeded() bool {
+ return g.EnableCaller
+}
+
+// Format converts a log record to bytes in GELF format.
+func (g *Gelf) Format(rec *logr.LogRec, level logr.Level, buf *bytes.Buffer) (*bytes.Buffer, error) {
+ if buf == nil {
+ buf = &bytes.Buffer{}
+ }
+ enc := gojay.BorrowEncoder(buf)
+ defer func() {
+ enc.Release()
+ }()
+
+ gr := gelfRecord{
+ LogRec: rec,
+ Gelf: g,
+ level: level,
+ sorter: g.FieldSorter,
+ }
+
+ err := enc.EncodeObject(gr)
+ if err != nil {
+ return nil, err
+ }
+
+ buf.WriteByte(0)
+ return buf, nil
+}
+
+type gelfRecord struct {
+ *logr.LogRec
+ *Gelf
+ level logr.Level
+ sorter func(fields []logr.Field) []logr.Field
+}
+
+// MarshalJSONObject encodes the LogRec as JSON.
+func (gr gelfRecord) MarshalJSONObject(enc *gojay.Encoder) {
+ enc.AddStringKey(GelfVersionKey, GelfVersion)
+ enc.AddStringKey(GelfHostKey, gr.getHostname())
+ enc.AddStringKey(GelfShortKey, gr.Msg())
+
+ if gr.level.Stacktrace {
+ frames := gr.StackFrames()
+ if len(frames) != 0 {
+ var sbuf strings.Builder
+ for _, frame := range frames {
+ fmt.Fprintf(&sbuf, "%s\n %s:%d\n", frame.Function, frame.File, frame.Line)
+ }
+ enc.AddStringKey(GelfFullKey, sbuf.String())
+ }
+ }
+
+ secs := float64(gr.Time().UTC().Unix())
+ millis := float64(gr.Time().Nanosecond() / 1000000)
+ ts := secs + (millis / 1000)
+ enc.AddFloat64Key(GelfTimestampKey, ts)
+
+ enc.AddUint32Key(GelfLevelKey, uint32(gr.level.ID))
+
+ var fields []logr.Field
+ if gr.EnableCaller {
+ caller := logr.Field{
+ Key: "_caller",
+ Type: logr.StringType,
+ String: gr.LogRec.Caller(),
+ }
+ fields = append(fields, caller)
+ }
+
+ fields = append(fields, gr.Fields()...)
+ if gr.sorter != nil {
+ fields = gr.sorter(fields)
+ }
+
+ if len(fields) > 0 {
+ for _, field := range fields {
+ if !strings.HasPrefix("_", field.Key) {
+ field.Key = "_" + field.Key
+ }
+ if err := encodeField(enc, field); err != nil {
+ enc.AddStringKey(field.Key, fmt.Sprintf("<error encoding field: %v>", err))
+ }
+ }
+ }
+}
+
+// IsNil returns true if the gelf record pointer is nil.
+func (gr gelfRecord) IsNil() bool {
+ return gr.LogRec == nil
+}
+
+func (g *Gelf) getHostname() string {
+ if g.Hostname != "" {
+ return g.Hostname
+ }
+ h, err := os.Hostname()
+ if err == nil {
+ return h
+ }
+
+ // get the egress IP by fake dialing any address. UDP ensures no dial.
+ conn, err := net.Dial("udp", "8.8.8.8:80")
+ if err != nil {
+ return "unknown"
+ }
+ defer conn.Close()
+
+ local := conn.LocalAddr().(*net.UDPAddr)
+ return local.IP.String()
+}
diff --git a/vendor/github.com/mattermost/logr/v2/formatters/json.go b/vendor/github.com/mattermost/logr/v2/formatters/json.go
new file mode 100644
index 00000000..172b9612
--- /dev/null
+++ b/vendor/github.com/mattermost/logr/v2/formatters/json.go
@@ -0,0 +1,273 @@
+package formatters
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "runtime"
+ "strings"
+ "sync"
+
+ "github.com/francoispqt/gojay"
+ "github.com/mattermost/logr/v2"
+)
+
+// JSON formats log records as JSON.
+type JSON struct {
+ // DisableTimestamp disables output of timestamp field.
+ DisableTimestamp bool `json:"disable_timestamp"`
+ // DisableLevel disables output of level field.
+ DisableLevel bool `json:"disable_level"`
+ // DisableMsg disables output of msg field.
+ DisableMsg bool `json:"disable_msg"`
+ // DisableFields disables output of all fields.
+ DisableFields bool `json:"disable_fields"`
+ // DisableStacktrace disables output of stack trace.
+ DisableStacktrace bool `json:"disable_stacktrace"`
+ // EnableCaller enables output of the file and line number that emitted a log record.
+ EnableCaller bool `json:"enable_caller"`
+
+ // TimestampFormat is an optional format for timestamps. If empty
+ // then DefTimestampFormat is used.
+ TimestampFormat string `json:"timestamp_format"`
+
+ // KeyTimestamp overrides the timestamp field key name.
+ KeyTimestamp string `json:"key_timestamp"`
+
+ // KeyLevel overrides the level field key name.
+ KeyLevel string `json:"key_level"`
+
+ // KeyMsg overrides the msg field key name.
+ KeyMsg string `json:"key_msg"`
+
+ // KeyGroupFields when not empty will group all context fields
+ // under this key.
+ KeyGroupFields string `json:"key_group_fields"`
+
+ // KeyStacktrace overrides the stacktrace field key name.
+ KeyStacktrace string `json:"key_stacktrace"`
+
+ // KeyCaller overrides the caller field key name.
+ KeyCaller string `json:"key_caller"`
+
+ // FieldSorter allows custom sorting of the fields. If nil then
+ // no sorting is done.
+ FieldSorter func(fields []logr.Field) []logr.Field `json:"-"`
+
+ once sync.Once
+}
+
+func (j *JSON) CheckValid() error {
+ return nil
+}
+
+// IsStacktraceNeeded returns true if a stacktrace is needed so we can output the `Caller` field.
+func (j *JSON) IsStacktraceNeeded() bool {
+ return j.EnableCaller
+}
+
+// Format converts a log record to bytes in JSON format.
+func (j *JSON) Format(rec *logr.LogRec, level logr.Level, buf *bytes.Buffer) (*bytes.Buffer, error) {
+ j.once.Do(j.applyDefaultKeyNames)
+
+ if buf == nil {
+ buf = &bytes.Buffer{}
+ }
+ enc := gojay.BorrowEncoder(buf)
+ defer func() {
+ enc.Release()
+ }()
+
+ jlr := JSONLogRec{
+ LogRec: rec,
+ JSON: j,
+ level: level,
+ sorter: j.FieldSorter,
+ }
+
+ err := enc.EncodeObject(jlr)
+ if err != nil {
+ return nil, err
+ }
+ buf.WriteByte('\n')
+ return buf, nil
+}
+
+func (j *JSON) applyDefaultKeyNames() {
+ if j.KeyTimestamp == "" {
+ j.KeyTimestamp = "timestamp"
+ }
+ if j.KeyLevel == "" {
+ j.KeyLevel = "level"
+ }
+ if j.KeyMsg == "" {
+ j.KeyMsg = "msg"
+ }
+ if j.KeyStacktrace == "" {
+ j.KeyStacktrace = "stacktrace"
+ }
+ if j.KeyCaller == "" {
+ j.KeyCaller = "caller"
+ }
+}
+
+// JSONLogRec decorates a LogRec adding JSON encoding.
+type JSONLogRec struct {
+ *logr.LogRec
+ *JSON
+ level logr.Level
+ sorter func(fields []logr.Field) []logr.Field
+}
+
+// MarshalJSONObject encodes the LogRec as JSON.
+func (jlr JSONLogRec) MarshalJSONObject(enc *gojay.Encoder) {
+ if !jlr.DisableTimestamp {
+ timestampFmt := jlr.TimestampFormat
+ if timestampFmt == "" {
+ timestampFmt = logr.DefTimestampFormat
+ }
+ time := jlr.Time()
+ enc.AddTimeKey(jlr.KeyTimestamp, &time, timestampFmt)
+ }
+ if !jlr.DisableLevel {
+ enc.AddStringKey(jlr.KeyLevel, jlr.level.Name)
+ }
+ if !jlr.DisableMsg {
+ enc.AddStringKey(jlr.KeyMsg, jlr.Msg())
+ }
+ if jlr.EnableCaller {
+ enc.AddStringKey(jlr.KeyCaller, jlr.Caller())
+ }
+ if !jlr.DisableFields {
+ fields := jlr.Fields()
+ if jlr.sorter != nil {
+ fields = jlr.sorter(fields)
+ }
+ if jlr.KeyGroupFields != "" {
+ enc.AddObjectKey(jlr.KeyGroupFields, FieldArray(fields))
+ } else {
+ if len(fields) > 0 {
+ for _, field := range fields {
+ field = jlr.prefixCollision(field)
+ if err := encodeField(enc, field); err != nil {
+ enc.AddStringKey(field.Key, "<error encoding field: "+err.Error()+">")
+ }
+ }
+ }
+ }
+ }
+ if jlr.level.Stacktrace && !jlr.DisableStacktrace {
+ frames := jlr.StackFrames()
+ if len(frames) > 0 {
+ enc.AddArrayKey(jlr.KeyStacktrace, stackFrames(frames))
+ }
+ }
+}
+
+// IsNil returns true if the LogRec pointer is nil.
+func (rec JSONLogRec) IsNil() bool {
+ return rec.LogRec == nil
+}
+
+func (rec JSONLogRec) prefixCollision(field logr.Field) logr.Field {
+ switch field.Key {
+ case rec.KeyTimestamp, rec.KeyLevel, rec.KeyMsg, rec.KeyStacktrace:
+ f := field
+ f.Key = "_" + field.Key
+ return rec.prefixCollision(f)
+ }
+ return field
+}
+
+type stackFrames []runtime.Frame
+
+// MarshalJSONArray encodes stackFrames slice as JSON.
+func (s stackFrames) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, frame := range s {
+ enc.AddObject(stackFrame(frame))
+ }
+}
+
+// IsNil returns true if stackFrames is empty slice.
+func (s stackFrames) IsNil() bool {
+ return len(s) == 0
+}
+
+type stackFrame runtime.Frame
+
+// MarshalJSONArray encodes stackFrame as JSON.
+func (f stackFrame) MarshalJSONObject(enc *gojay.Encoder) {
+ enc.AddStringKey("Function", f.Function)
+ enc.AddStringKey("File", f.File)
+ enc.AddIntKey("Line", f.Line)
+}
+
+func (f stackFrame) IsNil() bool {
+ return false
+}
+
+type FieldArray []logr.Field
+
+// MarshalJSONObject encodes Fields map to JSON.
+func (fa FieldArray) MarshalJSONObject(enc *gojay.Encoder) {
+ for _, fld := range fa {
+ if err := encodeField(enc, fld); err != nil {
+ enc.AddStringKey(fld.Key, "<error encoding field: "+err.Error()+">")
+ }
+ }
+}
+
+// IsNil returns true if map is nil.
+func (fa FieldArray) IsNil() bool {
+ return fa == nil
+}
+
+func encodeField(enc *gojay.Encoder, field logr.Field) error {
+ // first check if the value has a marshaller already.
+ switch vt := field.Interface.(type) {
+ case gojay.MarshalerJSONObject:
+ enc.AddObjectKey(field.Key, vt)
+ return nil
+ case gojay.MarshalerJSONArray:
+ enc.AddArrayKey(field.Key, vt)
+ return nil
+ }
+
+ switch field.Type {
+ case logr.StringType:
+ enc.AddStringKey(field.Key, field.String)
+
+ case logr.BoolType:
+ var b bool
+ if field.Integer != 0 {
+ b = true
+ }
+ enc.AddBoolKey(field.Key, b)
+
+ case logr.StructType, logr.ArrayType, logr.MapType, logr.UnknownType:
+ b, err := json.Marshal(field.Interface)
+ if err != nil {
+ return err
+ }
+ embed := gojay.EmbeddedJSON(b)
+ enc.AddEmbeddedJSONKey(field.Key, &embed)
+
+ case logr.StringerType, logr.ErrorType, logr.TimestampMillisType, logr.TimeType, logr.DurationType, logr.BinaryType:
+ var buf strings.Builder
+ _ = field.ValueString(&buf, nil)
+ enc.AddStringKey(field.Key, buf.String())
+
+ case logr.Int64Type, logr.Int32Type, logr.IntType:
+ enc.AddInt64Key(field.Key, field.Integer)
+
+ case logr.Uint64Type, logr.Uint32Type, logr.UintType:
+ enc.AddUint64Key(field.Key, uint64(field.Integer))
+
+ case logr.Float64Type, logr.Float32Type:
+ enc.AddFloat64Key(field.Key, field.Float)
+
+ default:
+ return fmt.Errorf("invalid field type: %d", field.Type)
+ }
+ return nil
+}
diff --git a/vendor/github.com/mattermost/logr/v2/formatters/plain.go b/vendor/github.com/mattermost/logr/v2/formatters/plain.go
new file mode 100644
index 00000000..4d8af643
--- /dev/null
+++ b/vendor/github.com/mattermost/logr/v2/formatters/plain.go
@@ -0,0 +1,146 @@
+package formatters
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+
+ "github.com/mattermost/logr/v2"
+)
+
+// Plain is the simplest formatter, outputting only text with
+// no colors.
+type Plain struct {
+ // DisableTimestamp disables output of timestamp field.
+ DisableTimestamp bool `json:"disable_timestamp"`
+ // DisableLevel disables output of level field.
+ DisableLevel bool `json:"disable_level"`
+ // DisableMsg disables output of msg field.
+ DisableMsg bool `json:"disable_msg"`
+ // DisableFields disables output of all fields.
+ DisableFields bool `json:"disable_fields"`
+ // DisableStacktrace disables output of stack trace.
+ DisableStacktrace bool `json:"disable_stacktrace"`
+ // EnableCaller enables output of the file and line number that emitted a log record.
+ EnableCaller bool `json:"enable_caller"`
+
+ // Delim is an optional delimiter output between each log field.
+ // Defaults to a single space.
+ Delim string `json:"delim"`
+
+ // MinLevelLen sets the minimum level name length. If the level name is less
+ // than the minimum it will be padded with spaces.
+ MinLevelLen int `json:"min_level_len"`
+
+ // MinMessageLen sets the minimum msg length. If the msg text is less
+ // than the minimum it will be padded with spaces.
+ MinMessageLen int `json:"min_msg_len"`
+
+ // TimestampFormat is an optional format for timestamps. If empty
+ // then DefTimestampFormat is used.
+ TimestampFormat string `json:"timestamp_format"`
+
+ // LineEnd sets the end of line character(s). Defaults to '\n'.
+ LineEnd string `json:"line_end"`
+
+ // EnableColor sets whether output should include color.
+ EnableColor bool `json:"enable_color"`
+}
+
+func (p *Plain) CheckValid() error {
+ if p.MinMessageLen < 0 || p.MinMessageLen > 1024 {
+ return fmt.Errorf("min_msg_len is invalid(%d)", p.MinMessageLen)
+ }
+ return nil
+}
+
+// IsStacktraceNeeded returns true if a stacktrace is needed so we can output the `Caller` field.
+func (p *Plain) IsStacktraceNeeded() bool {
+ return p.EnableCaller
+}
+
+// Format converts a log record to bytes.
+func (p *Plain) Format(rec *logr.LogRec, level logr.Level, buf *bytes.Buffer) (*bytes.Buffer, error) {
+ delim := p.Delim
+ if delim == "" {
+ delim = " "
+ }
+ if buf == nil {
+ buf = &bytes.Buffer{}
+ }
+
+ timestampFmt := p.TimestampFormat
+ if timestampFmt == "" {
+ timestampFmt = logr.DefTimestampFormat
+ }
+
+ color := logr.NoColor
+ if p.EnableColor {
+ color = level.Color
+ }
+
+ if !p.DisableLevel {
+ _ = logr.WriteWithColor(buf, level.Name, color)
+ count := len(level.Name)
+ if p.MinLevelLen > count {
+ _, _ = buf.WriteString(strings.Repeat(" ", p.MinLevelLen-count))
+ }
+ buf.WriteString(delim)
+ }
+
+ if !p.DisableTimestamp {
+ var arr [128]byte
+ tbuf := rec.Time().AppendFormat(arr[:0], timestampFmt)
+ buf.WriteByte('[')
+ buf.Write(tbuf)
+ buf.WriteByte(']')
+ buf.WriteString(delim)
+ }
+
+ if !p.DisableMsg {
+ count, _ := buf.WriteString(rec.Msg())
+ if p.MinMessageLen > count {
+ _, _ = buf.WriteString(strings.Repeat(" ", p.MinMessageLen-count))
+ }
+ _, _ = buf.WriteString(delim)
+ }
+
+ var fields []logr.Field
+
+ if p.EnableCaller {
+ fld := logr.Field{
+ Key: "caller",
+ Type: logr.StringType,
+ String: rec.Caller(),
+ }
+ fields = append(fields, fld)
+ }
+
+ if !p.DisableFields {
+ fields = append(fields, rec.Fields()...)
+ }
+
+ if len(fields) > 0 {
+ if err := logr.WriteFields(buf, fields, logr.Space, color); err != nil {
+ return nil, err
+ }
+ }
+
+ if level.Stacktrace && !p.DisableStacktrace {
+ frames := rec.StackFrames()
+ if len(frames) > 0 {
+ buf.WriteString("\n")
+ if err := logr.WriteStacktrace(buf, rec.StackFrames()); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ if p.LineEnd == "" {
+ buf.WriteString("\n")
+ } else {
+ buf.WriteString(p.LineEnd)
+ }
+
+ return buf, nil
+}