github.com/netdata/go.d.plugin@v0.58.1/pkg/logs/json.go (about) 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"` 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 }