github.com/nsqio/nsq@v1.3.0/nsqd/stats.go (about)

     1  package nsqd
     2  
     3  import (
     4  	"runtime"
     5  	"sort"
     6  	"sync/atomic"
     7  
     8  	"github.com/nsqio/nsq/internal/quantile"
     9  )
    10  
    11  type Stats struct {
    12  	Topics    []TopicStats
    13  	Producers []ClientStats
    14  }
    15  
    16  type ClientStats interface {
    17  	String() string
    18  }
    19  
    20  type TopicStats struct {
    21  	TopicName    string         `json:"topic_name"`
    22  	Channels     []ChannelStats `json:"channels"`
    23  	Depth        int64          `json:"depth"`
    24  	BackendDepth int64          `json:"backend_depth"`
    25  	MessageCount uint64         `json:"message_count"`
    26  	MessageBytes uint64         `json:"message_bytes"`
    27  	Paused       bool           `json:"paused"`
    28  
    29  	E2eProcessingLatency *quantile.Result `json:"e2e_processing_latency"`
    30  }
    31  
    32  func NewTopicStats(t *Topic, channels []ChannelStats) TopicStats {
    33  	return TopicStats{
    34  		TopicName:    t.name,
    35  		Channels:     channels,
    36  		Depth:        t.Depth(),
    37  		BackendDepth: t.backend.Depth(),
    38  		MessageCount: atomic.LoadUint64(&t.messageCount),
    39  		MessageBytes: atomic.LoadUint64(&t.messageBytes),
    40  		Paused:       t.IsPaused(),
    41  
    42  		E2eProcessingLatency: t.AggregateChannelE2eProcessingLatency().Result(),
    43  	}
    44  }
    45  
    46  type ChannelStats struct {
    47  	ChannelName   string        `json:"channel_name"`
    48  	Depth         int64         `json:"depth"`
    49  	BackendDepth  int64         `json:"backend_depth"`
    50  	InFlightCount int           `json:"in_flight_count"`
    51  	DeferredCount int           `json:"deferred_count"`
    52  	MessageCount  uint64        `json:"message_count"`
    53  	RequeueCount  uint64        `json:"requeue_count"`
    54  	TimeoutCount  uint64        `json:"timeout_count"`
    55  	ClientCount   int           `json:"client_count"`
    56  	Clients       []ClientStats `json:"clients"`
    57  	Paused        bool          `json:"paused"`
    58  
    59  	E2eProcessingLatency *quantile.Result `json:"e2e_processing_latency"`
    60  }
    61  
    62  func NewChannelStats(c *Channel, clients []ClientStats, clientCount int) ChannelStats {
    63  	c.inFlightMutex.Lock()
    64  	inflight := len(c.inFlightMessages)
    65  	c.inFlightMutex.Unlock()
    66  	c.deferredMutex.Lock()
    67  	deferred := len(c.deferredMessages)
    68  	c.deferredMutex.Unlock()
    69  
    70  	return ChannelStats{
    71  		ChannelName:   c.name,
    72  		Depth:         c.Depth(),
    73  		BackendDepth:  c.backend.Depth(),
    74  		InFlightCount: inflight,
    75  		DeferredCount: deferred,
    76  		MessageCount:  atomic.LoadUint64(&c.messageCount),
    77  		RequeueCount:  atomic.LoadUint64(&c.requeueCount),
    78  		TimeoutCount:  atomic.LoadUint64(&c.timeoutCount),
    79  		ClientCount:   clientCount,
    80  		Clients:       clients,
    81  		Paused:        c.IsPaused(),
    82  
    83  		E2eProcessingLatency: c.e2eProcessingLatencyStream.Result(),
    84  	}
    85  }
    86  
    87  type Topics []*Topic
    88  
    89  func (t Topics) Len() int      { return len(t) }
    90  func (t Topics) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
    91  
    92  type TopicsByName struct {
    93  	Topics
    94  }
    95  
    96  func (t TopicsByName) Less(i, j int) bool { return t.Topics[i].name < t.Topics[j].name }
    97  
    98  type Channels []*Channel
    99  
   100  func (c Channels) Len() int      { return len(c) }
   101  func (c Channels) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
   102  
   103  type ChannelsByName struct {
   104  	Channels
   105  }
   106  
   107  func (c ChannelsByName) Less(i, j int) bool { return c.Channels[i].name < c.Channels[j].name }
   108  
   109  func (n *NSQD) GetStats(topic string, channel string, includeClients bool) Stats {
   110  	var stats Stats
   111  
   112  	n.RLock()
   113  	var realTopics []*Topic
   114  	if topic == "" {
   115  		realTopics = make([]*Topic, 0, len(n.topicMap))
   116  		for _, t := range n.topicMap {
   117  			realTopics = append(realTopics, t)
   118  		}
   119  	} else if val, exists := n.topicMap[topic]; exists {
   120  		realTopics = []*Topic{val}
   121  	} else {
   122  		n.RUnlock()
   123  		return stats
   124  	}
   125  	n.RUnlock()
   126  	sort.Sort(TopicsByName{realTopics})
   127  
   128  	topics := make([]TopicStats, 0, len(realTopics))
   129  
   130  	for _, t := range realTopics {
   131  		t.RLock()
   132  		var realChannels []*Channel
   133  		if channel == "" {
   134  			realChannels = make([]*Channel, 0, len(t.channelMap))
   135  			for _, c := range t.channelMap {
   136  				realChannels = append(realChannels, c)
   137  			}
   138  		} else if val, exists := t.channelMap[channel]; exists {
   139  			realChannels = []*Channel{val}
   140  		} else {
   141  			t.RUnlock()
   142  			continue
   143  		}
   144  		t.RUnlock()
   145  		sort.Sort(ChannelsByName{realChannels})
   146  		channels := make([]ChannelStats, 0, len(realChannels))
   147  		for _, c := range realChannels {
   148  			var clients []ClientStats
   149  			var clientCount int
   150  			c.RLock()
   151  			if includeClients {
   152  				clients = make([]ClientStats, 0, len(c.clients))
   153  				for _, client := range c.clients {
   154  					clients = append(clients, client.Stats(topic))
   155  				}
   156  			}
   157  			clientCount = len(c.clients)
   158  			c.RUnlock()
   159  			channels = append(channels, NewChannelStats(c, clients, clientCount))
   160  		}
   161  		topics = append(topics, NewTopicStats(t, channels))
   162  	}
   163  	stats.Topics = topics
   164  
   165  	if includeClients {
   166  		var producerStats []ClientStats
   167  		n.tcpServer.conns.Range(func(k, v interface{}) bool {
   168  			c := v.(Client)
   169  			if c.Type() == typeProducer {
   170  				producerStats = append(producerStats, c.Stats(topic))
   171  			}
   172  			return true
   173  		})
   174  		stats.Producers = producerStats
   175  	}
   176  
   177  	return stats
   178  }
   179  
   180  type memStats struct {
   181  	HeapObjects       uint64 `json:"heap_objects"`
   182  	HeapIdleBytes     uint64 `json:"heap_idle_bytes"`
   183  	HeapInUseBytes    uint64 `json:"heap_in_use_bytes"`
   184  	HeapReleasedBytes uint64 `json:"heap_released_bytes"`
   185  	GCPauseUsec100    uint64 `json:"gc_pause_usec_100"`
   186  	GCPauseUsec99     uint64 `json:"gc_pause_usec_99"`
   187  	GCPauseUsec95     uint64 `json:"gc_pause_usec_95"`
   188  	NextGCBytes       uint64 `json:"next_gc_bytes"`
   189  	GCTotalRuns       uint32 `json:"gc_total_runs"`
   190  }
   191  
   192  func getMemStats() memStats {
   193  	var ms runtime.MemStats
   194  	runtime.ReadMemStats(&ms)
   195  
   196  	// sort the GC pause array
   197  	length := len(ms.PauseNs)
   198  	if int(ms.NumGC) < length {
   199  		length = int(ms.NumGC)
   200  	}
   201  	gcPauses := make(Uint64Slice, length)
   202  	copy(gcPauses, ms.PauseNs[:length])
   203  	sort.Sort(gcPauses)
   204  
   205  	return memStats{
   206  		ms.HeapObjects,
   207  		ms.HeapIdle,
   208  		ms.HeapInuse,
   209  		ms.HeapReleased,
   210  		percentile(100.0, gcPauses, len(gcPauses)) / 1000,
   211  		percentile(99.0, gcPauses, len(gcPauses)) / 1000,
   212  		percentile(95.0, gcPauses, len(gcPauses)) / 1000,
   213  		ms.NextGC,
   214  		ms.NumGC,
   215  	}
   216  
   217  }