github.com/kubeshop/testkube@v1.17.23/pkg/repository/common/metrics.go (about) 1 package common 2 3 import ( 4 "time" 5 6 "github.com/montanaflynn/stats" 7 8 "github.com/kubeshop/testkube/pkg/api/v1/testkube" 9 "github.com/kubeshop/testkube/pkg/log" 10 "github.com/kubeshop/testkube/pkg/utils" 11 ) 12 13 func CalculateMetrics(executionsMetrics []testkube.ExecutionsMetricsExecutions) (metrics testkube.ExecutionsMetrics) { 14 metrics.Executions = executionsMetrics 15 var durations []float64 16 17 for j, execution := range metrics.Executions { 18 if execution.Status == string(testkube.FAILED_ExecutionStatus) { 19 metrics.FailedExecutions++ 20 } 21 metrics.TotalExecutions++ 22 23 // ignore empty and invalid durations 24 duration, err := time.ParseDuration(execution.Duration) 25 if err != nil { 26 continue 27 } 28 durations = append(durations, float64(duration)) 29 30 metrics.Executions[j].Duration = utils.RoundDuration(duration).String() 31 metrics.Executions[j].DurationMs = int32(duration / time.Millisecond) 32 } 33 34 if metrics.TotalExecutions > 0 { 35 metrics.PassFailRatio = 100 * float64(metrics.TotalExecutions-metrics.FailedExecutions) / float64(metrics.TotalExecutions) 36 } 37 38 durationP50 := time.Duration(calculate(durations, 50)) 39 durationP90 := time.Duration(calculate(durations, 90)) 40 durationP95 := time.Duration(calculate(durations, 95)) 41 durationP99 := time.Duration(calculate(durations, 99)) 42 43 metrics.ExecutionDurationP50 = utils.RoundDuration(durationP50).String() 44 metrics.ExecutionDurationP90 = utils.RoundDuration(durationP90).String() 45 metrics.ExecutionDurationP95 = utils.RoundDuration(durationP95).String() 46 metrics.ExecutionDurationP99 = utils.RoundDuration(durationP99).String() 47 48 metrics.ExecutionDurationP50ms = int32(durationP50 / time.Millisecond) 49 metrics.ExecutionDurationP90ms = int32(durationP90 / time.Millisecond) 50 metrics.ExecutionDurationP95ms = int32(durationP95 / time.Millisecond) 51 metrics.ExecutionDurationP99ms = int32(durationP99 / time.Millisecond) 52 53 return 54 } 55 56 func calculate(durations []float64, quantile float64) float64 { 57 if len(durations) == 0 { 58 return 0 59 } 60 percentile, err := stats.PercentileNearestRank(durations, quantile) 61 if err != nil { 62 log.DefaultLogger.Errorw("Unable to calculate percentile", "error", err) 63 return 0 64 } 65 return percentile 66 }