2016-05-13 06:49:40 +03:00
|
|
|
// Copyright 2015 The etcd Authors
|
2015-01-25 06:19:16 +03:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2014-10-18 02:41:22 +04:00
|
|
|
|
2014-10-11 02:53:28 +04:00
|
|
|
package stats
|
|
|
|
|
|
|
|
import (
|
2014-10-17 05:39:55 +04:00
|
|
|
"encoding/json"
|
|
|
|
"log"
|
2014-10-11 02:53:28 +04:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/coreos/etcd/raft"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ServerStats encapsulates various statistics about an EtcdServer and its
|
|
|
|
// communication with other members of the cluster
|
|
|
|
type ServerStats struct {
|
2017-06-04 07:31:20 +03:00
|
|
|
serverStats
|
|
|
|
sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewServerStats(name, id string) *ServerStats {
|
|
|
|
ss := &ServerStats{
|
|
|
|
serverStats: serverStats{
|
|
|
|
Name: name,
|
|
|
|
ID: id,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
now := time.Now()
|
|
|
|
ss.StartTime = now
|
|
|
|
ss.LeaderInfo.StartTime = now
|
|
|
|
ss.sendRateQueue = &statsQueue{back: -1}
|
|
|
|
ss.recvRateQueue = &statsQueue{back: -1}
|
|
|
|
return ss
|
|
|
|
}
|
|
|
|
|
|
|
|
type serverStats struct {
|
2014-10-11 02:53:28 +04:00
|
|
|
Name string `json:"name"`
|
2016-02-21 16:05:03 +03:00
|
|
|
// ID is the raft ID of the node.
|
2014-10-11 02:53:28 +04:00
|
|
|
// TODO(jonboulle): use ID instead of name?
|
|
|
|
ID string `json:"id"`
|
|
|
|
State raft.StateType `json:"state"`
|
|
|
|
StartTime time.Time `json:"startTime"`
|
|
|
|
|
|
|
|
LeaderInfo struct {
|
|
|
|
Name string `json:"leader"`
|
|
|
|
Uptime string `json:"uptime"`
|
|
|
|
StartTime time.Time `json:"startTime"`
|
|
|
|
} `json:"leaderInfo"`
|
|
|
|
|
|
|
|
RecvAppendRequestCnt uint64 `json:"recvAppendRequestCnt,"`
|
|
|
|
RecvingPkgRate float64 `json:"recvPkgRate,omitempty"`
|
|
|
|
RecvingBandwidthRate float64 `json:"recvBandwidthRate,omitempty"`
|
|
|
|
|
|
|
|
SendAppendRequestCnt uint64 `json:"sendAppendRequestCnt"`
|
|
|
|
SendingPkgRate float64 `json:"sendPkgRate,omitempty"`
|
|
|
|
SendingBandwidthRate float64 `json:"sendBandwidthRate,omitempty"`
|
|
|
|
|
|
|
|
sendRateQueue *statsQueue
|
|
|
|
recvRateQueue *statsQueue
|
|
|
|
}
|
|
|
|
|
2014-10-17 05:39:55 +04:00
|
|
|
func (ss *ServerStats) JSON() []byte {
|
|
|
|
ss.Lock()
|
2017-06-04 07:31:20 +03:00
|
|
|
stats := ss.serverStats
|
|
|
|
stats.SendingPkgRate, stats.SendingBandwidthRate = stats.sendRateQueue.Rate()
|
|
|
|
stats.RecvingPkgRate, stats.RecvingBandwidthRate = stats.recvRateQueue.Rate()
|
2018-04-11 16:37:09 +03:00
|
|
|
stats.LeaderInfo.Uptime = time.Since(stats.LeaderInfo.StartTime).String()
|
2018-04-12 05:43:11 +03:00
|
|
|
ss.Unlock()
|
2014-10-17 06:49:35 +04:00
|
|
|
b, err := json.Marshal(stats)
|
2014-10-17 05:39:55 +04:00
|
|
|
// TODO(jonboulle): appropriate error handling?
|
|
|
|
if err != nil {
|
2014-10-31 02:48:23 +03:00
|
|
|
log.Printf("stats: error marshalling server stats: %v", err)
|
2014-10-17 05:39:55 +04:00
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2014-10-11 02:53:28 +04:00
|
|
|
// RecvAppendReq updates the ServerStats in response to an AppendRequest
|
|
|
|
// from the given leader being received
|
|
|
|
func (ss *ServerStats) RecvAppendReq(leader string, reqSize int) {
|
|
|
|
ss.Lock()
|
|
|
|
defer ss.Unlock()
|
|
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
|
|
|
ss.State = raft.StateFollower
|
|
|
|
if leader != ss.LeaderInfo.Name {
|
|
|
|
ss.LeaderInfo.Name = leader
|
|
|
|
ss.LeaderInfo.StartTime = now
|
|
|
|
}
|
|
|
|
|
|
|
|
ss.recvRateQueue.Insert(
|
|
|
|
&RequestStats{
|
|
|
|
SendingTime: now,
|
|
|
|
Size: reqSize,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
ss.RecvAppendRequestCnt++
|
|
|
|
}
|
|
|
|
|
|
|
|
// SendAppendReq updates the ServerStats in response to an AppendRequest
|
|
|
|
// being sent by this server
|
|
|
|
func (ss *ServerStats) SendAppendReq(reqSize int) {
|
|
|
|
ss.Lock()
|
|
|
|
defer ss.Unlock()
|
|
|
|
|
2016-08-11 19:39:25 +03:00
|
|
|
ss.becomeLeader()
|
2014-10-11 02:53:28 +04:00
|
|
|
|
|
|
|
ss.sendRateQueue.Insert(
|
|
|
|
&RequestStats{
|
2016-08-11 19:39:25 +03:00
|
|
|
SendingTime: time.Now(),
|
2014-10-11 02:53:28 +04:00
|
|
|
Size: reqSize,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
ss.SendAppendRequestCnt++
|
|
|
|
}
|
2014-12-16 03:55:17 +03:00
|
|
|
|
|
|
|
func (ss *ServerStats) BecomeLeader() {
|
2016-04-22 17:39:08 +03:00
|
|
|
ss.Lock()
|
|
|
|
defer ss.Unlock()
|
2016-08-11 19:39:25 +03:00
|
|
|
ss.becomeLeader()
|
|
|
|
}
|
2016-04-22 17:39:08 +03:00
|
|
|
|
2016-08-11 19:39:25 +03:00
|
|
|
func (ss *ServerStats) becomeLeader() {
|
2014-12-16 03:55:17 +03:00
|
|
|
if ss.State != raft.StateLeader {
|
|
|
|
ss.State = raft.StateLeader
|
|
|
|
ss.LeaderInfo.Name = ss.ID
|
|
|
|
ss.LeaderInfo.StartTime = time.Now()
|
|
|
|
}
|
|
|
|
}
|