@@ -6,6 +6,10 @@ import (
66 "time"
77)
88
9+ var (
10+ unclassifiedPatternLabel = "unclassified pattern (pattern limit reached)"
11+ )
12+
913type LogEntry struct {
1014 Timestamp time.Time
1115 Content string
@@ -22,8 +26,10 @@ type LogCounter struct {
2226type Parser struct {
2327 decoder Decoder
2428
25- patterns map [patternKey ]* patternStat
26- lock sync.RWMutex
29+ patterns map [patternKey ]* patternStat
30+ patternsPerLevel map [Level ]int
31+ patternsPerLevelLimit int
32+ lock sync.RWMutex
2733
2834 multilineCollector * MultilineCollector
2935
@@ -34,11 +40,13 @@ type Parser struct {
3440
3541type OnMsgCallbackF func (ts time.Time , level Level , patternHash string , msg string )
3642
37- func NewParser (ch <- chan LogEntry , decoder Decoder , onMsgCallback OnMsgCallbackF , multilineCollectorTimeout time.Duration ) * Parser {
43+ func NewParser (ch <- chan LogEntry , decoder Decoder , onMsgCallback OnMsgCallbackF , multilineCollectorTimeout time.Duration , patternsPerLevelLimit int ) * Parser {
3844 p := & Parser {
39- decoder : decoder ,
40- patterns : map [patternKey ]* patternStat {},
41- onMsgCb : onMsgCallback ,
45+ decoder : decoder ,
46+ patterns : map [patternKey ]* patternStat {},
47+ patternsPerLevel : map [Level ]int {},
48+ patternsPerLevelLimit : patternsPerLevelLimit ,
49+ onMsgCb : onMsgCallback ,
4250 }
4351 ctx , stop := context .WithCancel (context .Background ())
4452 p .stop = stop
@@ -96,26 +104,43 @@ func (p *Parser) inc(msg Message) {
96104 }
97105
98106 pattern := NewPattern (msg .Content )
99- key := patternKey {level : msg .Level , hash : pattern .Hash ()}
100- stat := p .patterns [key ]
101- if stat == nil {
102- for k , ps := range p .patterns {
103- if k .level == msg .Level && ps .pattern .WeakEqual (pattern ) {
104- stat = ps
105- break
106- }
107- }
108- if stat == nil {
109- stat = & patternStat {pattern : pattern , sample : msg .Content }
110- p .patterns [key ] = stat
111- }
112- }
107+ stat , key := p .getPatternStat (msg .Level , pattern , msg .Content )
113108 if p .onMsgCb != nil {
114109 p .onMsgCb (msg .Timestamp , msg .Level , key .hash , msg .Content )
115110 }
116111 stat .messages ++
117112}
118113
114+ func (p * Parser ) getPatternStat (level Level , pattern * Pattern , sample string ) (* patternStat , patternKey ) {
115+ key := patternKey {level : level , hash : pattern .Hash ()}
116+ if stat := p .patterns [key ]; stat != nil {
117+ return stat , key
118+ }
119+ for k , ps := range p .patterns {
120+ if k .level != level || ps .pattern == nil {
121+ continue
122+ }
123+ if ps .pattern .WeakEqual (pattern ) {
124+ return ps , k
125+ }
126+ }
127+
128+ if p .patternsPerLevel [level ] >= p .patternsPerLevelLimit {
129+ fallbackKey := patternKey {level : level , hash : "" }
130+ stat := p .patterns [fallbackKey ]
131+ if stat == nil {
132+ stat = & patternStat {sample : unclassifiedPatternLabel }
133+ p .patterns [fallbackKey ] = stat
134+ }
135+ return stat , fallbackKey
136+ }
137+
138+ stat := & patternStat {pattern : pattern , sample : sample }
139+ p .patterns [key ] = stat
140+ p .patternsPerLevel [level ]++
141+ return stat , key
142+ }
143+
119144func (p * Parser ) GetCounters () []LogCounter {
120145 p .lock .RLock ()
121146 defer p .lock .RUnlock ()
0 commit comments