123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- package gonx
- import (
- "bufio"
- "fmt"
- "io"
- "regexp"
- "strings"
- )
- // StringParser is the interface that wraps the ParseString method.
- type StringParser interface {
- ParseString(line string) (entry *Entry, err error)
- }
- // Parser is a log record parser. Use specific constructors to initialize it.
- type Parser struct {
- format string
- regexp *regexp.Regexp
- }
- // NewParser returns a new Parser, use given log format to create its internal
- // strings parsing regexp.
- func NewParser(format string) *Parser {
- re := regexp.MustCompile(`\\\$([a-z_]+)(\\?(.))`).ReplaceAllString(
- regexp.QuoteMeta(format+" "), "(?P<$1>[^$3]*)$2")
- return &Parser{format, regexp.MustCompile(fmt.Sprintf("^%v", strings.Trim(re, " ")))}
- }
- // ParseString parses a log file line using internal format regexp. If a line
- // does not match the given format an error will be returned.
- func (parser *Parser) ParseString(line string) (entry *Entry, err error) {
- re := parser.regexp
- fields := re.FindStringSubmatch(line)
- if fields == nil {
- err = fmt.Errorf("access log line '%v' does not match given format '%v'", line, re)
- return
- }
- // Iterate over subexp foung and fill the map record
- entry = NewEmptyEntry()
- for i, name := range re.SubexpNames() {
- if i == 0 {
- continue
- }
- entry.SetField(name, fields[i])
- }
- return
- }
- // NewNginxParser parses the nginx conf file to find log_format with the given
- // name and returns a parser for this format. It returns an error if cannot find
- // the given log format.
- func NewNginxParser(conf io.Reader, name string) (parser *Parser, err error) {
- scanner := bufio.NewScanner(conf)
- re := regexp.MustCompile(fmt.Sprintf(`^\s*log_format\s+%v\s+(.+)\s*$`, name))
- found := false
- var format string
- for scanner.Scan() {
- var line string
- if !found {
- // Find a log_format definition
- line = scanner.Text()
- formatDef := re.FindStringSubmatch(line)
- if formatDef == nil {
- continue
- }
- found = true
- line = formatDef[1]
- } else {
- line = scanner.Text()
- }
- // Look for a definition end
- re = regexp.MustCompile(`^\s*(.*?)\s*(;|$)`)
- lineSplit := re.FindStringSubmatch(line)
- if l := len(lineSplit[1]); l > 2 {
- format += lineSplit[1][1 : l-1]
- }
- if lineSplit[2] == ";" {
- break
- }
- }
- if !found {
- err = fmt.Errorf("`log_format %v` not found in given config", name)
- } else {
- err = scanner.Err()
- }
- parser = NewParser(format)
- return
- }
|