go.etcd.io/etcd@v3.3.27+incompatible/etcdserver/stats/server.go (about) 1 // Copyright 2015 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package stats 16 17 import ( 18 "encoding/json" 19 "log" 20 "sync" 21 "time" 22 23 "github.com/coreos/etcd/raft" 24 ) 25 26 // ServerStats encapsulates various statistics about an EtcdServer and its 27 // communication with other members of the cluster 28 type ServerStats struct { 29 serverStats 30 sync.Mutex 31 } 32 33 func NewServerStats(name, id string) *ServerStats { 34 ss := &ServerStats{ 35 serverStats: serverStats{ 36 Name: name, 37 ID: id, 38 }, 39 } 40 now := time.Now() 41 ss.StartTime = now 42 ss.LeaderInfo.StartTime = now 43 ss.sendRateQueue = &statsQueue{back: -1} 44 ss.recvRateQueue = &statsQueue{back: -1} 45 return ss 46 } 47 48 type serverStats struct { 49 Name string `json:"name"` 50 // ID is the raft ID of the node. 51 // TODO(jonboulle): use ID instead of name? 52 ID string `json:"id"` 53 State raft.StateType `json:"state"` 54 StartTime time.Time `json:"startTime"` 55 56 LeaderInfo struct { 57 Name string `json:"leader"` 58 Uptime string `json:"uptime"` 59 StartTime time.Time `json:"startTime"` 60 } `json:"leaderInfo"` 61 62 RecvAppendRequestCnt uint64 `json:"recvAppendRequestCnt,"` 63 RecvingPkgRate float64 `json:"recvPkgRate,omitempty"` 64 RecvingBandwidthRate float64 `json:"recvBandwidthRate,omitempty"` 65 66 SendAppendRequestCnt uint64 `json:"sendAppendRequestCnt"` 67 SendingPkgRate float64 `json:"sendPkgRate,omitempty"` 68 SendingBandwidthRate float64 `json:"sendBandwidthRate,omitempty"` 69 70 sendRateQueue *statsQueue 71 recvRateQueue *statsQueue 72 } 73 74 func (ss *ServerStats) JSON() []byte { 75 ss.Lock() 76 stats := ss.serverStats 77 stats.SendingPkgRate, stats.SendingBandwidthRate = stats.sendRateQueue.Rate() 78 stats.RecvingPkgRate, stats.RecvingBandwidthRate = stats.recvRateQueue.Rate() 79 stats.LeaderInfo.Uptime = time.Since(stats.LeaderInfo.StartTime).String() 80 ss.Unlock() 81 b, err := json.Marshal(stats) 82 // TODO(jonboulle): appropriate error handling? 83 if err != nil { 84 log.Printf("stats: error marshalling server stats: %v", err) 85 } 86 return b 87 } 88 89 // RecvAppendReq updates the ServerStats in response to an AppendRequest 90 // from the given leader being received 91 func (ss *ServerStats) RecvAppendReq(leader string, reqSize int) { 92 ss.Lock() 93 defer ss.Unlock() 94 95 now := time.Now() 96 97 ss.State = raft.StateFollower 98 if leader != ss.LeaderInfo.Name { 99 ss.LeaderInfo.Name = leader 100 ss.LeaderInfo.StartTime = now 101 } 102 103 ss.recvRateQueue.Insert( 104 &RequestStats{ 105 SendingTime: now, 106 Size: reqSize, 107 }, 108 ) 109 ss.RecvAppendRequestCnt++ 110 } 111 112 // SendAppendReq updates the ServerStats in response to an AppendRequest 113 // being sent by this server 114 func (ss *ServerStats) SendAppendReq(reqSize int) { 115 ss.Lock() 116 defer ss.Unlock() 117 118 ss.becomeLeader() 119 120 ss.sendRateQueue.Insert( 121 &RequestStats{ 122 SendingTime: time.Now(), 123 Size: reqSize, 124 }, 125 ) 126 127 ss.SendAppendRequestCnt++ 128 } 129 130 func (ss *ServerStats) BecomeLeader() { 131 ss.Lock() 132 defer ss.Unlock() 133 ss.becomeLeader() 134 } 135 136 func (ss *ServerStats) becomeLeader() { 137 if ss.State != raft.StateLeader { 138 ss.State = raft.StateLeader 139 ss.LeaderInfo.Name = ss.ID 140 ss.LeaderInfo.StartTime = time.Now() 141 } 142 }