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 15package v2stats 16 17import ( 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 28type ServerStats struct { 29 serverStats 30 sync.Mutex 31} 32 33func 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 48type 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 74func (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 91func (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 114func (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 130func (ss *ServerStats) BecomeLeader() { 131 ss.Lock() 132 defer ss.Unlock() 133 ss.becomeLeader() 134} 135 136func (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} 143