owncast/metrics/healthOverview.go

96 lines
2.8 KiB
Go
Raw Normal View History

package metrics
import (
"fmt"
"sort"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models"
)
var errorMessages = map[string]string{
"LOWSPEED": "%d of %d clients (%d%%) are consuming video slower than, or too close to your bitrate of %d kbps.",
"PLAYBACK_ERRORS": "%d of %d clients (%d%%) are experiencing different, unspecified, playback issues.",
}
// GetStreamHealthOverview will return the stream health overview.
func GetStreamHealthOverview() *models.StreamHealthOverview {
return metrics.streamHealthOverview
}
func generateStreamHealthOverview() {
overview := models.StreamHealthOverview{
Healthy: true,
HealthyPercentage: 100,
}
defer func() {
metrics.streamHealthOverview = &overview
}()
type singleVariant struct {
isVideoPassthrough bool
bitrate int
}
outputVariants := data.GetStreamOutputVariants()
streamSortVariants := make([]singleVariant, len(outputVariants))
for i, variant := range outputVariants {
variantSort := singleVariant{
bitrate: variant.VideoBitrate,
isVideoPassthrough: variant.IsVideoPassthrough,
}
streamSortVariants[i] = variantSort
}
sort.Slice(streamSortVariants, func(i, j int) bool {
if streamSortVariants[i].isVideoPassthrough && !streamSortVariants[j].isVideoPassthrough {
return true
}
if !streamSortVariants[i].isVideoPassthrough && streamSortVariants[j].isVideoPassthrough {
return false
}
return streamSortVariants[i].bitrate > streamSortVariants[j].bitrate
})
lowestSupportedBitrate := float64(streamSortVariants[0].bitrate)
totalNumberOfClients := len(windowedBandwidths)
if totalNumberOfClients == 0 {
return
}
// Determine healthy status based on bandwidth speeds of clients.
unhealthyClientCount := 0
for _, speed := range windowedBandwidths {
if int(speed) < int(lowestSupportedBitrate*1.1) {
unhealthyClientCount++
}
}
if unhealthyClientCount > 0 {
overview.Message = fmt.Sprintf(errorMessages["LOWSPEED"], unhealthyClientCount, totalNumberOfClients, int((float64(unhealthyClientCount)/float64(totalNumberOfClients))*100), int(lowestSupportedBitrate))
}
// If bandwidth is ok, determine healthy status based on error
// counts of clients.
if unhealthyClientCount == 0 {
for _, errors := range windowedErrorCounts {
unhealthyClientCount += int(errors)
}
if unhealthyClientCount > 0 {
overview.Message = fmt.Sprintf(errorMessages["PLAYBACK_ERRORS"], unhealthyClientCount, totalNumberOfClients, int((float64(unhealthyClientCount)/float64(totalNumberOfClients))*100))
}
}
if unhealthyClientCount == 0 {
return
}
percentUnhealthy := 100 - ((float64(unhealthyClientCount) / float64(totalNumberOfClients)) * 100)
overview.HealthyPercentage = int(percentUnhealthy)
overview.Healthy = overview.HealthyPercentage > 95
}