Precompile log buffer regular expressions

Compile fixed patterns during monitor and log counter initialization, pass compiled expressions to the log buffer, and reject invalid log counter patterns before watching logs.
This commit is contained in:
Ciprian Hacman
2026-07-25 09:21:31 +03:00
parent 3b47d535b6
commit b02e2dcd09
6 changed files with 103 additions and 33 deletions
+18 -5
View File
@@ -21,6 +21,7 @@ package logcounter
import (
"fmt"
"regexp"
"time"
"k8s.io/utils/clock"
@@ -42,12 +43,24 @@ const (
type logCounter struct {
logCh <-chan *systemtypes.Log
buffer systemlogmonitor.LogBuffer
pattern string
revertPattern string
pattern *regexp.Regexp
revertPattern *regexp.Regexp
clock clock.Clock
}
func NewJournaldLogCounter(options *options.LogCounterOptions) (types.LogCounter, error) {
pattern, err := systemlogmonitor.CompilePattern(options.Pattern)
if err != nil {
return nil, fmt.Errorf("invalid pattern %q: %w", options.Pattern, err)
}
var revertPattern *regexp.Regexp
if options.RevertPattern != "" {
revertPattern, err = systemlogmonitor.CompilePattern(options.RevertPattern)
if err != nil {
return nil, fmt.Errorf("invalid revert pattern %q: %w", options.RevertPattern, err)
}
}
watcher := journald.NewJournaldWatcher(watchertypes.WatcherConfig{
Plugin: "journald",
PluginConfig: map[string]string{journaldSourceKey: options.JournaldSource},
@@ -62,8 +75,8 @@ func NewJournaldLogCounter(options *options.LogCounterOptions) (types.LogCounter
return &logCounter{
logCh: logCh,
buffer: systemlogmonitor.NewLogBuffer(bufferSize),
pattern: options.Pattern,
revertPattern: options.RevertPattern,
pattern: pattern,
revertPattern: revertPattern,
clock: clock.RealClock{},
}, nil
}
@@ -86,7 +99,7 @@ func (e *logCounter) Count() (count int, err error) {
if len(e.buffer.Match(e.pattern)) != 0 {
count++
}
if e.revertPattern != "" && len(e.buffer.Match(e.revertPattern)) != 0 {
if e.revertPattern != nil && len(e.buffer.Match(e.revertPattern)) != 0 {
count--
}
case <-e.clock.After(timeout):
+43 -3
View File
@@ -20,27 +20,67 @@ limitations under the License.
package logcounter
import (
"strings"
"testing"
"time"
testclock "k8s.io/utils/clock/testing"
"k8s.io/node-problem-detector/cmd/logcounter/options"
"k8s.io/node-problem-detector/pkg/logcounter/types"
"k8s.io/node-problem-detector/pkg/systemlogmonitor"
systemtypes "k8s.io/node-problem-detector/pkg/systemlogmonitor/types"
)
func NewTestLogCounter(pattern string, startTime time.Time) (types.LogCounter, *testclock.FakeClock, chan *systemtypes.Log) {
func newTestLogCounter(t *testing.T, pattern string, startTime time.Time) (types.LogCounter, *testclock.FakeClock, chan *systemtypes.Log) {
t.Helper()
compiledPattern, err := systemlogmonitor.CompilePattern(pattern)
if err != nil {
t.Fatalf("failed to compile pattern %q: %v", pattern, err)
}
logCh := make(chan *systemtypes.Log)
clock := testclock.NewFakeClock(startTime)
return &logCounter{
logCh: logCh,
buffer: systemlogmonitor.NewLogBuffer(bufferSize),
pattern: pattern,
pattern: compiledPattern,
clock: clock,
}, clock, logCh
}
func TestNewJournaldLogCounterRejectsInvalidPatterns(t *testing.T) {
for _, tc := range []struct {
name string
pattern string
revertPattern string
errorContains string
}{
{
name: "pattern",
pattern: "[",
errorContains: `invalid pattern "["`,
},
{
name: "revert pattern",
revertPattern: "[",
errorContains: `invalid revert pattern "["`,
},
} {
t.Run(tc.name, func(t *testing.T) {
_, err := NewJournaldLogCounter(&options.LogCounterOptions{
Pattern: tc.pattern,
RevertPattern: tc.revertPattern,
})
if err == nil {
t.Fatal("expected invalid pattern error")
}
if !strings.Contains(err.Error(), tc.errorContains) {
t.Errorf("expected error containing %q, got %q", tc.errorContains, err)
}
})
}
}
func TestCount(t *testing.T) {
startTime := time.Now()
for _, tc := range []struct {
@@ -113,7 +153,7 @@ func TestCount(t *testing.T) {
},
} {
t.Run(tc.description, func(t *testing.T) {
counter, fakeClock, logCh := NewTestLogCounter(tc.pattern, startTime)
counter, fakeClock, logCh := newTestLogCounter(t, tc.pattern, startTime)
go func(logs []*systemtypes.Log, ch chan<- *systemtypes.Log) {
for _, log := range logs {
ch <- log