Like Prometheus, but for logs.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
loki/pkg/logql/log/pattern/pattern.go

95 lines
1.7 KiB

package pattern
import (
"bytes"
"errors"
)
var (
ErrNoCapture = errors.New("at least one capture is required")
ErrInvalidExpr = errors.New("invalid expression")
)
type Matcher interface {
Matches(in []byte) [][]byte
Names() []string
}
type matcher struct {
e expr
captures [][]byte
names []string
}
func New(in string) (Matcher, error) {
e, err := parseExpr(in)
if err != nil {
return nil, err
}
if err := e.validate(); err != nil {
return nil, err
}
return &matcher{
e: e,
captures: make([][]byte, 0, e.captureCount()),
names: e.captures(),
}, nil
}
// Matches matches the given line with the provided pattern.
// Matches invalidates the previous returned captures array.
func (m *matcher) Matches(in []byte) [][]byte {
if len(in) == 0 {
return nil
}
if len(m.e) == 0 {
return nil
}
captures := m.captures[:0]
expr := m.e
if ls, ok := expr[0].(literals); ok {
i := bytes.Index(in, ls)
if i != 0 {
return nil
}
in = in[len(ls):]
expr = expr[1:]
}
if len(expr) == 0 {
return nil
}
// from now we have capture - literals - capture ... (literals)?
for len(expr) != 0 {
if len(expr) == 1 { // we're ending on a capture.
if !(expr[0].(capture)).isUnamed() {
captures = append(captures, in)
}
return captures
}
cap := expr[0].(capture)
ls := expr[1].(literals)
expr = expr[2:]
i := bytes.Index(in, ls)
if i == -1 {
// if a capture is missed we return up to the end as the capture.
if !cap.isUnamed() {
captures = append(captures, in)
}
return captures
}
if cap.isUnamed() {
in = in[len(ls)+i:]
continue
}
captures = append(captures, in[:i])
in = in[len(ls)+i:]
}
return captures
}
func (m *matcher) Names() []string {
return m.names
}