import { TRANSACTION_DURATION } from '../../../common/elasticsearch_fieldnames' ; import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions' ; import { mergeProjection } from '../../projections/util/merge_projection' ; import { SetupUX } from './route' ; export const MICRO_TO_SEC = 1000000 ; export function microToSec ( val ) { return Math . round ( ( val / MICRO_TO_SEC + Number . EPSILON ) * 100 ) / 100 ; } export function removeZeroesFromTail ( distData ) { if ( distData . length > 0 ) { while ( distData [ distData . length - 1 ] . y === 0 ) { distData . pop ( ) ; } } return distData ; } export const getPLDChartSteps = ( { maxDuration , minDuration , initStepValue , } ) => { let stepValue = 0.5 ; if ( maxDuration - minDuration <= 5 * MICRO_TO_SEC ) { stepValue = 0.1 ; } if ( initStepValue ) { stepValue = initStepValue ; } let initValue = minDuration ; const stepValues = [ initValue ] ; while ( initValue < maxDuration ) { initValue += stepValue * MICRO_TO_SEC ; stepValues . push ( initValue ) ; } return stepValues ; } ; export async function getPageLoadDistribution ( { setup , minPercentile , maxPercentile , urlQuery , start , end , } ) { const projection = getRumPageLoadTransactionsProjection ( { setup , urlQuery , start , end , } ) ; let maxDuration = ( maxPercentile ? + maxPercentile : 50 ) * MICRO_TO_SEC ; const minDuration = minPercentile ? + minPercentile * MICRO_TO_SEC : 0 ; const stepValues = getPLDChartSteps ( { maxDuration , minDuration , } ) ; const params = mergeProjection ( projection , { body : { size : 0 , aggs : { durPercentiles : { percentiles : { field : TRANSACTION_DURATION , percents : [ 50 , 75 , 90 , 95 , 99 ] , hdr : { number_of_significant_value_digits : 3 , } , } , } , loadDistribution : { percentile_ranks : { field : TRANSACTION_DURATION , values : stepValues , keyed : false , hdr : { number_of_significant_value_digits : 3 , } , } , } , } , } , } ) ; const { apmEventClient } = setup ; const { aggregations , hits : { total } , } = await apmEventClient . search ( 'get_page_load_distribution' , params ) ; if ( total . value === 0 ) { return null ; } const { durPercentiles , loadDistribution } = aggregations ?? { } ; let pageDistVals = loadDistribution ?. values ?? [ ] ; const maxPercQuery = durPercentiles ?. values [ '99.0' ] ?? 0 ; if ( maxPercQuery > maxDuration && ! maxPercentile ) { const additionalStepsPageVals = await getPercentilesDistribution ( { setup , maxDuration : maxPercQuery , minDuration : maxDuration , start , end , } ) ; pageDistVals = pageDistVals . concat ( additionalStepsPageVals ) ; maxDuration = maxPercQuery ; } let pageDist = pageDistVals . map ( ( { key , value : maybeNullValue } , index , arr ) => { const value = maybeNullValue ! ; return { x : microToSec ( key ) , y : index === 0 ? value : value - arr [ index - 1 ] . value ! , } ; } ) ; pageDist = removeZeroesFromTail ( pageDist ) ; Object . entries ( durPercentiles ?. values ?? { } ) . forEach ( ( [ key , val ] ) => { if ( durPercentiles ?. values ?. [ key ] ) { durPercentiles . values [ key ] = microToSec ( val as number ) ; } } ) ; return { pageLoadDistribution : pageDist , percentiles : durPercentiles ?. values , minDuration : microToSec ( minDuration ) , maxDuration : microToSec ( maxDuration ) , } ; } const getPercentilesDistribution = async ( { setup , minDuration , maxDuration , start , end , } ) => { const stepValues = getPLDChartSteps ( { minDuration : minDuration + 0.5 * MICRO_TO_SEC , maxDuration , initStepValue : 0.5 , } ) ; const projection = getRumPageLoadTransactionsProjection ( { setup , start , end , } ) ; const params = mergeProjection ( projection , { body : { size : 0 , aggs : { loadDistribution : { percentile_ranks : { field : TRANSACTION_DURATION , values : stepValues , keyed : false , hdr : { number_of_significant_value_digits : 3 , } , } , } , } , } , } ) ; const { apmEventClient } = setup ; const { aggregations } = await apmEventClient . search ( 'get_page_load_distribution' , params ) ; return aggregations ?. loadDistribution . values ?? [ ] ; } ;