aboutsummaryrefslogtreecommitdiff
path: root/weed/stats
diff options
context:
space:
mode:
Diffstat (limited to 'weed/stats')
-rw-r--r--weed/stats/disk.go14
-rw-r--r--weed/stats/disk_notsupported.go7
-rw-r--r--weed/stats/disk_supported.go19
-rw-r--r--weed/stats/duration_counter.go94
-rw-r--r--weed/stats/duration_counter_test.go19
-rw-r--r--weed/stats/memory.go28
-rw-r--r--weed/stats/memory_notsupported.go7
-rw-r--r--weed/stats/memory_supported.go18
-rw-r--r--weed/stats/stats.go113
9 files changed, 319 insertions, 0 deletions
diff --git a/weed/stats/disk.go b/weed/stats/disk.go
new file mode 100644
index 000000000..46d8c465e
--- /dev/null
+++ b/weed/stats/disk.go
@@ -0,0 +1,14 @@
+package stats
+
+type DiskStatus struct {
+ Dir string
+ All uint64
+ Used uint64
+ Free uint64
+}
+
+func NewDiskStatus(path string) (disk *DiskStatus) {
+ disk = &DiskStatus{Dir: path}
+ disk.fillInStatus()
+ return
+}
diff --git a/weed/stats/disk_notsupported.go b/weed/stats/disk_notsupported.go
new file mode 100644
index 000000000..e380d27ea
--- /dev/null
+++ b/weed/stats/disk_notsupported.go
@@ -0,0 +1,7 @@
+// +build windows openbsd netbsd plan9 solaris
+
+package stats
+
+func (disk *DiskStatus) fillInStatus() {
+ return
+}
diff --git a/weed/stats/disk_supported.go b/weed/stats/disk_supported.go
new file mode 100644
index 000000000..d68f0a32e
--- /dev/null
+++ b/weed/stats/disk_supported.go
@@ -0,0 +1,19 @@
+// +build !windows,!openbsd,!netbsd,!plan9,!solaris
+
+package stats
+
+import (
+ "syscall"
+)
+
+func (disk *DiskStatus) fillInStatus() {
+ fs := syscall.Statfs_t{}
+ err := syscall.Statfs(disk.Dir, &fs)
+ if err != nil {
+ return
+ }
+ disk.All = fs.Blocks * uint64(fs.Bsize)
+ disk.Free = fs.Bfree * uint64(fs.Bsize)
+ disk.Used = disk.All - disk.Free
+ return
+}
diff --git a/weed/stats/duration_counter.go b/weed/stats/duration_counter.go
new file mode 100644
index 000000000..69c8be61d
--- /dev/null
+++ b/weed/stats/duration_counter.go
@@ -0,0 +1,94 @@
+package stats
+
+import (
+ "time"
+)
+
+type TimedValue struct {
+ t time.Time
+ val int64
+}
+
+func NewTimedValue(t time.Time, val int64) *TimedValue {
+ return &TimedValue{t: t, val: val}
+}
+
+type RoundRobinCounter struct {
+ LastIndex int
+ Values []int64
+ Counts []int64
+}
+
+func NewRoundRobinCounter(slots int) *RoundRobinCounter {
+ return &RoundRobinCounter{LastIndex: -1, Values: make([]int64, slots), Counts: make([]int64, slots)}
+}
+func (rrc *RoundRobinCounter) Add(index int, val int64) {
+ if index >= len(rrc.Values) {
+ return
+ }
+ for rrc.LastIndex != index {
+ rrc.LastIndex = (rrc.LastIndex + 1) % len(rrc.Values)
+ rrc.Values[rrc.LastIndex] = 0
+ rrc.Counts[rrc.LastIndex] = 0
+ }
+ rrc.Values[index] += val
+ rrc.Counts[index]++
+}
+func (rrc *RoundRobinCounter) Max() (max int64) {
+ for _, val := range rrc.Values {
+ if max < val {
+ max = val
+ }
+ }
+ return
+}
+func (rrc *RoundRobinCounter) Count() (cnt int64) {
+ for _, c := range rrc.Counts {
+ cnt += c
+ }
+ return
+}
+func (rrc *RoundRobinCounter) Sum() (sum int64) {
+ for _, val := range rrc.Values {
+ sum += val
+ }
+ 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
+ DayCounter *RoundRobinCounter
+ WeekCounter *RoundRobinCounter
+}
+
+func NewDurationCounter() *DurationCounter {
+ return &DurationCounter{
+ MinuteCounter: NewRoundRobinCounter(60),
+ HourCounter: NewRoundRobinCounter(60),
+ DayCounter: NewRoundRobinCounter(24),
+ WeekCounter: NewRoundRobinCounter(7),
+ }
+}
+
+// Add is for cumulative counts
+func (sc *DurationCounter) Add(tv *TimedValue) {
+ sc.MinuteCounter.Add(tv.t.Second(), tv.val)
+ sc.HourCounter.Add(tv.t.Minute(), tv.val)
+ sc.DayCounter.Add(tv.t.Hour(), tv.val)
+ sc.WeekCounter.Add(int(tv.t.Weekday()), tv.val)
+}
diff --git a/weed/stats/duration_counter_test.go b/weed/stats/duration_counter_test.go
new file mode 100644
index 000000000..aa9d61c87
--- /dev/null
+++ b/weed/stats/duration_counter_test.go
@@ -0,0 +1,19 @@
+package stats
+
+import "testing"
+
+func TestRobinCounter(t *testing.T) {
+ rrc := NewRoundRobinCounter(60)
+ rrc.Add(0, 1)
+ rrc.Add(50, 2)
+ if rrc.Count() != 2 {
+ t.Fatal()
+ }
+ if rrc.Sum() != 3 {
+ t.Fatal()
+ }
+ /*
+ index out of range
+ */
+ rrc.Add(61, 1)
+}
diff --git a/weed/stats/memory.go b/weed/stats/memory.go
new file mode 100644
index 000000000..0700d92de
--- /dev/null
+++ b/weed/stats/memory.go
@@ -0,0 +1,28 @@
+package stats
+
+import (
+ "runtime"
+)
+
+type MemStatus struct {
+ Goroutines int
+ All uint64
+ Used uint64
+ Free uint64
+ Self uint64
+ Heap uint64
+ Stack uint64
+}
+
+func MemStat() MemStatus {
+ mem := MemStatus{}
+ mem.Goroutines = runtime.NumGoroutine()
+ memStat := new(runtime.MemStats)
+ runtime.ReadMemStats(memStat)
+ mem.Self = memStat.Alloc
+ mem.Heap = memStat.HeapAlloc
+ mem.Stack = memStat.StackInuse
+
+ mem.fillInStatus()
+ return mem
+}
diff --git a/weed/stats/memory_notsupported.go b/weed/stats/memory_notsupported.go
new file mode 100644
index 000000000..ba8229364
--- /dev/null
+++ b/weed/stats/memory_notsupported.go
@@ -0,0 +1,7 @@
+// +build !linux
+
+package stats
+
+func (mem *MemStatus) fillInStatus() {
+ return
+}
diff --git a/weed/stats/memory_supported.go b/weed/stats/memory_supported.go
new file mode 100644
index 000000000..fd0c36d72
--- /dev/null
+++ b/weed/stats/memory_supported.go
@@ -0,0 +1,18 @@
+// +build linux
+
+package stats
+
+import (
+ "syscall"
+)
+
+func (mem *MemStatus) fillInStatus() {
+ //system memory usage
+ sysInfo := new(syscall.Sysinfo_t)
+ err := syscall.Sysinfo(sysInfo)
+ if err == nil {
+ mem.All = uint64(sysInfo.Totalram) //* uint64(syscall.Getpagesize())
+ mem.Free = uint64(sysInfo.Freeram) //* uint64(syscall.Getpagesize())
+ mem.Used = mem.All - mem.Free
+ }
+}
diff --git a/weed/stats/stats.go b/weed/stats/stats.go
new file mode 100644
index 000000000..09826152f
--- /dev/null
+++ b/weed/stats/stats.go
@@ -0,0 +1,113 @@
+package stats
+
+import (
+ "time"
+)
+
+type ServerStats struct {
+ Requests *DurationCounter
+ Connections *DurationCounter
+ AssignRequests *DurationCounter
+ ReadRequests *DurationCounter
+ WriteRequests *DurationCounter
+ DeleteRequests *DurationCounter
+ BytesIn *DurationCounter
+ BytesOut *DurationCounter
+}
+
+type Channels struct {
+ Connections chan *TimedValue
+ Requests chan *TimedValue
+ AssignRequests chan *TimedValue
+ ReadRequests chan *TimedValue
+ WriteRequests chan *TimedValue
+ DeleteRequests chan *TimedValue
+ BytesIn chan *TimedValue
+ BytesOut chan *TimedValue
+}
+
+var (
+ Chan *Channels
+)
+
+func init() {
+ Chan = &Channels{
+ Connections: make(chan *TimedValue, 100),
+ Requests: make(chan *TimedValue, 100),
+ AssignRequests: make(chan *TimedValue, 100),
+ ReadRequests: make(chan *TimedValue, 100),
+ WriteRequests: make(chan *TimedValue, 100),
+ DeleteRequests: make(chan *TimedValue, 100),
+ BytesIn: make(chan *TimedValue, 100),
+ BytesOut: make(chan *TimedValue, 100),
+ }
+}
+
+func NewServerStats() *ServerStats {
+ return &ServerStats{
+ Requests: NewDurationCounter(),
+ Connections: NewDurationCounter(),
+ AssignRequests: NewDurationCounter(),
+ ReadRequests: NewDurationCounter(),
+ WriteRequests: NewDurationCounter(),
+ DeleteRequests: NewDurationCounter(),
+ BytesIn: NewDurationCounter(),
+ BytesOut: NewDurationCounter(),
+ }
+}
+
+func ConnectionOpen() {
+ Chan.Connections <- NewTimedValue(time.Now(), 1)
+}
+func ConnectionClose() {
+ Chan.Connections <- NewTimedValue(time.Now(), -1)
+}
+func RequestOpen() {
+ Chan.Requests <- NewTimedValue(time.Now(), 1)
+}
+func RequestClose() {
+ Chan.Requests <- NewTimedValue(time.Now(), -1)
+}
+func AssignRequest() {
+ Chan.AssignRequests <- NewTimedValue(time.Now(), 1)
+}
+func ReadRequest() {
+ Chan.ReadRequests <- NewTimedValue(time.Now(), 1)
+}
+func WriteRequest() {
+ Chan.WriteRequests <- NewTimedValue(time.Now(), 1)
+}
+func DeleteRequest() {
+ Chan.DeleteRequests <- NewTimedValue(time.Now(), 1)
+}
+func BytesIn(val int64) {
+ Chan.BytesIn <- NewTimedValue(time.Now(), val)
+}
+func BytesOut(val int64) {
+ Chan.BytesOut <- NewTimedValue(time.Now(), val)
+}
+
+func (ss *ServerStats) Start() {
+ for {
+ select {
+ case tv := <-Chan.Connections:
+ ss.Connections.Add(tv)
+ case tv := <-Chan.Requests:
+ ss.Requests.Add(tv)
+ case tv := <-Chan.AssignRequests:
+ ss.AssignRequests.Add(tv)
+ case tv := <-Chan.ReadRequests:
+ ss.ReadRequests.Add(tv)
+ case tv := <-Chan.WriteRequests:
+ ss.WriteRequests.Add(tv)
+ case tv := <-Chan.ReadRequests:
+ ss.ReadRequests.Add(tv)
+ case tv := <-Chan.DeleteRequests:
+ ss.DeleteRequests.Add(tv)
+ case tv := <-Chan.BytesIn:
+ ss.BytesIn.Add(tv)
+ case tv := <-Chan.BytesOut:
+ ss.BytesOut.Add(tv)
+ }
+ }
+}