forked from cwtch.im/cwtch
Merge branch 'server-metrics' of dan/cwtch into master
This commit is contained in:
commit
e0396c6c8e
|
@ -1,6 +1,9 @@
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -46,7 +49,21 @@ func (c *counter) GetStarttime() time.Time {
|
||||||
return c.startTime
|
return c.startTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MonitorType controls how the monitor will report itself
|
||||||
|
type MonitorType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Count indicates the monitor should report in interger format
|
||||||
|
Count MonitorType = iota
|
||||||
|
// Percent indicates the monitor should report in decimal format with 2 places
|
||||||
|
Percent
|
||||||
|
// MegaBytes indicates the monitor should transform the raw number into MBs
|
||||||
|
MegaBytes
|
||||||
|
)
|
||||||
|
|
||||||
type monitorHistory struct {
|
type monitorHistory struct {
|
||||||
|
monitorType MonitorType
|
||||||
|
|
||||||
starttime time.Time
|
starttime time.Time
|
||||||
perMinutePerHour [60]float64
|
perMinutePerHour [60]float64
|
||||||
timeLastHourRotate time.Time
|
timeLastHourRotate time.Time
|
||||||
|
@ -74,11 +91,13 @@ type MonitorHistory interface {
|
||||||
Days() []float64
|
Days() []float64
|
||||||
Weeks() []float64
|
Weeks() []float64
|
||||||
Months() []float64
|
Months() []float64
|
||||||
|
|
||||||
|
Report(w *bufio.Writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMonitorHistory returns a new MonitorHistory with starttime of time.Now and Started running with supplied monitor
|
// NewMonitorHistory returns a new MonitorHistory with starttime of time.Now and Started running with supplied monitor
|
||||||
func NewMonitorHistory(monitor func() float64) MonitorHistory {
|
func NewMonitorHistory(t MonitorType, monitor func() float64) MonitorHistory {
|
||||||
mh := &monitorHistory{starttime: time.Now(), monitor: monitor, breakChannel: make(chan bool)}
|
mh := &monitorHistory{monitorType: t, starttime: time.Now(), monitor: monitor, breakChannel: make(chan bool)}
|
||||||
mh.Start()
|
mh.Start()
|
||||||
return mh
|
return mh
|
||||||
}
|
}
|
||||||
|
@ -118,6 +137,30 @@ func (mh *monitorHistory) Months() []float64 {
|
||||||
return mh.returnCopy(mh.perMonthForYear[:])
|
return mh.returnCopy(mh.perMonthForYear[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mh *monitorHistory) Report(w *bufio.Writer) {
|
||||||
|
fmt.Fprintln(w, "Minutes:", reportLine(mh.monitorType, mh.perMinutePerHour[:]))
|
||||||
|
fmt.Fprintln(w, "Hours: ", reportLine(mh.monitorType, mh.perHourForDay[:]))
|
||||||
|
fmt.Fprintln(w, "Days: ", reportLine(mh.monitorType, mh.perDayForWeek[:]))
|
||||||
|
fmt.Fprintln(w, "Weeks: ", reportLine(mh.monitorType, mh.perWeekForMonth[:]))
|
||||||
|
fmt.Fprintln(w, "Months: ", reportLine(mh.monitorType, mh.perMonthForYear[:]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func reportLine(t MonitorType, array []float64) string {
|
||||||
|
switch t {
|
||||||
|
case Count:
|
||||||
|
return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(array)), " "), "[]")
|
||||||
|
case Percent:
|
||||||
|
return strings.Trim(strings.Join(strings.Fields(fmt.Sprintf("%.2f", array)), " "), "[]")
|
||||||
|
case MegaBytes:
|
||||||
|
mbs := make([]int, len(array))
|
||||||
|
for i, b := range array {
|
||||||
|
mbs[i] = int(b) / 1024 / 1024
|
||||||
|
}
|
||||||
|
return strings.Trim(strings.Join(strings.Fields(fmt.Sprintf("%d", mbs)), "MBs "), "[]") + "MBs"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (mh *monitorHistory) returnCopy(slice []float64) []float64 {
|
func (mh *monitorHistory) returnCopy(slice []float64) []float64 {
|
||||||
retSlice := make([]float64, len(slice))
|
retSlice := make([]float64, len(slice))
|
||||||
mh.lock.Lock()
|
mh.lock.Lock()
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
||||||
"github.com/struCoder/pidusage"
|
"github.com/struCoder/pidusage"
|
||||||
"log"
|
"log"
|
||||||
|
@ -8,24 +10,30 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
reportFile = "serverMonitorReport.txt"
|
||||||
|
)
|
||||||
|
|
||||||
// Monitors is a package of metrics for a Cwtch Server including message count, CPU, Mem, and conns
|
// Monitors is a package of metrics for a Cwtch Server including message count, CPU, Mem, and conns
|
||||||
type Monitors struct {
|
type Monitors struct {
|
||||||
MessageCounter Counter
|
MessageCounter Counter
|
||||||
Messages MonitorHistory
|
Messages MonitorHistory
|
||||||
CPU MonitorHistory
|
CPU MonitorHistory
|
||||||
Memory MonitorHistory
|
Memory MonitorHistory
|
||||||
ClientListenConns MonitorHistory
|
ClientConns MonitorHistory
|
||||||
breakChannel chan bool
|
starttime time.Time
|
||||||
|
breakChannel chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start initializes a Monitors's monitors
|
// Start initializes a Monitors's monitors
|
||||||
func (mp *Monitors) Start(ra *application.RicochetApplication) {
|
func (mp *Monitors) Start(ra *application.RicochetApplication) {
|
||||||
|
mp.starttime = time.Now()
|
||||||
mp.breakChannel = make(chan bool)
|
mp.breakChannel = make(chan bool)
|
||||||
mp.MessageCounter = NewCounter()
|
mp.MessageCounter = NewCounter()
|
||||||
mp.Messages = NewMonitorHistory(func() (c float64) { c = float64(mp.MessageCounter.Count()); mp.MessageCounter.Reset(); return })
|
mp.Messages = NewMonitorHistory(Count, func() (c float64) { c = float64(mp.MessageCounter.Count()); mp.MessageCounter.Reset(); return })
|
||||||
mp.CPU = NewMonitorHistory(func() float64 { sysInfo, _ := pidusage.GetStat(os.Getpid()); return float64(sysInfo.CPU) })
|
mp.CPU = NewMonitorHistory(Percent, func() float64 { sysInfo, _ := pidusage.GetStat(os.Getpid()); return float64(sysInfo.CPU) })
|
||||||
mp.Memory = NewMonitorHistory(func() float64 { sysInfo, _ := pidusage.GetStat(os.Getpid()); return float64(sysInfo.Memory) })
|
mp.Memory = NewMonitorHistory(MegaBytes, func() float64 { sysInfo, _ := pidusage.GetStat(os.Getpid()); return float64(sysInfo.Memory) })
|
||||||
mp.ClientListenConns = NewMonitorHistory(func() float64 { return float64(ra.ConnectionCount()) })
|
mp.ClientConns = NewMonitorHistory(Count, func() float64 { return float64(ra.ConnectionCount()) })
|
||||||
|
|
||||||
// Todo: replace with proper reporting
|
// Todo: replace with proper reporting
|
||||||
go mp.log()
|
go mp.log()
|
||||||
|
@ -38,19 +46,48 @@ func (mp *Monitors) log() {
|
||||||
messageMinutes := mp.Messages.Minutes()
|
messageMinutes := mp.Messages.Minutes()
|
||||||
cpuMinutes := mp.CPU.Minutes()
|
cpuMinutes := mp.CPU.Minutes()
|
||||||
memoryMinutes := mp.Memory.Minutes()
|
memoryMinutes := mp.Memory.Minutes()
|
||||||
listenConnsMinutes := mp.ClientListenConns.Minutes()
|
listenConnsMinutes := mp.ClientConns.Minutes()
|
||||||
log.Printf("METRICS: Messages: %.0f ClientListenConns: %.0f CPU: %.2f Memory: %.0f\n", messageMinutes[0], listenConnsMinutes[0], cpuMinutes[0], memoryMinutes[0])
|
log.Printf("METRICS: Messages: %.0f ClientConns: %.0f CPU: %.2f Memory: %.0fMBs\n", messageMinutes[0], listenConnsMinutes[0], cpuMinutes[0], memoryMinutes[0]/1024/1024)
|
||||||
|
mp.report()
|
||||||
case <-mp.breakChannel:
|
case <-mp.breakChannel:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mp *Monitors) report() {
|
||||||
|
f, err := os.Create(reportFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("ERROR: Could not open monitor reporting file: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
w := bufio.NewWriter(f)
|
||||||
|
|
||||||
|
fmt.Fprintln(w, "Started: ", mp.starttime, "\n")
|
||||||
|
|
||||||
|
fmt.Fprintln(w, "Messages:")
|
||||||
|
mp.Messages.Report(w)
|
||||||
|
|
||||||
|
fmt.Fprintln(w, "\nClient Connections:")
|
||||||
|
mp.ClientConns.Report(w)
|
||||||
|
|
||||||
|
fmt.Fprintln(w, "\nCPU:")
|
||||||
|
mp.CPU.Report(w)
|
||||||
|
|
||||||
|
fmt.Fprintln(w, "\nMemory:")
|
||||||
|
mp.Memory.Report(w)
|
||||||
|
|
||||||
|
w.Flush()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Stop stops all the monitors in a Monitors
|
// Stop stops all the monitors in a Monitors
|
||||||
func (mp *Monitors) Stop() {
|
func (mp *Monitors) Stop() {
|
||||||
mp.breakChannel <- true
|
mp.breakChannel <- true
|
||||||
mp.Messages.Stop()
|
mp.Messages.Stop()
|
||||||
mp.CPU.Stop()
|
mp.CPU.Stop()
|
||||||
mp.Memory.Stop()
|
mp.Memory.Stop()
|
||||||
mp.ClientListenConns.Stop()
|
mp.ClientConns.Stop()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue