func()

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
}