You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
2.8 KiB
95 lines
2.8 KiB
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 |
|
}
|
|
|