Browse Source

etcdserver: expose store statistics

Jonathan Boulle 11 years ago
parent
commit
0a8721a708
3 changed files with 42 additions and 0 deletions
  1. 12 0
      etcdserver/etcdhttp/http.go
  2. 26 0
      etcdserver/etcdhttp/http_test.go
  3. 4 0
      etcdserver/server.go

+ 12 - 0
etcdserver/etcdhttp/http.go

@@ -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

+ 26 - 0
etcdserver/etcdhttp/http_test.go

@@ -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

+ 4 - 0
etcdserver/server.go

@@ -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.