Repository: incubator-htrace
Updated Branches:
  refs/heads/master f52ea334d -> 8bc64091c


HTRACE-129: htraced: add /server/stats REST endpoint (cmccabe)


Project: http://git-wip-us.apache.org/repos/asf/incubator-htrace/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-htrace/commit/8bc64091
Tree: http://git-wip-us.apache.org/repos/asf/incubator-htrace/tree/8bc64091
Diff: http://git-wip-us.apache.org/repos/asf/incubator-htrace/diff/8bc64091

Branch: refs/heads/master
Commit: 8bc64091c2737a78c663dd55f0f1ae1d469ff3c1
Parents: f52ea33
Author: Colin P. Mccabe <[email protected]>
Authored: Thu Sep 24 11:05:44 2015 -0700
Committer: Colin P. Mccabe <[email protected]>
Committed: Thu Sep 24 11:05:44 2015 -0700

----------------------------------------------------------------------
 .../go/src/org/apache/htrace/client/client.go   | 15 +++++++
 .../go/src/org/apache/htrace/common/rest.go     | 16 +++++++
 .../go/src/org/apache/htrace/htrace/cmd.go      | 44 ++++++++++++++++++++
 .../src/org/apache/htrace/htraced/datastore.go  | 23 ++++++++++
 .../go/src/org/apache/htrace/htraced/rest.go    | 43 ++++++++++++++++++-
 5 files changed, 140 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/8bc64091/htrace-htraced/go/src/org/apache/htrace/client/client.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/client/client.go 
b/htrace-htraced/go/src/org/apache/htrace/client/client.go
index 5051d94..2ac8a1e 100644
--- a/htrace-htraced/go/src/org/apache/htrace/client/client.go
+++ b/htrace-htraced/go/src/org/apache/htrace/client/client.go
@@ -67,6 +67,21 @@ func (hcl *Client) GetServerInfo() (*common.ServerInfo, 
error) {
        return &info, nil
 }
 
+// Get the htraced server statistics.
+func (hcl *Client) GetServerStats() (*common.ServerStats, error) {
+       buf, _, err := hcl.makeGetRequest("server/stats")
+       if err != nil {
+               return nil, err
+       }
+       var stats common.ServerStats
+       err = json.Unmarshal(buf, &stats)
+       if err != nil {
+               return nil, errors.New(fmt.Sprintf("Error: error unmarshalling 
response "+
+                       "body %s: %s", string(buf), err.Error()))
+       }
+       return &stats, nil
+}
+
 // Get information about a trace span.  Returns nil, nil if the span was not 
