in processors/dissect/dissect.go [103:180]
func (d *Dissector) extract(s string) (positions, error) {
positions := make([]position, len(d.parser.fields))
var i, start, lookahead, end int
// Position on the first delimiter, we assume a hard match on the first delimiter.
// Previous version of dissect was doing a lookahead in the string until it can find the delimiter,
// LS and Beats now have the same behavior and this is consistent with the principle of least
// surprise.
dl := d.parser.delimiters[0]
offset := dl.IndexOf(s, 0)
if offset == -1 || offset != 0 {
return nil, fmt.Errorf(
"could not find beginning delimiter: `%s` in remaining: `%s`, (offset: %d)",
dl.Delimiter(), s, 0,
)
}
offset += dl.Len()
// move through all the other delimiters, until we have consumed all of them.
for dl.Next() != nil {
start = offset
// corresponding field of the delimiter
field := d.parser.fields[d.parser.fieldsIDMap[i]]
// for fixed-length field, just step the same size of its length
if field.IsFixedLength() {
end = offset + field.Length()
if end > len(s) {
return nil, fmt.Errorf(
"field length is grater than string length: remaining: `%s`, (offset: %d), field: %s",
s[offset:], offset, field,
)
}
} else {
end = dl.Next().IndexOf(s, offset)
if end == -1 {
return nil, fmt.Errorf(
"could not find delimiter: `%s` in remaining: `%s`, (offset: %d)",
dl.Delimiter(), s[offset:], offset,
)
}
}
offset = end
// Greedy consumes keys defined with padding.
// Keys are defined with `->` suffix.
if dl.IsGreedy() {
for {
lookahead = dl.Next().IndexOf(s, offset+1)
if lookahead != offset+1 {
break
} else {
offset = lookahead
}
}
}
positions[i] = position{start: start, end: end}
offset += dl.Next().Len()
i++
dl = dl.Next()
}
field := d.parser.fields[d.parser.fieldsIDMap[i]]
if field.IsFixedLength() && offset+field.Length() != len(s) {
return nil, fmt.Errorf("last fixed length key `%s` (length: %d) does not fit into remaining: `%s`, (offset: %d)",
field, field.Length(), s, offset,
)
}
// If we have remaining contents and have not captured all the requested fields
if offset < len(s) && i < len(d.parser.fields) {
positions[i] = position{start: offset, end: len(s)}
}
return positions, nil
}