etcdserver: expose store statistics

release-2.0
Jonathan Boulle 2014-10-10 12:55:17 -07:00
parent 79e9f2ab81
commit 0a8721a708
3 changed files with 42 additions and 0 deletions

View File

@ -25,6 +25,7 @@ const (
deprecatedMachinesPrefix = "/v2/machines"
adminMembersPrefix = "/v2/admin/members/"
raftPrefix = "/raft"
statsPrefix = "/v2/stats"
// time to wait for response from EtcdServer requests
defaultServerTimeout = 500 * time.Millisecond
@ -42,10 +43,12 @@ func NewClientHandler(server *etcdserver.EtcdServer) http.Handler {
clusterStore: server.ClusterStore,
timer: server,
timeout: defaultServerTimeout,
storeStats: server.StoreStats,
}
mux := http.NewServeMux()
mux.HandleFunc(keysPrefix, sh.serveKeys)
mux.HandleFunc(keysPrefix+"/", sh.serveKeys)
mux.HandleFunc(statsPrefix+"/store", sh.serveStoreStats)
// TODO: dynamic configuration may make this outdated. take care of it.
// TODO: dynamic configuration may introduce race also.
// TODO: add serveMembers
@ -72,6 +75,7 @@ type serverHandler struct {
server etcdserver.Server
timer etcdserver.RaftTimer
clusterStore etcdserver.ClusterStore
storeStats func() []byte
}
func (h serverHandler) serveKeys(w http.ResponseWriter, r *http.Request) {
@ -162,6 +166,14 @@ func (h serverHandler) serveAdminMembers(w http.ResponseWriter, r *http.Request)
}
}
func (h serverHandler) serveStoreStats(w http.ResponseWriter, r *http.Request) {
if !allowMethod(w, r.Method, "GET") {
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(h.storeStats())
}
func (h serverHandler) serveRaft(w http.ResponseWriter, r *http.Request) {
if !allowMethod(w, r.Method, "POST") {
return

View File

@ -637,6 +637,32 @@ func TestServeMachines(t *testing.T) {
}
}
func TestServeStoreStats(t *testing.T) {
w := "foobarbaz"
sh := &serverHandler{
storeStats: func() []byte {
return []byte(w)
},
}
rw := httptest.NewRecorder()
req, err := http.NewRequest("GET", "", nil)
if err != nil {
t.Fatal(err)
}
sh.serveStoreStats(rw, req)
if rw.Code != http.StatusOK {
t.Errorf("header = %d, want %d", rw.Code, http.StatusOK)
}
wct := "application/json"
if gct := rw.Header().Get("Content-Type"); gct != wct {
t.Errorf("Content-Type = %q, want %q", gct, wct)
}
if g := rw.Body.String(); g != w {
t.Errorf("body = %s, want %s", g, w)
}
}
func TestAllowMethod(t *testing.T) {
tests := []struct {
m string

View File

@ -198,6 +198,10 @@ func (s *EtcdServer) Start() {
go s.publish(defaultPublishRetryInterval)
}
func (s *EtcdServer) StoreStats() []byte {
return s.store.JsonStats()
}
// start prepares and starts server in a new goroutine. It is no longer safe to
// modify a server's fields after it has been sent to Start.
// This function is just used for testing.