259 lines
7.4 KiB
Go
259 lines
7.4 KiB
Go
package aether
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
)
|
|
|
|
// BroadcasterMetrics provides observability metrics for EventBroadcaster implementations.
|
|
// All methods are safe for concurrent use.
|
|
type BroadcasterMetrics interface {
|
|
// EventsPublished returns the total number of events published per namespace.
|
|
EventsPublished(namespaceID string) int64
|
|
|
|
// EventsReceived returns the total number of events received per namespace.
|
|
// For EventBus this equals events delivered to subscribers.
|
|
// For NATSEventBus this includes events received from NATS.
|
|
EventsReceived(namespaceID string) int64
|
|
|
|
// ActiveSubscriptions returns the current number of active subscriptions per namespace.
|
|
ActiveSubscriptions(namespaceID string) int64
|
|
|
|
// TotalActiveSubscriptions returns the total number of active subscriptions across all namespaces.
|
|
TotalActiveSubscriptions() int64
|
|
|
|
// PublishErrors returns the total number of publish errors per namespace.
|
|
PublishErrors(namespaceID string) int64
|
|
|
|
// SubscribeErrors returns the total number of subscribe errors per namespace.
|
|
SubscribeErrors(namespaceID string) int64
|
|
|
|
// DroppedEvents returns the total number of events dropped (e.g., full channel) per namespace.
|
|
DroppedEvents(namespaceID string) int64
|
|
|
|
// Namespaces returns a list of all namespaces that have metrics.
|
|
Namespaces() []string
|
|
|
|
// Reset resets all metrics. Useful for testing.
|
|
Reset()
|
|
}
|
|
|
|
// MetricsCollector provides methods for collecting metrics.
|
|
// This interface is implemented internally and used by EventBus implementations.
|
|
type MetricsCollector interface {
|
|
BroadcasterMetrics
|
|
|
|
// RecordPublish records a successful publish event.
|
|
RecordPublish(namespaceID string)
|
|
|
|
// RecordReceive records a received event.
|
|
RecordReceive(namespaceID string)
|
|
|
|
// RecordSubscribe records a new subscription.
|
|
RecordSubscribe(namespaceID string)
|
|
|
|
// RecordUnsubscribe records a removed subscription.
|
|
RecordUnsubscribe(namespaceID string)
|
|
|
|
// RecordPublishError records a publish error.
|
|
RecordPublishError(namespaceID string)
|
|
|
|
// RecordSubscribeError records a subscribe error.
|
|
RecordSubscribeError(namespaceID string)
|
|
|
|
// RecordDroppedEvent records a dropped event (e.g., channel full).
|
|
RecordDroppedEvent(namespaceID string)
|
|
}
|
|
|
|
// namespaceMetrics holds counters for a single namespace.
|
|
type namespaceMetrics struct {
|
|
eventsPublished int64
|
|
eventsReceived int64
|
|
activeSubscriptions int64
|
|
publishErrors int64
|
|
subscribeErrors int64
|
|
droppedEvents int64
|
|
}
|
|
|
|
// DefaultMetricsCollector is the default implementation of MetricsCollector.
|
|
// It uses atomic operations for thread-safe counter updates.
|
|
type DefaultMetricsCollector struct {
|
|
mu sync.RWMutex
|
|
namespaces map[string]*namespaceMetrics
|
|
}
|
|
|
|
// NewMetricsCollector creates a new DefaultMetricsCollector.
|
|
func NewMetricsCollector() *DefaultMetricsCollector {
|
|
return &DefaultMetricsCollector{
|
|
namespaces: make(map[string]*namespaceMetrics),
|
|
}
|
|
}
|
|
|
|
// getOrCreateNamespace returns metrics for a namespace, creating if needed.
|
|
func (m *DefaultMetricsCollector) getOrCreateNamespace(namespaceID string) *namespaceMetrics {
|
|
m.mu.RLock()
|
|
ns, exists := m.namespaces[namespaceID]
|
|
m.mu.RUnlock()
|
|
|
|
if exists {
|
|
return ns
|
|
}
|
|
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
// Double-check after acquiring write lock
|
|
if ns, exists = m.namespaces[namespaceID]; exists {
|
|
return ns
|
|
}
|
|
|
|
ns = &namespaceMetrics{}
|
|
m.namespaces[namespaceID] = ns
|
|
return ns
|
|
}
|
|
|
|
// EventsPublished returns the total number of events published for a namespace.
|
|
func (m *DefaultMetricsCollector) EventsPublished(namespaceID string) int64 {
|
|
m.mu.RLock()
|
|
ns, exists := m.namespaces[namespaceID]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
return 0
|
|
}
|
|
return atomic.LoadInt64(&ns.eventsPublished)
|
|
}
|
|
|
|
// EventsReceived returns the total number of events received for a namespace.
|
|
func (m *DefaultMetricsCollector) EventsReceived(namespaceID string) int64 {
|
|
m.mu.RLock()
|
|
ns, exists := m.namespaces[namespaceID]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
return 0
|
|
}
|
|
return atomic.LoadInt64(&ns.eventsReceived)
|
|
}
|
|
|
|
// ActiveSubscriptions returns the current number of active subscriptions for a namespace.
|
|
func (m *DefaultMetricsCollector) ActiveSubscriptions(namespaceID string) int64 {
|
|
m.mu.RLock()
|
|
ns, exists := m.namespaces[namespaceID]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
return 0
|
|
}
|
|
return atomic.LoadInt64(&ns.activeSubscriptions)
|
|
}
|
|
|
|
// TotalActiveSubscriptions returns the total number of active subscriptions across all namespaces.
|
|
func (m *DefaultMetricsCollector) TotalActiveSubscriptions() int64 {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
var total int64
|
|
for _, ns := range m.namespaces {
|
|
total += atomic.LoadInt64(&ns.activeSubscriptions)
|
|
}
|
|
return total
|
|
}
|
|
|
|
// PublishErrors returns the total number of publish errors for a namespace.
|
|
func (m *DefaultMetricsCollector) PublishErrors(namespaceID string) int64 {
|
|
m.mu.RLock()
|
|
ns, exists := m.namespaces[namespaceID]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
return 0
|
|
}
|
|
return atomic.LoadInt64(&ns.publishErrors)
|
|
}
|
|
|
|
// SubscribeErrors returns the total number of subscribe errors for a namespace.
|
|
func (m *DefaultMetricsCollector) SubscribeErrors(namespaceID string) int64 {
|
|
m.mu.RLock()
|
|
ns, exists := m.namespaces[namespaceID]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
return 0
|
|
}
|
|
return atomic.LoadInt64(&ns.subscribeErrors)
|
|
}
|
|
|
|
// DroppedEvents returns the total number of dropped events for a namespace.
|
|
func (m *DefaultMetricsCollector) DroppedEvents(namespaceID string) int64 {
|
|
m.mu.RLock()
|
|
ns, exists := m.namespaces[namespaceID]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
return 0
|
|
}
|
|
return atomic.LoadInt64(&ns.droppedEvents)
|
|
}
|
|
|
|
// Namespaces returns a list of all namespaces that have metrics.
|
|
func (m *DefaultMetricsCollector) Namespaces() []string {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
namespaces := make([]string, 0, len(m.namespaces))
|
|
for ns := range m.namespaces {
|
|
namespaces = append(namespaces, ns)
|
|
}
|
|
return namespaces
|
|
}
|
|
|
|
// Reset resets all metrics.
|
|
func (m *DefaultMetricsCollector) Reset() {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.namespaces = make(map[string]*namespaceMetrics)
|
|
}
|
|
|
|
// RecordPublish records a successful publish event.
|
|
func (m *DefaultMetricsCollector) RecordPublish(namespaceID string) {
|
|
ns := m.getOrCreateNamespace(namespaceID)
|
|
atomic.AddInt64(&ns.eventsPublished, 1)
|
|
}
|
|
|
|
// RecordReceive records a received event.
|
|
func (m *DefaultMetricsCollector) RecordReceive(namespaceID string) {
|
|
ns := m.getOrCreateNamespace(namespaceID)
|
|
atomic.AddInt64(&ns.eventsReceived, 1)
|
|
}
|
|
|
|
// RecordSubscribe records a new subscription.
|
|
func (m *DefaultMetricsCollector) RecordSubscribe(namespaceID string) {
|
|
ns := m.getOrCreateNamespace(namespaceID)
|
|
atomic.AddInt64(&ns.activeSubscriptions, 1)
|
|
}
|
|
|
|
// RecordUnsubscribe records a removed subscription.
|
|
func (m *DefaultMetricsCollector) RecordUnsubscribe(namespaceID string) {
|
|
ns := m.getOrCreateNamespace(namespaceID)
|
|
atomic.AddInt64(&ns.activeSubscriptions, -1)
|
|
}
|
|
|
|
// RecordPublishError records a publish error.
|
|
func (m *DefaultMetricsCollector) RecordPublishError(namespaceID string) {
|
|
ns := m.getOrCreateNamespace(namespaceID)
|
|
atomic.AddInt64(&ns.publishErrors, 1)
|
|
}
|
|
|
|
// RecordSubscribeError records a subscribe error.
|
|
func (m *DefaultMetricsCollector) RecordSubscribeError(namespaceID string) {
|
|
ns := m.getOrCreateNamespace(namespaceID)
|
|
atomic.AddInt64(&ns.subscribeErrors, 1)
|
|
}
|
|
|
|
// RecordDroppedEvent records a dropped event.
|
|
func (m *DefaultMetricsCollector) RecordDroppedEvent(namespaceID string) {
|
|
ns := m.getOrCreateNamespace(namespaceID)
|
|
atomic.AddInt64(&ns.droppedEvents, 1)
|
|
}
|