github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/stats/stats.go (about) 1 package stats 2 3 //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen 4 5 import ( 6 "context" 7 "sync" 8 9 "github.com/v2fly/v2ray-core/v5/common" 10 "github.com/v2fly/v2ray-core/v5/common/errors" 11 "github.com/v2fly/v2ray-core/v5/features/stats" 12 ) 13 14 // Manager is an implementation of stats.Manager. 15 type Manager struct { 16 access sync.RWMutex 17 counters map[string]*Counter 18 channels map[string]*Channel 19 running bool 20 } 21 22 // NewManager creates an instance of Statistics Manager. 23 func NewManager(ctx context.Context, config *Config) (*Manager, error) { 24 m := &Manager{ 25 counters: make(map[string]*Counter), 26 channels: make(map[string]*Channel), 27 } 28 29 return m, nil 30 } 31 32 // Type implements common.HasType. 33 func (*Manager) Type() interface{} { 34 return stats.ManagerType() 35 } 36 37 // RegisterCounter implements stats.Manager. 38 func (m *Manager) RegisterCounter(name string) (stats.Counter, error) { 39 m.access.Lock() 40 defer m.access.Unlock() 41 42 if _, found := m.counters[name]; found { 43 return nil, newError("Counter ", name, " already registered.") 44 } 45 newError("create new counter ", name).AtDebug().WriteToLog() 46 c := new(Counter) 47 m.counters[name] = c 48 return c, nil 49 } 50 51 // UnregisterCounter implements stats.Manager. 52 func (m *Manager) UnregisterCounter(name string) error { 53 m.access.Lock() 54 defer m.access.Unlock() 55 56 if _, found := m.counters[name]; found { 57 newError("remove counter ", name).AtDebug().WriteToLog() 58 delete(m.counters, name) 59 } 60 return nil 61 } 62 63 // GetCounter implements stats.Manager. 64 func (m *Manager) GetCounter(name string) stats.Counter { 65 m.access.RLock() 66 defer m.access.RUnlock() 67 68 if c, found := m.counters[name]; found { 69 return c 70 } 71 return nil 72 } 73 74 // VisitCounters calls visitor function on all managed counters. 75 func (m *Manager) VisitCounters(visitor func(string, stats.Counter) bool) { 76 m.access.RLock() 77 defer m.access.RUnlock() 78 79 for name, c := range m.counters { 80 if !visitor(name, c) { 81 break 82 } 83 } 84 } 85 86 // RegisterChannel implements stats.Manager. 87 func (m *Manager) RegisterChannel(name string) (stats.Channel, error) { 88 m.access.Lock() 89 defer m.access.Unlock() 90 91 if _, found := m.channels[name]; found { 92 return nil, newError("Channel ", name, " already registered.") 93 } 94 newError("create new channel ", name).AtDebug().WriteToLog() 95 c := NewChannel(&ChannelConfig{BufferSize: 64, Blocking: false}) 96 m.channels[name] = c 97 if m.running { 98 return c, c.Start() 99 } 100 return c, nil 101 } 102 103 // UnregisterChannel implements stats.Manager. 104 func (m *Manager) UnregisterChannel(name string) error { 105 m.access.Lock() 106 defer m.access.Unlock() 107 108 if c, found := m.channels[name]; found { 109 newError("remove channel ", name).AtDebug().WriteToLog() 110 delete(m.channels, name) 111 return c.Close() 112 } 113 return nil 114 } 115 116 // GetChannel implements stats.Manager. 117 func (m *Manager) GetChannel(name string) stats.Channel { 118 m.access.RLock() 119 defer m.access.RUnlock() 120 121 if c, found := m.channels[name]; found { 122 return c 123 } 124 return nil 125 } 126 127 // Start implements common.Runnable. 128 func (m *Manager) Start() error { 129 m.access.Lock() 130 defer m.access.Unlock() 131 m.running = true 132 errs := []error{} 133 for _, channel := range m.channels { 134 if err := channel.Start(); err != nil { 135 errs = append(errs, err) 136 } 137 } 138 if len(errs) != 0 { 139 return errors.Combine(errs...) 140 } 141 return nil 142 } 143 144 // Close implement common.Closable. 145 func (m *Manager) Close() error { 146 m.access.Lock() 147 defer m.access.Unlock() 148 m.running = false 149 errs := []error{} 150 for name, channel := range m.channels { 151 newError("remove channel ", name).AtDebug().WriteToLog() 152 delete(m.channels, name) 153 if err := channel.Close(); err != nil { 154 errs = append(errs, err) 155 } 156 } 157 if len(errs) != 0 { 158 return errors.Combine(errs...) 159 } 160 return nil 161 } 162 163 func init() { 164 common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 165 return NewManager(ctx, config.(*Config)) 166 })) 167 }