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 }