k6

K6 - How to add elements to an empty array and calculate the average?


I am writing a test to calculate the average transfer time for each request.

import http from 'k6/http';
import { sleep } from 'k6';
import { check } from 'k6';

export let options = {
      vus: 1, 
      duration: 5s, 
};

let transferTimes = [];

export default function () {

  const res = http.get(<url>);    
  check(res, {
    'Successful response': (resp) => resp.status === 200,
  });

  const transferTime = res.timings.duration;
  transferTimes.push(transferTime);
  console.log(`Transfer time: ${transferTime} ms`);
}

export function teardown() {
  console.log(`Length of the array: ${transferTimes.length}`);
  for (let i = 0; i < transferTimes.length; i++) {
    console.log(`Element at index ${i}: ${transferTimes[i]}`);
  }  
  const sum = transferTimes.reduce((a, b) => a + b, 0);
  console.log(`Sum: ${sum}`);
  const averageTransferTime = sum / transferTimes.length;
  console.log(`Average transfer time: ${averageTransferTime} ms`);
}

I am getting the output as:

.
.
.
INFO[0005] Transfer time: 1.164713 ms                    source=console
INFO[0005] Transfer time: 1.163952 ms                    source=console
INFO[0005] Length of the array: 0                        source=console
INFO[0005] Sum: 0                                        source=console
INFO[0005] Average transfer time: NaN ms                 source=console

For some reason the transferTimes.push(transferTime); doesn't seem to work.

What else can be done to get this working? Thanks.


Solution

  • Each VU has its own init context, which means in your case that every VU (virtual user) has its own transfer times array. This applies to the summary too: it is created in a separate "process", without access to VU-specific data of the other VUs.

    I recommend using builtin functionality of k6 to track custom metrics, such as Trend; no need to manually implement response time tracking and aggregation. Also, you don't have to worry about running out of memory, since not every data point is pushed to an array.

    In your case, you can even rely on the default metrics, which already track the number and duration of HTTP requests.

    By implementing a custom summary with the handleSummary function, you can access your metrics and thresholds and generate your desired output, e.g. data.metrics['http_req_duration{expected_response:true}']. The metrics map will contain the type and values (e.g. count, avg, min, max).