-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathlogfmt_handler.go
More file actions
101 lines (91 loc) · 2.11 KB
/
logfmt_handler.go
File metadata and controls
101 lines (91 loc) · 2.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package humanlog
import (
"bytes"
"time"
"github.com/go-logfmt/logfmt"
typesv1 "github.com/minitape/api/go/types/v1"
"google.golang.org/protobuf/types/known/timestamppb"
)
// LogfmtHandler can handle logs emitted by logrus.TextFormatter loggers.
type LogfmtHandler struct {
Opts *HandlerOptions
Level string
Time time.Time
Message string
Fields []*typesv1.KV
}
func (h *LogfmtHandler) clear() {
h.Level = ""
h.Time = time.Time{}
h.Message = ""
h.Fields = nil
}
// CanHandle tells if this line can be handled by this handler.
func (h *LogfmtHandler) TryHandle(d []byte, out *typesv1.Log) bool {
if !bytes.ContainsRune(d, '=') {
return false
}
h.clear()
if !h.UnmarshalLogfmt(d) {
return false
}
if !h.Time.IsZero() {
out.Timestamp = timestamppb.New(h.Time)
}
out.Body = h.Message
out.SeverityText = h.Level
out.Attributes = h.Fields
return true
}
// HandleLogfmt sets the fields of the handler.
func (h *LogfmtHandler) UnmarshalLogfmt(data []byte) bool {
dec := logfmt.NewDecoder(bytes.NewReader(data))
for dec.ScanRecord() {
next_kv:
for dec.ScanKeyval() {
key := string(dec.Key())
val := string(dec.Value())
if h.Time.IsZero() {
foundTime := checkEachUntilFound(h.Opts.TimeFields, func(field string) bool {
if !fieldsEqualAllString(key, field) {
return false
}
time, ok := tryParseTime(val)
if ok {
h.Time = time
}
return ok
})
if foundTime {
continue next_kv
}
}
if len(h.Message) == 0 {
foundMessage := checkEachUntilFound(h.Opts.MessageFields, func(field string) bool {
if !fieldsEqualAllString(key, field) {
return false
}
h.Message = val
return true
})
if foundMessage {
continue next_kv
}
}
if len(h.Level) == 0 {
foundLevel := checkEachUntilFound(h.Opts.LevelFields, func(field string) bool {
if !fieldsEqualAllString(key, field) {
return false
}
h.Level = val
return true
})
if foundLevel {
continue next_kv
}
}
h.Fields = append(h.Fields, typesv1.KeyVal(key, typesv1.ValStr(val)))
}
}
return dec.Err() == nil
}