diff options
| -rw-r--r-- | go/stats/duration_counter.go | 14 | ||||
| -rw-r--r-- | go/storage/store.go | 3 | ||||
| -rw-r--r-- | go/storage/volume_ttl.go | 8 | ||||
| -rw-r--r-- | go/weed/weed_server/common.go | 2 | ||||
| -rw-r--r-- | go/weed/weed_server/master_server.go | 1 | ||||
| -rw-r--r-- | go/weed/weed_server/master_server_handlers_ui.go | 10 | ||||
| -rw-r--r-- | go/weed/weed_server/master_ui/templates.go | 4 | ||||
| -rw-r--r-- | go/weed/weed_server/volume_server_handlers_ui.go | 5 | ||||
| -rw-r--r-- | go/weed/weed_server/volume_server_ui/templates.go | 59 |
9 files changed, 93 insertions, 13 deletions
diff --git a/go/stats/duration_counter.go b/go/stats/duration_counter.go index 254a95fc7..50a8bce43 100644 --- a/go/stats/duration_counter.go +++ b/go/stats/duration_counter.go @@ -58,6 +58,20 @@ func (rrc *RoundRobinCounter) Sum() (sum int64) { return } +func (rrc *RoundRobinCounter) ToList() (ret []int64) { + index := rrc.LastIndex + step := len(rrc.Values) + for step > 0 { + step-- + index++ + if index >= len(rrc.Values) { + index = 0 + } + ret = append(ret, rrc.Values[index]) + } + return +} + type DurationCounter struct { MinuteCounter *RoundRobinCounter HourCounter *RoundRobinCounter diff --git a/go/storage/store.go b/go/storage/store.go index f514b3fcc..2695537f6 100644 --- a/go/storage/store.go +++ b/go/storage/store.go @@ -243,7 +243,8 @@ func (s *Store) Status() []*VolumeInfo { FileCount: v.nm.FileCount(), DeleteCount: v.nm.DeletedCount(), DeletedByteCount: v.nm.DeletedSize(), - ReadOnly: v.readOnly} + ReadOnly: v.readOnly, + Ttl: v.Ttl} stats = append(stats, s) } } diff --git a/go/storage/volume_ttl.go b/go/storage/volume_ttl.go index 459ee55ba..4318bb048 100644 --- a/go/storage/volume_ttl.go +++ b/go/storage/volume_ttl.go @@ -60,19 +60,19 @@ func LoadTTLFromUint32(ttl uint32) (t *TTL) { } // save stored bytes to an output with 2 bytes -func (t TTL) ToBytes(output []byte) { +func (t *TTL) ToBytes(output []byte) { output[0] = t.count output[1] = t.unit } -func (t TTL) ToUint32() (output uint32) { +func (t *TTL) ToUint32() (output uint32) { output = uint32(t.count) << 8 output += uint32(t.unit) return output } -func (t TTL) String() string { - if t.count == 0 { +func (t *TTL) String() string { + if t == nil || t.count == 0 { return "" } if t.unit == Empty { diff --git a/go/weed/weed_server/common.go b/go/weed/weed_server/common.go index 095652a6b..07b439b9b 100644 --- a/go/weed/weed_server/common.go +++ b/go/weed/weed_server/common.go @@ -9,6 +9,7 @@ import ( "path/filepath" "strconv" "strings" + "time" "github.com/chrislusf/weed-fs/go/glog" "github.com/chrislusf/weed-fs/go/operation" @@ -19,6 +20,7 @@ import ( ) var serverStats *stats.ServerStats +var startTime = time.Now() func init() { serverStats = stats.NewServerStats() diff --git a/go/weed/weed_server/master_server.go b/go/weed/weed_server/master_server.go index a89fca701..7a4b990a4 100644 --- a/go/weed/weed_server/master_server.go +++ b/go/weed/weed_server/master_server.go @@ -60,6 +60,7 @@ func NewMasterServer(r *mux.Router, port int, metaFolder string, ms.guard = security.NewGuard(whiteList, secureKey) + r.HandleFunc("/", ms.uiStatusHandler) r.HandleFunc("/ui/index.html", ms.uiStatusHandler) r.HandleFunc("/dir/assign", ms.proxyToLeader(ms.guard.WhiteList(ms.dirAssignHandler))) r.HandleFunc("/dir/lookup", ms.proxyToLeader(ms.guard.WhiteList(ms.dirLookupHandler))) diff --git a/go/weed/weed_server/master_server_handlers_ui.go b/go/weed/weed_server/master_server_handlers_ui.go index 3ba4bb053..9f9b179da 100644 --- a/go/weed/weed_server/master_server_handlers_ui.go +++ b/go/weed/weed_server/master_server_handlers_ui.go @@ -3,24 +3,26 @@ package weed_server import ( "net/http" + "github.com/chrislusf/weed-fs/go/stats" "github.com/chrislusf/weed-fs/go/util" ui "github.com/chrislusf/weed-fs/go/weed/weed_server/master_ui" ) func (ms *MasterServer) uiStatusHandler(w http.ResponseWriter, r *http.Request) { - stats := make(map[string]interface{}) - stats["Version"] = util.VERSION + infos := make(map[string]interface{}) + infos["Version"] = util.VERSION args := struct { Version string Topology interface{} Peers interface{} Stats interface{} + Counters *stats.ServerStats }{ util.VERSION, ms.Topo.ToMap(), ms.Topo.RaftServer.Peers(), - stats, - //serverStats, + infos, + serverStats, } ui.StatusTpl.Execute(w, args) } diff --git a/go/weed/weed_server/master_ui/templates.go b/go/weed/weed_server/master_ui/templates.go index d292952aa..42adacb5d 100644 --- a/go/weed/weed_server/master_ui/templates.go +++ b/go/weed/weed_server/master_ui/templates.go @@ -44,6 +44,10 @@ var StatusTpl = template.Must(template.New("status").Parse(`<!DOCTYPE html> <div class="col-sm-6"> <h2>System Stats</h2> <table class="table table-condensed table-striped"> + <tr> + <th>Concurrent Connections</th> + <td>{{ .Counters.Connections.WeekCounter.Count }}</td> + </tr> {{ range $key, $val := .Stats }} <tr> <th>{{ $key }}</th> diff --git a/go/weed/weed_server/volume_server_handlers_ui.go b/go/weed/weed_server/volume_server_handlers_ui.go index b033173bb..deae6df61 100644 --- a/go/weed/weed_server/volume_server_handlers_ui.go +++ b/go/weed/weed_server/volume_server_handlers_ui.go @@ -3,6 +3,7 @@ package weed_server import ( "net/http" "path/filepath" + "time" "github.com/chrislusf/weed-fs/go/stats" "github.com/chrislusf/weed-fs/go/util" @@ -11,7 +12,7 @@ import ( func (vs *VolumeServer) uiStatusHandler(w http.ResponseWriter, r *http.Request) { infos := make(map[string]interface{}) - infos["Version"] = util.VERSION + infos["Up Time"] = time.Now().Sub(startTime).String() var ds []*stats.DiskStatus for _, loc := range vs.store.Locations { if dir, e := filepath.Abs(loc.Directory); e == nil { @@ -24,12 +25,14 @@ func (vs *VolumeServer) uiStatusHandler(w http.ResponseWriter, r *http.Request) Volumes interface{} DiskStatuses interface{} Stats interface{} + Counters *stats.ServerStats }{ util.VERSION, vs.masterNode, vs.store.Status(), ds, infos, + serverStats, } ui.StatusTpl.Execute(w, args) } diff --git a/go/weed/weed_server/volume_server_ui/templates.go b/go/weed/weed_server/volume_server_ui/templates.go index 98e91bd25..ce51ab4f8 100644 --- a/go/weed/weed_server/volume_server_ui/templates.go +++ b/go/weed/weed_server/volume_server_ui/templates.go @@ -2,13 +2,48 @@ package master_ui import ( "html/template" + "strconv" + "strings" ) -var StatusTpl = template.Must(template.New("status").Parse(`<!DOCTYPE html> +func join(data []int64) string { + var ret []string + for _, d := range data { + ret = append(ret, strconv.Itoa(int(d))) + } + return strings.Join(ret, ",") +} + +var funcMap = template.FuncMap{ + "join": join, +} + +var StatusTpl = template.Must(template.New("status").Funcs(funcMap).Parse(`<!DOCTYPE html> <html> <head> <title>Seaweed File System {{ .Version }}</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"> + <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script> + <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-sparklines/2.1.2/jquery.sparkline.min.js"></script> + <script type="text/javascript"> + $(function() { + var periods = ['second', 'minute', 'hour', 'day']; + for (i = 0; i < periods.length; i++) { + var period = periods[i]; + $('.inlinesparkline-'+period).sparkline('html', { + type: 'line', + barColor: 'red', + tooltipSuffix:' request per '+period, + }); + } + }); + </script> + <style> + #jqstooltip{ + height: 28px !important; + width: 150px !important; + } + </style> </head> <body> <div class="container"> @@ -23,7 +58,7 @@ var StatusTpl = template.Must(template.New("status").Parse(`<!DOCTYPE html> {{ range .DiskStatuses }} <tr> <th>{{ .Dir }}</th> - <td>{{ .Free }}</td> + <td>{{ .Free }} Bytes Free</td> </tr> {{ end }} </table> @@ -36,6 +71,22 @@ var StatusTpl = template.Must(template.New("status").Parse(`<!DOCTYPE html> <th>Master</th> <td><a href="http://{{.Master}}/ui/index.html">{{.Master}}</a></td> </tr> + <tr> + <th>Weekly # ReadRequests</th> + <td><span class="inlinesparkline-day">{{ .Counters.ReadRequests.WeekCounter.ToList | join }}</span></td> + </tr> + <tr> + <th>Daily # ReadRequests</th> + <td><span class="inlinesparkline-hour">{{ .Counters.ReadRequests.DayCounter.ToList | join }}</span></td> + </tr> + <tr> + <th>Hourly # ReadRequests</th> + <td><span class="inlinesparkline-minute">{{ .Counters.ReadRequests.HourCounter.ToList | join }}</span></td> + </tr> + <tr> + <th>Last Minute # ReadRequests</th> + <td><span class="inlinesparkline-second">{{ .Counters.ReadRequests.MinuteCounter.ToList | join }}</span></td> + </tr> {{ range $key, $val := .Stats }} <tr> <th>{{ $key }}</th> @@ -52,6 +103,7 @@ var StatusTpl = template.Must(template.New("status").Parse(`<!DOCTYPE html> <thead> <tr> <th>Id</th> + <th>Collection</th> <th>Size</th> <th>Files</th> <th>Trash</th> @@ -62,7 +114,8 @@ var StatusTpl = template.Must(template.New("status").Parse(`<!DOCTYPE html> {{ range .Volumes }} <tr> <td><code>{{ .Id }}</code></td> - <td>{{ .Size }}</td> + <td>{{ .Collection }}</td> + <td>{{ .Size }} Bytes</td> <td>{{ .FileCount }}</td> <td>{{ .DeleteCount }} / {{.DeletedByteCount}} Bytes</td> <td>{{ .Ttl }}</td> |
