master
go 140 lines 2.69 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package logs
4
5 import (
6 "bufio"
7 "fmt"
8 "io"
9 "strconv"
10
11 "github.com/valyala/fastjson"
12 )
13
14 type JSONConfig struct {
15 Mapping map[string]string `yaml:"mapping" json:"mapping"`
16 }
17
18 type JSONParser struct {
19 reader *bufio.Reader
20 parser fastjson.Parser
21 buf []byte
22 mapping map[string]string
23 }
24
25 func NewJSONParser(config JSONConfig, in io.Reader) (*JSONParser, error) {
26 parser := &JSONParser{
27 reader: bufio.NewReader(in),
28 mapping: config.Mapping,
29 buf: make([]byte, 0, 100),
30 }
31 return parser, nil
32 }
33
34 func (p *JSONParser) ReadLine(line LogLine) error {
35 row, err := p.reader.ReadSlice('\n')
36 if err != nil && len(row) == 0 {
37 return err
38 }
39 if len(row) > 0 && row[len(row)-1] == '\n' {
40 row = row[:len(row)-1]
41 }
42 return p.Parse(row, line)
43 }
44
45 func (p *JSONParser) Parse(row []byte, line LogLine) error {
46 val, err := p.parser.ParseBytes(row)
47 if err != nil {
48 return err
49 }
50
51 if err := p.parseObject("", val, line); err != nil {
52 return &ParseError{msg: fmt.Sprintf("json parse: %v", err), err: err}
53 }
54
55 return nil
56 }
57
58 func (p *JSONParser) parseObject(prefix string, val *fastjson.Value, line LogLine) error {
59 obj, err := val.Object()
60 if err != nil {
61 return err
62 }
63
64 obj.Visit(func(key []byte, v *fastjson.Value) {
65 if err != nil {
66 return
67 }
68
69 k := jsonObjKey(prefix, string(key))
70
71 switch v.Type() {
72 case fastjson.TypeString, fastjson.TypeNumber:
73 err = p.parseStringNumber(k, v, line)
74 case fastjson.TypeArray:
75 err = p.parseArray(k, v, line)
76 case fastjson.TypeObject:
77 err = p.parseObject(k, v, line)
78 default:
79 return
80 }
81 })
82
83 return err
84 }
85
86 func jsonObjKey(prefix, key string) string {
87 if prefix == "" {
88 return key
89 }
90 return prefix + "." + key
91 }
92
93 func (p *JSONParser) parseArray(key string, val *fastjson.Value, line LogLine) error {
94 arr, err := val.Array()
95 if err != nil {
96 return err
97 }
98
99 for i, v := range arr {
100 k := jsonObjKey(key, strconv.Itoa(i))
101
102 switch v.Type() {
103 case fastjson.TypeString, fastjson.TypeNumber:
104 err = p.parseStringNumber(k, v, line)
105 case fastjson.TypeArray:
106 err = p.parseArray(k, v, line)
107 case fastjson.TypeObject:
108 err = p.parseObject(k, v, line)
109 default:
110 continue
111 }
112
113 if err != nil {
114 return err
115 }
116 }
117
118 return err
119 }
120
121 func (p *JSONParser) parseStringNumber(key string, val *fastjson.Value, line LogLine) error {
122 if mapped, ok := p.mapping[key]; ok {
123 key = mapped
124 }
125
126 p.buf = p.buf[:0]
127 if p.buf = val.MarshalTo(p.buf); len(p.buf) == 0 {
128 return nil
129 }
130
131 if val.Type() == fastjson.TypeString {
132 // trim "
133 return line.Assign(key, string(p.buf[1:len(p.buf)-1]))
134 }
135 return line.Assign(key, string(p.buf))
136 }
137
138 func (p *JSONParser) Info() string {
139 return fmt.Sprintf("json: %q", p.mapping)
140 }