1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 21:05:53 +00:00
FrankerFaceZ/socketserver/server/stats.go

129 lines
2.9 KiB
Go
Raw Normal View History

2015-11-16 13:07:02 -08:00
package server
2015-11-16 13:25:25 -08:00
import (
"bytes"
"encoding/json"
"net/http"
"runtime"
"time"
linuxproc "github.com/c9s/goprocinfo/linux"
2015-11-16 13:25:25 -08:00
)
2015-11-16 13:07:02 -08:00
type StatsData struct {
2015-11-16 20:36:50 -08:00
Version int
2015-11-16 22:46:19 -08:00
StartTime time.Time
Uptime time.Duration
2015-11-16 21:57:18 -08:00
CachedStatsLastUpdate time.Time
2015-11-16 20:36:50 -08:00
CurrentClientCount uint64
2015-11-16 21:57:18 -08:00
PubSubChannelCount int
MemoryInUse uint64
MemoryRSS uint64
MemoryPerClient uint64
CpuUsagePct float64
ClientConnectsTotal uint64
ClientDisconnectsTotal uint64
DisconnectCodes map[string]uint64
2015-11-16 20:35:03 -08:00
CommandsIssuedTotal uint64
CommandsIssuedMap map[Command]uint64
2015-11-16 13:07:02 -08:00
MessagesSent uint64
2015-11-16 13:07:02 -08:00
2015-11-16 21:57:18 -08:00
EmotesReportedTotal uint64
2015-11-16 13:25:25 -08:00
2015-11-16 20:36:50 -08:00
// DisconnectReasons is at the bottom because it has indeterminate size
DisconnectReasons map[string]uint64
2015-11-16 13:07:02 -08:00
}
// Statistics is several variables that get incremented during normal operation of the server.
// Its structure should be versioned as it is exposed via JSON.
2015-11-16 21:57:18 -08:00
//
// Note as to threaded access - this is soft/fun data and not critical to data integrity.
// I don't really care.
var Statistics = newStatsData()
2015-11-16 21:57:18 -08:00
const StatsDataVersion = 3
const pageSize = 4096
var cpuUsage struct {
UserTime uint64
SysTime uint64
}
2015-11-16 13:25:25 -08:00
2015-11-16 13:07:02 -08:00
func newStatsData() *StatsData {
return &StatsData{
2015-11-16 22:46:19 -08:00
StartTime: time.Now(),
CommandsIssuedMap: make(map[Command]uint64),
DisconnectCodes: make(map[string]uint64),
DisconnectReasons: make(map[string]uint64),
2015-11-16 13:25:25 -08:00
Version: StatsDataVersion,
2015-11-16 13:07:02 -08:00
}
}
func updateStatsIfNeeded() {
if time.Now().Add(-2 * time.Second).After(Statistics.CachedStatsLastUpdate) {
updatePeriodicStats()
}
}
func updatePeriodicStats() {
nowUpdate := time.Now()
timeDiff := nowUpdate.Sub(Statistics.CachedStatsLastUpdate)
Statistics.CachedStatsLastUpdate = nowUpdate
{
m := runtime.MemStats{}
runtime.ReadMemStats(&m)
Statistics.MemoryInUse = m.Alloc
}
{
pstat, err := linuxproc.ReadProcessStat("/proc/self/stat")
if err == nil {
userTicks := pstat.Utime - cpuUsage.UserTime
sysTicks := pstat.Stime - cpuUsage.SysTime
cpuUsage.UserTime = pstat.Utime
cpuUsage.SysTime = pstat.Stime
Statistics.CpuUsagePct = 100 * float64(userTicks + sysTicks) / (timeDiff.Seconds() * float64(ticksPerSecond))
2015-11-16 21:57:18 -08:00
Statistics.MemoryRSS = uint64(pstat.Rss * pageSize)
Statistics.MemoryPerClient = Statistics.MemoryRSS / Statistics.CurrentClientCount
}
}
2015-11-16 21:57:18 -08:00
{
ChatSubscriptionLock.RLock()
Statistics.PubSubChannelCount = len(ChatSubscriptionInfo)
ChatSubscriptionLock.RUnlock()
GlobalSubscriptionInfo.RLock()
Statistics.CurrentClientCount = uint64(len(GlobalSubscriptionInfo.Members))
GlobalSubscriptionInfo.RUnlock()
}
2015-11-16 22:46:19 -08:00
{
Statistics.Uptime = nowUpdate.Sub(Statistics.StartTime)
}
}
2015-11-16 13:25:25 -08:00
func HTTPShowStatistics(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
updateStatsIfNeeded()
2015-11-16 13:25:25 -08:00
jsonBytes, _ := json.Marshal(Statistics)
outBuf := bytes.NewBuffer(nil)
json.Indent(outBuf, jsonBytes, "", "\t")
outBuf.WriteTo(w)
}