2015-11-16 13:07:02 -08:00
|
|
|
package server
|
|
|
|
|
2015-11-16 13:25:25 -08:00
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"net/http"
|
2015-11-16 21:15:29 -08:00
|
|
|
"runtime"
|
2015-11-17 11:11:14 -08:00
|
|
|
"sync"
|
2015-11-16 21:15:29 -08:00
|
|
|
"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 22:56:40 -08:00
|
|
|
StatsDataVersion int
|
|
|
|
|
2015-11-16 22:46:19 -08:00
|
|
|
StartTime time.Time
|
2015-11-16 23:15:38 -08:00
|
|
|
Uptime string
|
2015-11-16 22:56:40 -08:00
|
|
|
BuildTime string
|
|
|
|
BuildHash string
|
|
|
|
|
2015-11-16 21:57:18 -08:00
|
|
|
CachedStatsLastUpdate time.Time
|
2015-11-16 20:36:50 -08:00
|
|
|
|
2015-11-16 21:15:29 -08:00
|
|
|
CurrentClientCount uint64
|
|
|
|
|
2015-11-16 21:57:18 -08:00
|
|
|
PubSubChannelCount int
|
|
|
|
|
2015-11-17 11:11:14 -08:00
|
|
|
SysMemTotalKB uint64
|
|
|
|
SysMemFreeKB uint64
|
2015-11-17 12:16:46 -08:00
|
|
|
MemoryInUseKB uint64
|
|
|
|
MemoryRSSKB uint64
|
2015-11-16 21:57:18 -08:00
|
|
|
|
2015-11-17 12:16:46 -08:00
|
|
|
MemPerClientBytes uint64
|
2015-11-16 21:57:18 -08:00
|
|
|
|
|
|
|
CpuUsagePct float64
|
|
|
|
|
2015-11-16 21:15:29 -08:00
|
|
|
ClientConnectsTotal uint64
|
|
|
|
ClientDisconnectsTotal uint64
|
|
|
|
|
|
|
|
DisconnectCodes map[string]uint64
|
2015-11-16 20:35:03 -08:00
|
|
|
|
2015-11-16 21:15:29 -08:00
|
|
|
CommandsIssuedTotal uint64
|
|
|
|
CommandsIssuedMap map[Command]uint64
|
2015-11-16 13:07:02 -08:00
|
|
|
|
2015-11-16 21:15:29 -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
|
2015-11-16 21:15:29 -08:00
|
|
|
DisconnectReasons map[string]uint64
|
2015-11-16 13:07:02 -08:00
|
|
|
}
|
|
|
|
|
2015-11-16 21:15:29 -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.
|
2015-11-16 21:15:29 -08:00
|
|
|
var Statistics = newStatsData()
|
|
|
|
|
2015-11-16 22:56:40 -08:00
|
|
|
const StatsDataVersion = 4
|
2015-11-16 21:15:29 -08:00
|
|
|
const pageSize = 4096
|
|
|
|
|
|
|
|
var cpuUsage struct {
|
|
|
|
UserTime uint64
|
2015-11-16 23:15:38 -08:00
|
|
|
SysTime uint64
|
2015-11-16 21:15:29 -08:00
|
|
|
}
|
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(),
|
2015-11-16 21:15:29 -08:00
|
|
|
CommandsIssuedMap: make(map[Command]uint64),
|
|
|
|
DisconnectCodes: make(map[string]uint64),
|
|
|
|
DisconnectReasons: make(map[string]uint64),
|
2015-11-16 22:56:40 -08:00
|
|
|
StatsDataVersion: StatsDataVersion,
|
2015-11-16 13:07:02 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-17 11:01:42 -08:00
|
|
|
// SetBuildStamp should be called from the main package to identify the git build hash and build time.
|
2015-11-16 22:56:40 -08:00
|
|
|
func SetBuildStamp(buildTime, buildHash string) {
|
|
|
|
Statistics.BuildTime = buildTime
|
|
|
|
Statistics.BuildHash = buildHash
|
|
|
|
}
|
|
|
|
|
2015-11-16 21:15:29 -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)
|
|
|
|
|
2015-11-17 12:16:46 -08:00
|
|
|
Statistics.MemoryInUseKB = m.Alloc / 1024
|
2015-11-16 21:15:29 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
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
|
|
|
|
|
2015-11-16 23:15:38 -08:00
|
|
|
Statistics.CpuUsagePct = 100 * float64(userTicks+sysTicks) / (timeDiff.Seconds() * float64(ticksPerSecond))
|
2015-11-17 12:16:46 -08:00
|
|
|
Statistics.MemoryRSSKB = uint64(pstat.Rss * pageSize / 1024)
|
|
|
|
Statistics.MemPerClientBytes = (Statistics.MemoryRSSKB * 1024) / Statistics.CurrentClientCount
|
2015-11-16 21:15:29 -08:00
|
|
|
}
|
2015-11-17 11:01:42 -08:00
|
|
|
updateSysMem()
|
2015-11-16 21:15:29 -08:00
|
|
|
}
|
2015-11-16 21:57:18 -08:00
|
|
|
|
|
|
|
{
|
|
|
|
ChatSubscriptionLock.RLock()
|
|
|
|
Statistics.PubSubChannelCount = len(ChatSubscriptionInfo)
|
|
|
|
ChatSubscriptionLock.RUnlock()
|
|
|
|
|
2015-11-18 09:07:34 -08:00
|
|
|
GlobalSubscriptionLock.RLock()
|
|
|
|
Statistics.CurrentClientCount = uint64(len(GlobalSubscriptionInfo))
|
|
|
|
GlobalSubscriptionLock.RUnlock()
|
2015-11-16 21:57:18 -08:00
|
|
|
}
|
2015-11-16 22:46:19 -08:00
|
|
|
|
|
|
|
{
|
2015-11-16 23:15:38 -08:00
|
|
|
Statistics.Uptime = nowUpdate.Sub(Statistics.StartTime).String()
|
2015-11-16 22:46:19 -08:00
|
|
|
}
|
2015-11-16 21:15:29 -08:00
|
|
|
}
|
2015-11-16 13:25:25 -08:00
|
|
|
|
2015-11-17 11:01:42 -08:00
|
|
|
var sysMemLastUpdate time.Time
|
|
|
|
var sysMemUpdateLock sync.Mutex
|
|
|
|
|
|
|
|
func updateSysMem() {
|
|
|
|
if time.Now().Add(-2 * time.Second).After(sysMemLastUpdate) {
|
|
|
|
sysMemUpdateLock.Lock()
|
|
|
|
defer sysMemUpdateLock.Unlock()
|
|
|
|
if !time.Now().Add(-2 * time.Second).After(sysMemLastUpdate) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
sysMemLastUpdate = time.Now()
|
|
|
|
memInfo, err := linuxproc.ReadMemInfo("/proc/meminfo")
|
|
|
|
if err == nil {
|
2015-11-17 11:11:14 -08:00
|
|
|
Statistics.SysMemTotalKB = memInfo.MemTotal
|
|
|
|
Statistics.SysMemFreeKB = memInfo.MemAvailable
|
2015-11-17 11:01:42 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-16 13:25:25 -08:00
|
|
|
func HTTPShowStatistics(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
2015-11-16 21:15:29 -08:00
|
|
|
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)
|
|
|
|
}
|