in plugins/parsers/grok/parser.go [196:378]
func (p *Parser) ParseLine(line string) (telegraf.Metric, error) {
var err error
// values are the parsed fields from the log line
var values map[string]string
// the matching pattern string
var patternName string
for _, pattern := range p.NamedPatterns {
if values, err = p.g.Parse(pattern, line); err != nil {
return nil, err
}
if len(values) != 0 {
patternName = pattern
break
}
}
if len(values) == 0 {
p.Log.Debugf("Grok no match found for: %q", line)
return nil, nil
}
fields := make(map[string]interface{})
tags := make(map[string]string)
//add default tags
for k, v := range p.DefaultTags {
tags[k] = v
}
timestamp := time.Now()
for k, v := range values {
if k == "" || v == "" {
continue
}
// t is the modifier of the field
var t string
// check if pattern has some modifiers
if types, ok := p.typeMap[patternName]; ok {
t = types[k]
}
// if we didn't find a modifier, check if we have a timestamp layout
if t == "" {
if ts, ok := p.tsMap[patternName]; ok {
// check if the modifier is a timestamp layout
if layout, ok := ts[k]; ok {
t = layout
}
}
}
// if we didn't find a type OR timestamp modifier, assume string
if t == "" {
t = String
}
switch t {
case Measurement:
p.Measurement = v
case Int:
iv, err := strconv.ParseInt(v, 0, 64)
if err != nil {
p.Log.Errorf("Error parsing %s to int: %s", v, err)
} else {
fields[k] = iv
}
case Float:
fv, err := strconv.ParseFloat(v, 64)
if err != nil {
p.Log.Errorf("Error parsing %s to float: %s", v, err)
} else {
fields[k] = fv
}
case Duration:
d, err := time.ParseDuration(v)
if err != nil {
p.Log.Errorf("Error parsing %s to duration: %s", v, err)
} else {
fields[k] = int64(d)
}
case Tag:
tags[k] = v
case String:
fields[k] = v
case Epoch:
parts := strings.SplitN(v, ".", 2)
if len(parts) == 0 {
p.Log.Errorf("Error parsing %s to timestamp: %s", v, err)
break
}
sec, err := strconv.ParseInt(parts[0], 10, 64)
if err != nil {
p.Log.Errorf("Error parsing %s to timestamp: %s", v, err)
break
}
ts := time.Unix(sec, 0)
if len(parts) == 2 {
padded := fmt.Sprintf("%-9s", parts[1])
nsString := strings.Replace(padded[:9], " ", "0", -1)
nanosec, err := strconv.ParseInt(nsString, 10, 64)
if err != nil {
p.Log.Errorf("Error parsing %s to timestamp: %s", v, err)
break
}
ts = ts.Add(time.Duration(nanosec) * time.Nanosecond)
}
timestamp = ts
case EpochMilli:
ms, err := strconv.ParseInt(v, 10, 64)
if err != nil {
p.Log.Errorf("Error parsing %s to int: %s", v, err)
} else {
timestamp = time.Unix(0, ms*int64(time.Millisecond))
}
case EpochNano:
iv, err := strconv.ParseInt(v, 10, 64)
if err != nil {
p.Log.Errorf("Error parsing %s to int: %s", v, err)
} else {
timestamp = time.Unix(0, iv)
}
case SyslogTimestamp:
ts, err := time.ParseInLocation(time.Stamp, v, p.loc)
if err == nil {
if ts.Year() == 0 {
ts = ts.AddDate(timestamp.Year(), 0, 0)
}
timestamp = ts
} else {
p.Log.Errorf("Error parsing %s to time layout [%s]: %s", v, t, err)
}
case GenericTimestamp:
var foundTs bool
// first try timestamp layouts that we've already found
for _, layout := range p.foundTsLayouts {
ts, err := time.ParseInLocation(layout, v, p.loc)
if err == nil {
timestamp = ts
foundTs = true
break
}
}
// if we haven't found a timestamp layout yet, try all timestamp
// layouts.
if !foundTs {
for _, layout := range timeLayouts {
ts, err := time.ParseInLocation(layout, v, p.loc)
if err == nil {
timestamp = ts
foundTs = true
p.foundTsLayouts = append(p.foundTsLayouts, layout)
break
}
}
}
// if we still haven't found a timestamp layout, log it and we will
// just use time.Now()
if !foundTs {
p.Log.Errorf("Error parsing timestamp [%s], could not find any "+
"suitable time layouts.", v)
}
case Drop:
// goodbye!
default:
v = strings.Replace(v, ",", ".", -1)
ts, err := time.ParseInLocation(t, v, p.loc)
if err == nil {
if ts.Year() == 0 {
ts = ts.AddDate(timestamp.Year(), 0, 0)
}
timestamp = ts
} else {
p.Log.Errorf("Error parsing %s to time layout [%s]: %s", v, t, err)
}
}
}
if p.UniqueTimestamp != "auto" {
return metric.New(p.Measurement, tags, fields, timestamp), nil
}
return metric.New(p.Measurement, tags, fields, p.tsModder.tsMod(timestamp)), nil
}