package patterns import ( "fmt" "os" "regexp" "sync" "gopkg.in/yaml.v3" ) type Config struct { Patterns map[string]ServiceConfig `yaml:"patterns"` } type ServiceConfig struct { Extractors []ExtractorConfig `yaml:"extractors"` } type ExtractorConfig struct { Name string `yaml:"name"` Regex string `yaml:"regex"` Fields map[string]string `yaml:"fields"` } type CompiledExtractor struct { Name string Pattern *regexp.Regexp Fields map[string]string } type Repository struct { services map[string][]CompiledExtractor mu sync.RWMutex } var ( instance *Repository once sync.Once ) func GetInstance() *Repository { once.Do(func() { instance = &Repository{ services: make(map[string][]CompiledExtractor), } }) return instance } func (r *Repository) Load(path string) error { r.mu.Lock() defer r.mu.Unlock() data, err := os.ReadFile(path) if err != nil { return fmt.Errorf("failed to read patterns file: %w", err) } var cfg Config if err := yaml.Unmarshal(data, &cfg); err != nil { return fmt.Errorf("failed to parse yaml: %w", err) } for service, svcCfg := range cfg.Patterns { var compiledList []CompiledExtractor for _, ext := range svcCfg.Extractors { re, err := regexp.Compile(ext.Regex) if err != nil { return fmt.Errorf("invalid regex in service %s extractor %s: %w", service, ext.Name, err) } compiledList = append(compiledList, CompiledExtractor{ Name: ext.Name, Pattern: re, Fields: ext.Fields, }) } r.services[service] = compiledList } return nil } func (r *Repository) GetExtractors(service string) []CompiledExtractor { r.mu.RLock() defer r.mu.RUnlock() return r.services[service] }