khenaidoo | ab1f7bd | 2019-11-14 14:00:27 -0500 | [diff] [blame] | 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 v2stats |
| 16 | |
| 17 | import ( |
| 18 | "encoding/json" |
| 19 | "log" |
| 20 | "sync" |
| 21 | "time" |
| 22 | |
| 23 | "go.etcd.io/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 | } |