plugins/input/syslog/parser.go (158 lines of code) (raw):

// Copyright 2021 iLogtail Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package inputsyslog import ( "errors" "time" "github.com/alibaba/ilogtail/pkg/util" "github.com/influxdata/go-syslog/rfc5424" "github.com/jeromer/syslogparser/rfc3164" ) type parseResult struct { hostname string program string priority int facility int severity int time time.Time content string // RFC5424 procID *string msgID *string structuredData *map[string]map[string]string } func newParseResult() *parseResult { return &parseResult{ hostname: "", program: "", priority: -1, facility: -1, severity: -1, time: time.Now(), content: "", } } type parser interface { // Parse parses @data to parseResult according to the protocol of parser. // If it parses failed but failField in parserConfig is set, it will set the // content of @data to this field and returns no error. // It returns parseResult and any error encountered. Parse(data []byte) (*parseResult, error) } type parserConfig struct { ignoreParseFailure bool addHostname bool } type parserCreator func(config *parserConfig) parser var syslogParsers = map[string]parserCreator{} // defaultParser does not parse. type defaultParser struct{} func newDefaultParser(config *parserConfig) parser { return &defaultParser{} } func (p *defaultParser) Parse(data []byte) (*parseResult, error) { pr := newParseResult() pr.content = string(data) return pr, nil } type rfc3164Parser struct { config *parserConfig } func newRfc3164Parser(config *parserConfig) parser { return &rfc3164Parser{config: config} } func (p *rfc3164Parser) Parse(data []byte) (*parseResult, error) { pp := rfc3164.NewParser(data) pp.Location(time.Local) // if hostname field is not included in log, add os.Hostname for parser default hostname if p.config.addHostname { pp.Hostname(util.GetHostName()) } err := pp.Parse() if err != nil { if !p.config.ignoreParseFailure { return nil, err } pr := newParseResult() pr.content = string(data) return pr, nil } rfc3164Pr := pp.DumpParseResult() pr := newParseResult() pr.hostname = rfc3164Pr.Hostname pr.program = rfc3164Pr.Tag pr.priority = rfc3164Pr.Priority pr.facility = rfc3164Pr.Facility pr.severity = rfc3164Pr.Severity pr.time = rfc3164Pr.Timestamp pr.content = rfc3164Pr.Content return pr, nil } type rfc5424Parser struct { config *parserConfig parser *rfc5424.Parser } func newRfc5424Parser(config *parserConfig) parser { return &rfc5424Parser{ config: config, parser: rfc5424.NewParser(), } } func (p *rfc5424Parser) Parse(data []byte) (*parseResult, error) { m, err := p.parser.Parse(data, nil) if err != nil { if !p.config.ignoreParseFailure { return nil, err } pr := newParseResult() pr.content = string(data) return pr, nil } pr := newParseResult() if m.Priority() != nil { pr.priority = int(*m.Priority()) } if m.Severity() != nil { pr.severity = int(*m.Severity()) } if m.Facility() != nil { pr.facility = int(*m.Facility()) } if m.Hostname() != nil { pr.hostname = *m.Hostname() } if m.Appname() != nil { pr.program = *m.Appname() } if m.Message() != nil { pr.content = *m.Message() } if m.Timestamp() != nil { pr.time = *m.Timestamp() } pr.procID = m.ProcID() pr.msgID = m.MsgID() pr.structuredData = m.StructuredData() return pr, nil } // autoParser use all available parsers to try to parse data. type autoParser struct { parsers []parser config *parserConfig } func newAutoParser(config *parserConfig) parser { p := &autoParser{config: config} p.parsers = append(p.parsers, newRfc3164Parser(config)) p.parsers = append(p.parsers, newRfc5424Parser(config)) return p } func (p *autoParser) Parse(data []byte) (pr *parseResult, err error) { for _, realParser := range p.parsers { pr, err = realParser.Parse(data) if err == nil { return pr, nil } } if !p.config.ignoreParseFailure { return nil, errors.New("No available parser can parse: " + string(data)) } pr = newParseResult() pr.content = string(data) return pr, nil } func init() { syslogParsers[""] = newDefaultParser syslogParsers["rfc3164"] = newRfc3164Parser syslogParsers["rfc5424"] = newRfc5424Parser syslogParsers["auto"] = newAutoParser }