found.
 func (hcl *Client) FindSpan(sid common.SpanId) (*common.Span, error) {
        buf, rc, err := hcl.makeGetRequest(fmt.Sprintf("span/%s", sid.String()))

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/8bc64091/htrace-htraced/go/src/org/apache/htrace/common/rest.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/common/rest.go 
b/htrace-htraced/go/src/org/apache/htrace/common/rest.go
index b898ca4..b367ed1 100644
--- a/htrace-htraced/go/src/org/apache/htrace/common/rest.go
+++ b/htrace-htraced/go/src/org/apache/htrace/common/rest.go
@@ -27,3 +27,19 @@ type ServerInfo struct {
        // The git hash that this software was built with.
        GitVersion string
 }
+
+// Info returned by /server/stats
+type ServerStats struct {
+       Shards []ShardStats
+}
+
+type ShardStats struct {
+       Path string
+
+       // The approximate number of spans present in this shard.  This may be 
an
+       // underestimate.
+       ApproxNumSpans uint64
+
+       // leveldb.stats information
+       LevelDbStats string
+}

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/8bc64091/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go 
b/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
index 8fd7067..8bc0c64 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
@@ -32,6 +32,7 @@ import (
        "org/apache/htrace/conf"
        "os"
        "time"
+       "strings"
 )
 
 var RELEASE_VERSION string
@@ -62,6 +63,8 @@ func main() {
        verbose = app.Flag("verbose", "Verbose.").Default("false").Bool()
        version := app.Command("version", "Print the version of this program.")
        serverInfo := app.Command("serverInfo", "Print information retrieved 
from an htraced server.")
+       serverStats := app.Command("serverStats", "Print statistics retrieved 
from the htraced server.")
+       serverStatsJson := serverStats.Flag("json", "Display statistics as raw 
JSON.").Default("false").Bool()
        findSpan := app.Command("findSpan", "Print information about a trace 
span with a given ID.")
        findSpanId := findSpan.Arg("id", "Span ID to find. Example: 
be305e54-4534-2110-a0b2-e06b9effe112").Required().String()
        findChildren := app.Command("findChildren", "Print out the span IDs 
that are children of a given span ID.")
@@ -122,6 +125,12 @@ func main() {
                os.Exit(printVersion())
        case serverInfo.FullCommand():
                os.Exit(printServerInfo(hcl))
+       case serverStats.FullCommand():
+               if (*serverStatsJson) {
+                       os.Exit(printServerStatsJson(hcl))
+               } else {
+                       os.Exit(printServerStats(hcl))
+               }
        case findSpan.FullCommand():
                var id *common.SpanId
                id.FromString(*findSpanId)
@@ -177,6 +186,41 @@ func printServerInfo(hcl *htrace.Client) int {
        return EXIT_SUCCESS
 }
 
+// Print information retrieved from an htraced server via /server/info
+func printServerStats(hcl *htrace.Client) int {
+       stats, err := hcl.GetServerStats()
+       if err != nil {
+               fmt.Println(err.Error())
+               return EXIT_FAILURE
+       }
+       fmt.Printf("HTraced server stats:\n")
+       fmt.Printf("%d leveldb shards.\n", len(stats.Shards))
+       for i := range(stats.Shards) {
+               shard := stats.Shards[i]
+               fmt.Printf("==== %s ===\n", shard.Path)
+               fmt.Printf("Approximate number of spans: %d\n", 
shard.ApproxNumSpans)
+               stats := strings.Replace(shard.LevelDbStats, "\\n", "\n", -1)
+               fmt.Printf("%s\n", stats)
+       }
+       return EXIT_SUCCESS
+}
+
+// Print information retrieved from an htraced server via /server/info as JSON
+func printServerStatsJson(hcl *htrace.Client) int {
+       stats, err := hcl.GetServerStats()
+       if err != nil {
+               fmt.Println(err.Error())
+               return EXIT_FAILURE
+       }
+       buf, err := json.MarshalIndent(stats, "", "  ")
+       if err != nil {
+               fmt.Printf("Error marshalling server stats: %s", err.Error())
+               return EXIT_FAILURE
+       }
+       fmt.Printf("%s\n", string(buf))
+       return EXIT_SUCCESS
+}
+
 // Print information about a trace span.
 func doFindSpan(hcl *htrace.Client, sid common.SpanId) int {
        span, err := hcl.FindSpan(sid)

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/8bc64091/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go 
b/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
index 5885168..0595d36 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
@@ -951,3 +951,26 @@ func (store *dataStore) HandleQuery(query *common.Query) 
([]*common.Span, error)
        }
        return ret, nil
 }
+
+func (store *dataStore) ServerStats() *common.ServerStats {
+       serverStats := common.ServerStats {
+               Shards : make([]common.ShardStats, len(store.shards)),
+       }
+       for shardIdx := range(store.shards) {
+               shard := store.shards[shardIdx]
+               serverStats.Shards[shardIdx].Path = shard.path
+               r := levigo.Range {
+                       Start : append([]byte{SPAN_ID_INDEX_PREFIX},
+                               common.INVALID_SPAN_ID.Val()...),
+                       Limit : append([]byte{SPAN_ID_INDEX_PREFIX + 1},
+                               common.INVALID_SPAN_ID.Val()...),
+               }
+               vals := shard.ldb.GetApproximateSizes([]levigo.Range { r })
+               serverStats.Shards[shardIdx].ApproxNumSpans = vals[0]
+               serverStats.Shards[shardIdx].LevelDbStats =
+                       shard.ldb.PropertyValue("leveldb.stats")
+               store.lg.Infof("shard.ldb.PropertyValue(leveldb.stats)=%s\n",
+                       shard.ldb.PropertyValue("leveldb.stats"))
+       }
+       return &serverStats
+}

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/8bc64091/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go 
b/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
index 66f78f8..97b2bca 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
@@ -25,6 +25,7 @@ import (
        "fmt"
        "github.com/gorilla/mux"
        "io"
+       "io/ioutil"
        "net"
        "net/http"
        "org/apache/htrace/common"
@@ -69,6 +70,24 @@ func (hand *serverInfoHandler) ServeHTTP(w 
http.ResponseWriter, req *http.Reques
        w.Write(buf)
 }
 
+type serverStatsHandler struct {
+       dataStoreHandler
+}
+
+func (hand *serverStatsHandler) ServeHTTP(w http.ResponseWriter, req 
*http.Request) {
+       setResponseHeaders(w.Header())
+       hand.lg.Debugf("serverStatsHandler\n")
+       stats := hand.store.ServerStats()
+       buf, err := json.Marshal(&stats)
+       if err != nil {
+               writeError(hand.lg, w, http.StatusInternalServerError,
+                       fmt.Sprintf("error marshalling ServerStats: %s\n", 
err.Error()))
+               return
+       }
+       hand.lg.Debugf("Returned ServerStats %s\n", string(buf))
+       w.Write(buf)
+}
+
 type dataStoreHandler struct {
        lg    *common.Logger
        store *dataStore
@@ -161,7 +180,19 @@ type writeSpansHandler struct {
 
 func (hand *writeSpansHandler) ServeHTTP(w http.ResponseWriter, req 
*http.Request) {
        setResponseHeaders(w.Header())
-       dec := json.NewDecoder(req.Body)
+       var dec *json.Decoder
+       if hand.lg.TraceEnabled() {
+               b, err := ioutil.ReadAll(req.Body)
+               if err != nil {
+                       writeError(hand.lg, w, http.StatusBadRequest,
+                               fmt.Sprintf("Error reading span data: %s", 
err.Error()))
+                       return
+               }
+               hand.lg.Tracef("writeSpansHandler: read %s\n", string(b))
+               dec = json.NewDecoder(bytes.NewBuffer(b))
+       } else {
+               dec = json.NewDecoder(req.Body)
+       }
        spans := make([]*common.Span, 0, 32)
        defaultTrid := req.Header.Get("htrace-trid")
        for {
@@ -175,6 +206,12 @@ func (hand *writeSpansHandler) ServeHTTP(w 
http.ResponseWriter, req *http.Reques
                        }
                        break
                }
+               spanIdProblem := span.Id.FindProblem()
+               if spanIdProblem != "" {
+                       writeError(hand.lg, w, http.StatusBadRequest,
+                               fmt.Sprintf("Invalid span ID: %s", 
spanIdProblem))
+                       return
+               }
                if span.TracerId == "" {
                        span.TracerId = defaultTrid
                }
@@ -262,6 +299,10 @@ func CreateRestServer(cnf *conf.Config, store *dataStore) 
(*RestServer, error) {
 
        r.Handle("/server/info", &serverInfoHandler{lg: rsv.lg}).Methods("GET")
 
+       serverStatsH := &serverStatsHandler{dataStoreHandler: dataStoreHandler{
+               store: store, lg: rsv.lg}}
+       r.Handle("/server/stats", serverStatsH).Methods("GET")
+
        writeSpansH := &writeSpansHandler{dataStoreHandler: dataStoreHandler{
                store: store, lg: rsv.lg}}
        r.Handle("/writeSpans", writeSpansH).Methods("POST")

Reply via email to