diff --git a/core/health/counter.go b/core/health/counter.go index 78604c0..584e609 100644 --- a/core/health/counter.go +++ b/core/health/counter.go @@ -12,6 +12,7 @@ const DefaultResetPeriod = time.Minute * 15 // AtomicCounter is a default Counter implementation. // It uses atomics under the hood (hence the name) and can be configured with custom reset timeout and type AtomicCounter struct { + name atomic.String msg atomic.String timestamp atomic.Time resetPeriod time.Duration @@ -23,16 +24,25 @@ type AtomicCounter struct { } // NewAtomicCounterWithPeriod returns AtomicCounter configured with provided period. -func NewAtomicCounterWithPeriod(resetPeriod time.Duration) Counter { +func NewAtomicCounterWithPeriod(name string, resetPeriod time.Duration) Counter { c := &AtomicCounter{} + c.SetName(name) c.resetPeriod = resetPeriod c.timestamp.Store(time.Now()) return c } // NewAtomicCounter returns AtomicCounter with DefaultResetPeriod. -func NewAtomicCounter() Counter { - return NewAtomicCounterWithPeriod(DefaultResetPeriod) +func NewAtomicCounter(name string) Counter { + return NewAtomicCounterWithPeriod(name, DefaultResetPeriod) +} + +func (a *AtomicCounter) Name() string { + return a.name.Load() +} + +func (a *AtomicCounter) SetName(name string) { + a.name.Store(name) } func (a *AtomicCounter) HitSuccess() { diff --git a/core/health/iface.go b/core/health/iface.go index eb3f143..7c11b87 100644 --- a/core/health/iface.go +++ b/core/health/iface.go @@ -3,7 +3,8 @@ package health // Storage stores different instances of Counter. Implementation should be goroutine-safe. type Storage interface { // Get counter by its ID. The counter will be instantiated automatically if necessary. - Get(id int) Counter + // Name here is not used to identify the counter in the storage. + Get(id int, name string) Counter // Remove counter if it exists. Remove(id int) // Process will iterate over counters and call Processor on each of them. @@ -15,6 +16,10 @@ type Storage interface { // is not working properly (invalid credentials, too many failed requests, etc) and take further action based on the result. // Implementation should be goroutine-safe. type Counter interface { + // Name can be used as a more friendly identifier for the counter. + Name() string + // SetName of the counter. + SetName(name string) // HitSuccess registers successful request. It should automatically clear error state because that state should be // used only if error is totally unrecoverable. HitSuccess() @@ -55,8 +60,8 @@ type Processor interface { // NotifyMessageLocalizer is the smallest subset of core.Localizer used in the type NotifyMessageLocalizer interface { - SetLocale(string) - GetLocalizedMessage(string) string + SetLocale(locale string) + GetLocalizedTemplateMessage(messageID string, templateData map[string]interface{}) string } // NotifyFunc will send notification about error to the system with provided credentials. @@ -64,7 +69,7 @@ type NotifyMessageLocalizer interface { type NotifyFunc func(apiURL, apiKey, msg string) // CounterConstructor is used to create counters. This way you can implement your own counter and still use default CounterStorage. -type CounterConstructor func() Counter +type CounterConstructor func(name string) Counter // ConnectionDataProvider should return the connection credentials and language by counter ID. // It's best to use account ID as a counter ID to be able to retrieve the necessary data as easy as possible. diff --git a/core/health/processor.go b/core/health/processor.go index 35804ca..fe469ea 100644 --- a/core/health/processor.go +++ b/core/health/processor.go @@ -26,8 +26,8 @@ func (c CounterProcessor) Process(id int, counter Counter) { return } - apiURL, apiKey, lang := c.ConnectionDataProvider(id) - c.Notifier(apiURL, apiKey, c.getErrorText(counter.Message(), lang)) + apiURL, apiKey, _ := c.ConnectionDataProvider(id) + c.Notifier(apiURL, apiKey, counter.Message()) counter.FailureProcessed() return } @@ -55,15 +55,15 @@ func (c CounterProcessor) Process(id int, counter Counter) { } apiURL, apiKey, lang := c.ConnectionDataProvider(id) - c.Notifier(apiURL, apiKey, c.getErrorText(c.Error, lang)) + c.Notifier(apiURL, apiKey, c.getErrorText(counter.Name(), c.Error, lang)) counter.CountersProcessed() return } -func (c CounterProcessor) getErrorText(msg, lang string) string { +func (c CounterProcessor) getErrorText(name, msg, lang string) string { if c.Localizer == nil { return msg } c.Localizer.SetLocale(lang) - return c.Localizer.GetLocalizedMessage(msg) + return c.Localizer.GetLocalizedTemplateMessage(msg, map[string]interface{}{"Name": name}) } diff --git a/core/health/storage.go b/core/health/storage.go index b74a7c4..5ae4870 100644 --- a/core/health/storage.go +++ b/core/health/storage.go @@ -15,12 +15,14 @@ func NewSyncMapStorage(constructor CounterConstructor) Storage { return &SyncMapStorage{constructor: constructor} } -func (s *SyncMapStorage) Get(id int) Counter { +func (s *SyncMapStorage) Get(id int, name string) Counter { val, found := s.m.Load(id) if found { + counter := val.(Counter) + counter.SetName(name) return val.(Counter) } - c := s.constructor() + c := s.constructor(name) s.m.Store(id, c) return c }