Persist time series viewer metrics (#1752)

* WIP persisting time series viewer metrics. Closes #1478

* Remove unused var, move around initial collection
This commit is contained in:
Gabe Kangas
2022-03-06 19:43:57 -08:00
committed by GitHub
parent 1f05783d9a
commit 1ed1cc01eb
6 changed files with 69 additions and 21 deletions

View File

@@ -13,15 +13,11 @@ import (
// How often we poll for updates.
const metricsPollingInterval = 1 * time.Minute
var _getStatus func() models.Status
// CollectedMetrics stores different collected + timestamped values.
type CollectedMetrics struct {
CPUUtilizations []timestampedValue `json:"cpu"`
RAMUtilizations []timestampedValue `json:"memory"`
DiskUtilizations []timestampedValue `json:"disk"`
Viewers []timestampedValue `json:"-"`
}
// Metrics is the shared Metrics instance.
@@ -29,8 +25,6 @@ var Metrics *CollectedMetrics
// Start will begin the metrics collection and alerting.
func Start(getStatus func() models.Status) {
_getStatus = getStatus
host := data.GetServerURL()
if host == "" {
host = "unknown"
@@ -72,7 +66,6 @@ func Start(getStatus func() models.Status) {
Metrics = new(CollectedMetrics)
go startViewerCollectionMetrics()
handlePolling()
for range time.Tick(metricsPollingInterval) {
handlePolling()

View File

@@ -1,8 +1,21 @@
package metrics
import "time"
import (
"time"
"github.com/nakabonne/tstorage"
)
type timestampedValue struct {
Time time.Time `json:"time"`
Value int `json:"value"`
}
func makeTimestampedValuesFromDatapoints(dp []*tstorage.DataPoint) []timestampedValue {
tv := []timestampedValue{}
for _, d := range dp {
tv = append(tv, timestampedValue{Time: time.Unix(d.Timestamp, 0), Value: int(d.Value)})
}
return tv
}

View File

@@ -3,15 +3,27 @@ package metrics
import (
"time"
"github.com/nakabonne/tstorage"
"github.com/owncast/owncast/core"
"github.com/owncast/owncast/core/chat"
"github.com/owncast/owncast/core/data"
log "github.com/sirupsen/logrus"
)
// How often we poll for updates.
const viewerMetricsPollingInterval = 2 * time.Minute
var storage tstorage.Storage
func startViewerCollectionMetrics() {
storage, _ = tstorage.NewStorage(
tstorage.WithTimestampPrecision(tstorage.Seconds),
tstorage.WithDataPath("./data/metrics"),
)
defer storage.Close()
collectViewerCount()
handlePolling()
for range time.Tick(viewerMetricsPollingInterval) {
collectViewerCount()
@@ -19,16 +31,15 @@ func startViewerCollectionMetrics() {
}
func collectViewerCount() {
if len(Metrics.Viewers) > maxCollectionValues {
Metrics.Viewers = Metrics.Viewers[1:]
// Don't collect metrics for viewers if there's no stream active.
if !core.GetStatus().Online {
return
}
}
count := _getStatus().ViewerCount
value := timestampedValue{
Value: count,
Time: time.Now(),
}
Metrics.Viewers = append(Metrics.Viewers, value)
func collectChatClientCount() {
count := len(chat.GetClients())
activeChatClientCount.Set(float64(count))
// Save to our Prometheus collector.
activeViewerCount.Set(float64(count))
@@ -40,9 +51,24 @@ func collectViewerCount() {
// Total user count
uc := data.GetUsersCount()
chatUserCount.Set(float64(uc))
if err := storage.InsertRows([]tstorage.Row{
{
Metric: "viewercount",
DataPoint: tstorage.DataPoint{Timestamp: time.Now().Unix(), Value: float64(count)},
},
}); err != nil {
log.Errorln(err)
}
}
func collectChatClientCount() {
count := len(chat.GetClients())
activeChatClientCount.Set(float64(count))
// GetViewersOverTime will return a window of viewer counts over time.
func GetViewersOverTime(start, end time.Time) []timestampedValue {
p, err := storage.Select("viewercount", nil, start.Unix(), end.Unix())
if err != nil && err != tstorage.ErrNoDataPoints {
log.Errorln(err)
}
datapoints := makeTimestampedValuesFromDatapoints(p)
return datapoints
}