Expand upon playback metrics
This commit is contained in:
parent
d84da617b7
commit
6479220e78
@ -13,13 +13,22 @@ import (
|
||||
// GetVideoPlaybackMetrics returns video playback metrics.
|
||||
func GetVideoPlaybackMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
type response struct {
|
||||
Errors []metrics.TimestampedValue `json:"errors"`
|
||||
QualityVariantChanges []metrics.TimestampedValue `json:"qualityVariantChanges"`
|
||||
Latency []metrics.TimestampedValue `json:"latency"`
|
||||
SegmentDownloadDuration []metrics.TimestampedValue `json:"segmentDownloadDuration"`
|
||||
SlowestDownloadRate []metrics.TimestampedValue `json:"minPlayerBitrate"`
|
||||
AvailableBitrates []int `json:"availableBitrates"`
|
||||
SegmentLength int `json:"segmentLength"`
|
||||
Errors []metrics.TimestampedValue `json:"errors"`
|
||||
QualityVariantChanges []metrics.TimestampedValue `json:"qualityVariantChanges"`
|
||||
|
||||
HighestLatency []metrics.TimestampedValue `json:"highestLatency"`
|
||||
MedianLatency []metrics.TimestampedValue `json:"medianLatency"`
|
||||
LowestLatency []metrics.TimestampedValue `json:"lowestLatency"`
|
||||
|
||||
MedianDownloadDuration []metrics.TimestampedValue `json:"medianSegmentDownloadDuration"`
|
||||
MaximumDownloadDuration []metrics.TimestampedValue `json:"maximumSegmentDownloadDuration"`
|
||||
MinimumDownloadDuration []metrics.TimestampedValue `json:"minimumSegmentDownloadDuration"`
|
||||
|
||||
SlowestDownloadRate []metrics.TimestampedValue `json:"minPlayerBitrate"`
|
||||
MedianDownloadRate []metrics.TimestampedValue `json:"medianPlayerBitrate"`
|
||||
HighestDownloadRater []metrics.TimestampedValue `json:"maxPlayerBitrate"`
|
||||
AvailableBitrates []int `json:"availableBitrates"`
|
||||
SegmentLength int `json:"segmentLength"`
|
||||
}
|
||||
|
||||
availableBitrates := []int{}
|
||||
@ -37,18 +46,32 @@ func GetVideoPlaybackMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
errors := metrics.GetPlaybackErrorCountOverTime()
|
||||
latency := metrics.GetLatencyOverTime()
|
||||
durations := metrics.GetDownloadDurationsOverTime()
|
||||
medianLatency := metrics.GetMedianLatencyOverTime()
|
||||
minimumLatency := metrics.GetMinimumLatencyOverTime()
|
||||
maximumLatency := metrics.GetMaximumLatencyOverTime()
|
||||
|
||||
medianDurations := metrics.GetMedianDownloadDurationsOverTime()
|
||||
maximumDurations := metrics.GetMaximumDownloadDurationsOverTime()
|
||||
minimumDurations := metrics.GetMinimumDownloadDurationsOverTime()
|
||||
|
||||
minPlayerBitrate := metrics.GetSlowestDownloadRateOverTime()
|
||||
medianPlayerBitrate := metrics.GetMedianDownloadRateOverTime()
|
||||
maxPlayerBitrate := metrics.GetMaxDownloadRateOverTime()
|
||||
qualityVariantChanges := metrics.GetQualityVariantChangesOverTime()
|
||||
|
||||
resp := response{
|
||||
AvailableBitrates: availableBitrates,
|
||||
Errors: errors,
|
||||
Latency: latency,
|
||||
MedianLatency: medianLatency,
|
||||
HighestLatency: maximumLatency,
|
||||
LowestLatency: minimumLatency,
|
||||
SegmentLength: segmentLength,
|
||||
SegmentDownloadDuration: durations,
|
||||
MedianDownloadDuration: medianDurations,
|
||||
MaximumDownloadDuration: maximumDurations,
|
||||
MinimumDownloadDuration: minimumDurations,
|
||||
SlowestDownloadRate: minPlayerBitrate,
|
||||
MedianDownloadRate: medianPlayerBitrate,
|
||||
HighestDownloadRater: maxPlayerBitrate,
|
||||
QualityVariantChanges: qualityVariantChanges,
|
||||
}
|
||||
|
||||
|
@ -20,14 +20,24 @@ const (
|
||||
|
||||
// CollectedMetrics stores different collected + timestamped values.
|
||||
type CollectedMetrics struct {
|
||||
CPUUtilizations []TimestampedValue `json:"cpu"`
|
||||
RAMUtilizations []TimestampedValue `json:"memory"`
|
||||
DiskUtilizations []TimestampedValue `json:"disk"`
|
||||
errorCount []TimestampedValue `json:"-"`
|
||||
lowestBitrate []TimestampedValue `json:"-"`
|
||||
segmentDownloadSeconds []TimestampedValue `json:"-"`
|
||||
averageLatency []TimestampedValue `json:"-"`
|
||||
qualityVariantChanges []TimestampedValue `json:"-"`
|
||||
CPUUtilizations []TimestampedValue `json:"cpu"`
|
||||
RAMUtilizations []TimestampedValue `json:"memory"`
|
||||
DiskUtilizations []TimestampedValue `json:"disk"`
|
||||
|
||||
errorCount []TimestampedValue `json:"-"`
|
||||
lowestBitrate []TimestampedValue `json:"-"`
|
||||
medianBitrate []TimestampedValue `json:"-"`
|
||||
highestBitrate []TimestampedValue `json:"-"`
|
||||
|
||||
medianSegmentDownloadSeconds []TimestampedValue `json:"-"`
|
||||
maximumSegmentDownloadSeconds []TimestampedValue `json:"-"`
|
||||
minimumSegmentDownloadSeconds []TimestampedValue `json:"-"`
|
||||
|
||||
minimumLatency []TimestampedValue `json:"-"`
|
||||
maximumLatency []TimestampedValue `json:"-"`
|
||||
medianLatency []TimestampedValue `json:"-"`
|
||||
|
||||
qualityVariantChanges []TimestampedValue `json:"-"`
|
||||
}
|
||||
|
||||
// Metrics is the shared Metrics instance.
|
||||
|
@ -65,25 +65,57 @@ func collectPlaybackErrorCount() {
|
||||
}
|
||||
|
||||
func collectSegmentDownloadDuration() {
|
||||
val := 0.0
|
||||
median := 0.0
|
||||
max := 0.0
|
||||
min := 0.0
|
||||
|
||||
if len(windowedDownloadDurations) > 0 {
|
||||
val = utils.Avg(windowedDownloadDurations)
|
||||
median = utils.Median(windowedDownloadDurations)
|
||||
min, max = utils.MinMax(windowedDownloadDurations)
|
||||
windowedDownloadDurations = []float64{}
|
||||
}
|
||||
metrics.segmentDownloadSeconds = append(metrics.segmentDownloadSeconds, TimestampedValue{
|
||||
|
||||
metrics.medianSegmentDownloadSeconds = append(metrics.medianSegmentDownloadSeconds, TimestampedValue{
|
||||
Time: time.Now(),
|
||||
Value: val,
|
||||
Value: median,
|
||||
})
|
||||
|
||||
if len(metrics.segmentDownloadSeconds) > maxCollectionValues {
|
||||
metrics.segmentDownloadSeconds = metrics.segmentDownloadSeconds[1:]
|
||||
if len(metrics.medianSegmentDownloadSeconds) > maxCollectionValues {
|
||||
metrics.medianSegmentDownloadSeconds = metrics.medianSegmentDownloadSeconds[1:]
|
||||
}
|
||||
|
||||
metrics.minimumSegmentDownloadSeconds = append(metrics.minimumSegmentDownloadSeconds, TimestampedValue{
|
||||
Time: time.Now(),
|
||||
Value: min,
|
||||
})
|
||||
|
||||
if len(metrics.minimumSegmentDownloadSeconds) > maxCollectionValues {
|
||||
metrics.minimumSegmentDownloadSeconds = metrics.minimumSegmentDownloadSeconds[1:]
|
||||
}
|
||||
|
||||
metrics.maximumSegmentDownloadSeconds = append(metrics.maximumSegmentDownloadSeconds, TimestampedValue{
|
||||
Time: time.Now(),
|
||||
Value: max,
|
||||
})
|
||||
|
||||
if len(metrics.maximumSegmentDownloadSeconds) > maxCollectionValues {
|
||||
metrics.maximumSegmentDownloadSeconds = metrics.maximumSegmentDownloadSeconds[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// GetDownloadDurationsOverTime will return a window of durations errors over time.
|
||||
func GetDownloadDurationsOverTime() []TimestampedValue {
|
||||
return metrics.segmentDownloadSeconds
|
||||
// GetMedianDownloadDurationsOverTime will return a window of durations errors over time.
|
||||
func GetMedianDownloadDurationsOverTime() []TimestampedValue {
|
||||
return metrics.medianSegmentDownloadSeconds
|
||||
}
|
||||
|
||||
// GetMaximumDownloadDurationsOverTime will return a maximum durations errors over time.
|
||||
func GetMaximumDownloadDurationsOverTime() []TimestampedValue {
|
||||
return metrics.maximumSegmentDownloadSeconds
|
||||
}
|
||||
|
||||
// GetMinimumDownloadDurationsOverTime will return a maximum durations errors over time.
|
||||
func GetMinimumDownloadDurationsOverTime() []TimestampedValue {
|
||||
return metrics.minimumSegmentDownloadSeconds
|
||||
}
|
||||
|
||||
// GetPlaybackErrorCountOverTime will return a window of playback errors over time.
|
||||
@ -92,53 +124,113 @@ func GetPlaybackErrorCountOverTime() []TimestampedValue {
|
||||
}
|
||||
|
||||
func collectLatencyValues() {
|
||||
val := 0.0
|
||||
median := 0.0
|
||||
min := 0.0
|
||||
max := 0.0
|
||||
|
||||
if len(windowedLatencies) > 0 {
|
||||
val = utils.Avg(windowedLatencies)
|
||||
val = math.Round(val)
|
||||
median = utils.Median(windowedLatencies)
|
||||
min, max = utils.MinMax(windowedLatencies)
|
||||
windowedLatencies = []float64{}
|
||||
}
|
||||
|
||||
metrics.averageLatency = append(metrics.averageLatency, TimestampedValue{
|
||||
metrics.medianLatency = append(metrics.medianLatency, TimestampedValue{
|
||||
Time: time.Now(),
|
||||
Value: val,
|
||||
Value: median,
|
||||
})
|
||||
|
||||
if len(metrics.averageLatency) > maxCollectionValues {
|
||||
metrics.averageLatency = metrics.averageLatency[1:]
|
||||
if len(metrics.medianLatency) > maxCollectionValues {
|
||||
metrics.medianLatency = metrics.medianLatency[1:]
|
||||
}
|
||||
|
||||
metrics.minimumLatency = append(metrics.minimumLatency, TimestampedValue{
|
||||
Time: time.Now(),
|
||||
Value: min,
|
||||
})
|
||||
|
||||
if len(metrics.minimumLatency) > maxCollectionValues {
|
||||
metrics.minimumLatency = metrics.minimumLatency[1:]
|
||||
}
|
||||
|
||||
metrics.maximumLatency = append(metrics.maximumLatency, TimestampedValue{
|
||||
Time: time.Now(),
|
||||
Value: max,
|
||||
})
|
||||
|
||||
if len(metrics.maximumLatency) > maxCollectionValues {
|
||||
metrics.maximumLatency = metrics.maximumLatency[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// GetLatencyOverTime will return the min, max and avg latency values over time.
|
||||
func GetLatencyOverTime() []TimestampedValue {
|
||||
if len(metrics.averageLatency) == 0 {
|
||||
// GetMedianLatencyOverTime will return the median latency values over time.
|
||||
func GetMedianLatencyOverTime() []TimestampedValue {
|
||||
if len(metrics.medianLatency) == 0 {
|
||||
return []TimestampedValue{}
|
||||
}
|
||||
|
||||
return metrics.averageLatency
|
||||
return metrics.medianLatency
|
||||
}
|
||||
|
||||
// collectLowestBandwidth will collect the lowest bandwidth currently collected
|
||||
// GetMinimumLatencyOverTime will return the min latency values over time.
|
||||
func GetMinimumLatencyOverTime() []TimestampedValue {
|
||||
if len(metrics.minimumLatency) == 0 {
|
||||
return []TimestampedValue{}
|
||||
}
|
||||
|
||||
return metrics.minimumLatency
|
||||
}
|
||||
|
||||
// GetMaximumLatencyOverTime will return the max latency values over time.
|
||||
func GetMaximumLatencyOverTime() []TimestampedValue {
|
||||
if len(metrics.maximumLatency) == 0 {
|
||||
return []TimestampedValue{}
|
||||
}
|
||||
|
||||
return metrics.maximumLatency
|
||||
}
|
||||
|
||||
// collectLowestBandwidth will collect the bandwidth currently collected
|
||||
// so we can report to the streamer the worst possible streaming condition
|
||||
// being experienced.
|
||||
func collectLowestBandwidth() {
|
||||
val := 0.0
|
||||
min := 0.0
|
||||
median := 0.0
|
||||
max := 0.0
|
||||
|
||||
if len(windowedBandwidths) > 0 {
|
||||
val, _ = utils.MinMax(windowedBandwidths)
|
||||
val = math.Round(val)
|
||||
min, max = utils.MinMax(windowedBandwidths)
|
||||
min = math.Round(min)
|
||||
max = math.Round(max)
|
||||
median = utils.Median(windowedBandwidths)
|
||||
windowedBandwidths = []float64{}
|
||||
}
|
||||
|
||||
metrics.lowestBitrate = append(metrics.lowestBitrate, TimestampedValue{
|
||||
Time: time.Now(),
|
||||
Value: math.Round(val),
|
||||
Value: math.Round(min),
|
||||
})
|
||||
|
||||
if len(metrics.lowestBitrate) > maxCollectionValues {
|
||||
metrics.lowestBitrate = metrics.lowestBitrate[1:]
|
||||
}
|
||||
|
||||
metrics.medianBitrate = append(metrics.medianBitrate, TimestampedValue{
|
||||
Time: time.Now(),
|
||||
Value: math.Round(median),
|
||||
})
|
||||
|
||||
if len(metrics.medianBitrate) > maxCollectionValues {
|
||||
metrics.medianBitrate = metrics.medianBitrate[1:]
|
||||
}
|
||||
|
||||
metrics.highestBitrate = append(metrics.highestBitrate, TimestampedValue{
|
||||
Time: time.Now(),
|
||||
Value: math.Round(max),
|
||||
})
|
||||
|
||||
if len(metrics.highestBitrate) > maxCollectionValues {
|
||||
metrics.highestBitrate = metrics.highestBitrate[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// GetSlowestDownloadRateOverTime will return the collected lowest bandwidth values
|
||||
@ -151,6 +243,38 @@ func GetSlowestDownloadRateOverTime() []TimestampedValue {
|
||||
return metrics.lowestBitrate
|
||||
}
|
||||
|
||||
// GetMedianDownloadRateOverTime will return the collected median bandwidth values.
|
||||
func GetMedianDownloadRateOverTime() []TimestampedValue {
|
||||
if len(metrics.medianBitrate) == 0 {
|
||||
return []TimestampedValue{}
|
||||
}
|
||||
return metrics.medianBitrate
|
||||
}
|
||||
|
||||
// GetMaximumDownloadRateOverTime will return the collected maximum bandwidth values.
|
||||
func GetMaximumDownloadRateOverTime() []TimestampedValue {
|
||||
if len(metrics.maximumLatency) == 0 {
|
||||
return []TimestampedValue{}
|
||||
}
|
||||
return metrics.maximumLatency
|
||||
}
|
||||
|
||||
// GetMinimumDownloadRateOverTime will return the collected minimum bandwidth values.
|
||||
func GetMinimumDownloadRateOverTime() []TimestampedValue {
|
||||
if len(metrics.minimumLatency) == 0 {
|
||||
return []TimestampedValue{}
|
||||
}
|
||||
return metrics.minimumLatency
|
||||
}
|
||||
|
||||
// GetMaxDownloadRateOverTime will return the collected highest bandwidth values.
|
||||
func GetMaxDownloadRateOverTime() []TimestampedValue {
|
||||
if len(metrics.highestBitrate) == 0 {
|
||||
return []TimestampedValue{}
|
||||
}
|
||||
return metrics.highestBitrate
|
||||
}
|
||||
|
||||
func collectQualityVariantChanges() {
|
||||
count := utils.Sum(windowedQualityVariantChanges)
|
||||
windowedQualityVariantChanges = []float64{}
|
||||
|
@ -82,3 +82,29 @@ func MinMax(array []float64) (float64, float64) {
|
||||
}
|
||||
return min, max
|
||||
}
|
||||
|
||||
func mean(input []float64) float64 {
|
||||
sum := Sum(input)
|
||||
|
||||
return sum / float64(len(input))
|
||||
}
|
||||
|
||||
// Median gets the median number in a slice of numbers.
|
||||
func Median(input []float64) float64 {
|
||||
if len(input) == 1 {
|
||||
return input[0]
|
||||
}
|
||||
|
||||
c := make([]float64, len(input))
|
||||
copy(c, input)
|
||||
|
||||
var median float64
|
||||
l := len(c)
|
||||
if l%2 == 0 {
|
||||
median = mean(c[l/2-1 : l/2+1])
|
||||
} else {
|
||||
median = c[l/2]
|
||||
}
|
||||
|
||||
return median
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user