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  }