github.com/xraypb/Xray-core@v1.8.1/app/stats/stats.go (about)

     1  package stats
     2  
     3  //go:generate go run github.com/xraypb/Xray-core/common/errors/errorgen
     4  
     5  import (
     6  	"context"
     7  	"sync"
     8  
     9  	"github.com/xraypb/Xray-core/common"
    10  	"github.com/xraypb/Xray-core/common/errors"
    11  	"github.com/xraypb/Xray-core/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  }