github.com/netdata/go.d.plugin@v0.58.1/pkg/logs/ltsv.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package logs 4 5 import ( 6 "bufio" 7 "errors" 8 "fmt" 9 "io" 10 "strconv" 11 "unsafe" 12 13 "github.com/Wing924/ltsv" 14 ) 15 16 type ( 17 LTSVConfig struct { 18 FieldDelimiter string `yaml:"field_delimiter"` 19 ValueDelimiter string `yaml:"value_delimiter"` 20 Mapping map[string]string `yaml:"mapping"` 21 } 22 23 LTSVParser struct { 24 r *bufio.Reader 25 parser ltsv.Parser 26 mapping map[string]string 27 } 28 ) 29 30 func NewLTSVParser(config LTSVConfig, in io.Reader) (*LTSVParser, error) { 31 p := ltsv.Parser{ 32 FieldDelimiter: ltsv.DefaultParser.FieldDelimiter, 33 ValueDelimiter: ltsv.DefaultParser.ValueDelimiter, 34 StrictMode: false, 35 } 36 if config.FieldDelimiter != "" { 37 if d, err := parseLTSVDelimiter(config.FieldDelimiter); err == nil { 38 p.FieldDelimiter = d 39 } 40 } 41 if config.ValueDelimiter != "" { 42 if d, err := parseLTSVDelimiter(config.ValueDelimiter); err == nil { 43 p.ValueDelimiter = d 44 } 45 } 46 parser := <SVParser{ 47 r: bufio.NewReader(in), 48 parser: p, 49 mapping: config.Mapping, 50 } 51 return parser, nil 52 } 53 54 func (p *LTSVParser) ReadLine(line LogLine) error { 55 row, err := p.r.ReadSlice('\n') 56 if err != nil && len(row) == 0 { 57 return err 58 } 59 if len(row) > 0 && row[len(row)-1] == '\n' { 60 row = row[:len(row)-1] 61 } 62 return p.Parse(row, line) 63 } 64 65 func (p *LTSVParser) Parse(row []byte, line LogLine) error { 66 err := p.parser.ParseLine(row, func(label []byte, value []byte) error { 67 s := *(*string)(unsafe.Pointer(&label)) // no alloc, same as in fmt.Builder.String() 68 if v, ok := p.mapping[s]; ok { 69 s = v 70 } 71 return line.Assign(s, string(value)) 72 }) 73 if err != nil { 74 return &ParseError{msg: fmt.Sprintf("ltsv parse: %v", err), err: err} 75 } 76 return nil 77 } 78 79 func (p LTSVParser) Info() string { 80 return fmt.Sprintf("ltsv: %q", p.mapping) 81 } 82 83 func parseLTSVDelimiter(s string) (byte, error) { 84 if isNumber(s) { 85 d, err := strconv.ParseUint(s, 10, 8) 86 if err != nil { 87 return 0, fmt.Errorf("invalid LTSV delimiter: %v", err) 88 } 89 return byte(d), nil 90 } 91 if len(s) != 1 { 92 return 0, errors.New("invalid LTSV delimiter: must be a single character") 93 } 94 return s[0], nil 95 }