diff --git a/pkg/systemlogmonitor/log_buffer.go b/pkg/systemlogmonitor/log_buffer.go index ed847de6..f86ec8f7 100644 --- a/pkg/systemlogmonitor/log_buffer.go +++ b/pkg/systemlogmonitor/log_buffer.go @@ -39,6 +39,8 @@ type logBuffer struct { msg []string max int current int + // regexps caches compiled regular expressions. + regexps map[string]*regexp.Regexp } // NewLogBuffer creates log buffer with max line number limit. Because we only match logs @@ -47,9 +49,10 @@ type logBuffer struct { // lines of patterns we support. func NewLogBuffer(maxLines int) *logBuffer { return &logBuffer{ - buffer: make([]*types.Log, maxLines), - msg: make([]string, maxLines), - max: maxLines, + buffer: make([]*types.Log, maxLines), + msg: make([]string, maxLines), + max: maxLines, + regexps: make(map[string]*regexp.Regexp), } } @@ -59,10 +62,13 @@ func (b *logBuffer) Push(log *types.Log) { b.current++ } -// TODO(random-liu): Cache regexp if garbage collection becomes a problem someday. func (b *logBuffer) Match(expr string) []*types.Log { // The expression should be checked outside, and it must match to the end. - reg := regexp.MustCompile(expr + `\z`) + reg, ok := b.regexps[expr] + if !ok { + reg = regexp.MustCompile(expr + `\z`) + b.regexps[expr] = reg + } log := b.String() loc := reg.FindStringIndex(log) if loc == nil { diff --git a/pkg/systemlogmonitor/log_buffer_test.go b/pkg/systemlogmonitor/log_buffer_test.go index 895a655f..b824e4c2 100644 --- a/pkg/systemlogmonitor/log_buffer_test.go +++ b/pkg/systemlogmonitor/log_buffer_test.go @@ -108,3 +108,17 @@ func TestMatch(t *testing.T) { } } } + +func BenchmarkMatch(b *testing.B) { + buf := NewLogBuffer(10) + for i := 0; i < 10; i++ { + buf.Push(&types.Log{Message: "Out of memory: Kill process 20744 (mysqld) score 318 or sacrifice child"}) + } + // A pattern from the default kernel monitor configuration which does not + // match the buffered logs. + expr := `task [\S ]+:\w+ blocked for more than \w+ seconds\.` + b.ResetTimer() + for i := 0; i < b.N; i++ { + buf.Match(expr) + } +}