P0-05: regexp.Compile错误被静默忽略 - extractMatch函数现在返回(string, error) - 正确处理regexp.Compile错误,返回格式化错误信息 - 修复无效正则导致的panic问题 P0-06: compiledPatterns非线程安全 - 添加sync.RWMutex保护map并发访问 - matchRegex和extractMatch使用读锁/写锁保护 - 实现双重检查锁定模式优化性能 测试验证: - 使用-race flag验证无数据竞争 - 并发100个goroutine测试通过
173 lines
3.8 KiB
Go
173 lines
3.8 KiB
Go
package rules
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"sync"
|
|
)
|
|
|
|
// MatchResult 匹配结果
|
|
type MatchResult struct {
|
|
Matched bool
|
|
RuleID string
|
|
Matchers []MatcherResult
|
|
}
|
|
|
|
// MatcherResult 单个匹配器的结果
|
|
type MatcherResult struct {
|
|
MatcherIndex int
|
|
MatcherType string
|
|
Pattern string
|
|
MatchValue string
|
|
IsMatch bool
|
|
}
|
|
|
|
// RuleEngine 规则引擎
|
|
type RuleEngine struct {
|
|
loader *RuleLoader
|
|
compiledPatterns map[string][]*regexp.Regexp
|
|
patternMu sync.RWMutex
|
|
}
|
|
|
|
// NewRuleEngine 创建新的规则引擎
|
|
func NewRuleEngine(loader *RuleLoader) *RuleEngine {
|
|
return &RuleEngine{
|
|
loader: loader,
|
|
compiledPatterns: make(map[string][]*regexp.Regexp),
|
|
}
|
|
}
|
|
|
|
// Match 执行规则匹配
|
|
func (e *RuleEngine) Match(rule Rule, content string) MatchResult {
|
|
result := MatchResult{
|
|
Matched: false,
|
|
RuleID: rule.ID,
|
|
Matchers: make([]MatcherResult, len(rule.Matchers)),
|
|
}
|
|
|
|
for i, matcher := range rule.Matchers {
|
|
matcherResult := MatcherResult{
|
|
MatcherIndex: i,
|
|
MatcherType: matcher.Type,
|
|
Pattern: matcher.Pattern,
|
|
IsMatch: false,
|
|
}
|
|
|
|
switch matcher.Type {
|
|
case "regex_match":
|
|
matcherResult.IsMatch = e.matchRegex(matcher.Pattern, content)
|
|
if matcherResult.IsMatch {
|
|
matcherResult.MatchValue, _ = e.extractMatch(matcher.Pattern, content)
|
|
}
|
|
default:
|
|
// 未知匹配器类型,默认不匹配
|
|
}
|
|
|
|
result.Matchers[i] = matcherResult
|
|
if matcherResult.IsMatch {
|
|
result.Matched = true
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// matchRegex 执行正则表达式匹配
|
|
func (e *RuleEngine) matchRegex(pattern string, content string) bool {
|
|
// 先尝试读取缓存(使用读锁)
|
|
e.patternMu.RLock()
|
|
regex, ok := e.compiledPatterns[pattern]
|
|
e.patternMu.RUnlock()
|
|
if ok {
|
|
return regex[0].MatchString(content)
|
|
}
|
|
|
|
// 未命中,需要编译(使用写锁)
|
|
e.patternMu.Lock()
|
|
defer e.patternMu.Unlock()
|
|
|
|
// 双重检查
|
|
regex, ok = e.compiledPatterns[pattern]
|
|
if ok {
|
|
return regex[0].MatchString(content)
|
|
}
|
|
|
|
var err error
|
|
regex = make([]*regexp.Regexp, 1)
|
|
regex[0], err = regexp.Compile(pattern)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
e.compiledPatterns[pattern] = regex
|
|
|
|
return regex[0].MatchString(content)
|
|
}
|
|
|
|
// extractMatch 提取匹配值
|
|
func (e *RuleEngine) extractMatch(pattern string, content string) (string, error) {
|
|
// 先尝试读取缓存(使用读锁)
|
|
e.patternMu.RLock()
|
|
regex, ok := e.compiledPatterns[pattern]
|
|
e.patternMu.RUnlock()
|
|
if ok {
|
|
return regex[0].FindString(content), nil
|
|
}
|
|
|
|
// 未命中,需要编译(使用写锁)
|
|
e.patternMu.Lock()
|
|
defer e.patternMu.Unlock()
|
|
|
|
// 双重检查
|
|
regex, ok = e.compiledPatterns[pattern]
|
|
if ok {
|
|
return regex[0].FindString(content), nil
|
|
}
|
|
|
|
var err error
|
|
regex = make([]*regexp.Regexp, 1)
|
|
regex[0], err = regexp.Compile(pattern)
|
|
if err != nil {
|
|
return "", fmt.Errorf("invalid regex pattern '%s': %w", pattern, err)
|
|
}
|
|
e.compiledPatterns[pattern] = regex
|
|
|
|
return regex[0].FindString(content), nil
|
|
}
|
|
|
|
// MatchFromConfig 从规则配置执行匹配
|
|
func (e *RuleEngine) MatchFromConfig(ruleID string, ruleConfig Rule, content string) (bool, error) {
|
|
// 验证规则
|
|
if err := e.validateRuleForMatch(ruleConfig); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
result := e.Match(ruleConfig, content)
|
|
return result.Matched, nil
|
|
}
|
|
|
|
// validateRuleForMatch 验证规则是否可用于匹配
|
|
func (e *RuleEngine) validateRuleForMatch(rule Rule) error {
|
|
if rule.ID == "" {
|
|
return ErrInvalidRule
|
|
}
|
|
if len(rule.Matchers) == 0 {
|
|
return ErrNoMatchers
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Custom errors
|
|
var (
|
|
ErrInvalidRule = &RuleEngineError{"invalid rule: missing required fields"}
|
|
ErrNoMatchers = &RuleEngineError{"invalid rule: no matchers defined"}
|
|
)
|
|
|
|
// RuleEngineError 规则引擎错误
|
|
type RuleEngineError struct {
|
|
Message string
|
|
}
|
|
|
|
func (e *RuleEngineError) Error() string {
|
|
return e.Message
|
|
}
|