github.com/netdata/go.d.plugin@v0.58.1/pkg/logs/regexp.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 "regexp" 11 ) 12 13 type ( 14 RegExpConfig struct { 15 Pattern string `yaml:"pattern"` 16 } 17 18 RegExpParser struct { 19 r *bufio.Reader 20 pattern *regexp.Regexp 21 } 22 ) 23 24 func NewRegExpParser(config RegExpConfig, in io.Reader) (*RegExpParser, error) { 25 if config.Pattern == "" { 26 return nil, errors.New("empty pattern") 27 } 28 29 pattern, err := regexp.Compile(config.Pattern) 30 if err != nil { 31 return nil, fmt.Errorf("compile: %w", err) 32 } 33 34 if pattern.NumSubexp() == 0 { 35 return nil, errors.New("pattern has no named subgroups") 36 } 37 38 p := &RegExpParser{ 39 r: bufio.NewReader(in), 40 pattern: pattern, 41 } 42 return p, nil 43 } 44 45 func (p *RegExpParser) ReadLine(line LogLine) error { 46 row, err := p.r.ReadSlice('\n') 47 if err != nil && len(row) == 0 { 48 return err 49 } 50 if len(row) > 0 && row[len(row)-1] == '\n' { 51 row = row[:len(row)-1] 52 } 53 return p.Parse(row, line) 54 } 55 56 func (p *RegExpParser) Parse(row []byte, line LogLine) error { 57 match := p.pattern.FindSubmatch(row) 58 if len(match) == 0 { 59 return &ParseError{msg: "regexp parse: unmatched line"} 60 } 61 62 for i, name := range p.pattern.SubexpNames() { 63 if name == "" || match[i] == nil { 64 continue 65 } 66 err := line.Assign(name, string(match[i])) 67 if err != nil { 68 return &ParseError{msg: fmt.Sprintf("regexp parse: %v", err), err: err} 69 } 70 } 71 return nil 72 } 73 74 func (p RegExpParser) Info() string { 75 return fmt.Sprintf("regexp: %s", p.pattern) 76 }