k6

k6 to track metrics for each URL


Following up on k6 to report test details for each URL, which I found the answer there not working for me.

Here is my script (incorporating the answer there):

import http from 'k6/http';
import { Trend, Counter, Rate } from 'k6/metrics';
import { sleep } from 'k6';

// Define URLs to test
const urls = [
  "1",
  "2",
  "5",
];

// Initialize custom metrics for each URL
const urlMetrics = {};
urls.forEach(url => {
  urlMetrics[url] = {
    responseTime: new Trend(`response_time_${url}`),
  };
});

export const options = {
  thresholds: Object.fromEntries(
    ['http_req_duration', 'http_reqs', 'http_req_failed', 'data_sent', 'data_received']
      .flatMap(metric => urls.map(url => [ `${metric}{url:${url}}`, []]))),
};
// {name:${url}} instead of url: should work too

export default function () {

  // Perform the HTTP GET request
  urls.forEach(url => {
    const fullurl = `https://postman-echo.com/delay/${url}`;
    const resp = http.get(fullurl);
    // Update custom metrics for the current URL
    urlMetrics[url].responseTime.add(resp.timings.duration);
    sleep(0.2);
  });

  // Optional: Add a small delay between requests to simulate realistic load
  sleep(1);
}

And here is its test result:

     scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop):
              * default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s)


     data_received..................: 6.5 kB 540 B/s
       { url:1 }....................: 0 B    0 B/s
       { url:2 }....................: 0 B    0 B/s
       { url:5 }....................: 0 B    0 B/s
     data_sent......................: 873 B  73 B/s
       { url:1 }....................: 0 B    0 B/s
       { url:2 }....................: 0 B    0 B/s
       { url:5 }....................: 0 B    0 B/s
     http_req_blocked...............: avg=205.62ms    min=291ns       med=440ns       max=616.87ms    p(90)=493.5ms     p(95)=555.18ms   
     http_req_connecting............: avg=66.5ms      min=0s          med=0s          max=199.5ms     p(90)=159.6ms     p(95)=179.55ms   
     http_req_duration..............: avg=3.26s       min=1.3s        med=2.2s        max=6.28s       p(90)=5.47s       p(95)=5.87s      
       { expected_response:true }...: avg=3.26s       min=1.3s        med=2.2s        max=6.28s       p(90)=5.47s       p(95)=5.87s      
       { url:1 }....................: avg=0s          min=0s          med=0s          max=0s          p(90)=0s          p(95)=0s         
       { url:2 }....................: avg=0s          min=0s          med=0s          max=0s          p(90)=0s          p(95)=0s         
       { url:5 }....................: avg=0s          min=0s          med=0s          max=0s          p(90)=0s          p(95)=0s         
     http_req_failed................: 0.00%  0 out of 3
       { url:1 }....................: 0.00%  0 out of 0
       { url:2 }....................: 0.00%  0 out of 0
       { url:5 }....................: 0.00%  0 out of 0
     http_req_receiving.............: avg=81.89µs     min=35.19µs     med=104.13µs    max=106.35µs    p(90)=105.9µs     p(95)=106.13µs   
     http_req_sending...............: avg=102.36µs    min=56.94µs     med=61.25µs     max=188.89µs    p(90)=163.36µs    p(95)=176.12µs   
     http_req_tls_handshaking.......: avg=133.61ms    min=0s          med=0s          max=400.85ms    p(90)=320.68ms    p(95)=360.76ms   
     http_req_waiting...............: avg=3.26s       min=1.3s        med=2.2s        max=6.28s       p(90)=5.47s       p(95)=5.87s      
     http_reqs......................: 3      0.249713/s
       { url:1 }....................: 0      0/s
       { url:2 }....................: 0      0/s
       { url:5 }....................: 0      0/s
     iteration_duration.............: avg=12.01s      min=12.01s      med=12.01s      max=12.01s      p(90)=12.01s      p(95)=12.01s     
     iterations.....................: 1      0.083238/s
     response_time_1................: avg=1300.799654 min=1300.799654 med=1300.799654 max=1300.799654 p(90)=1300.799654 p(95)=1300.799654
     response_time_2................: avg=2205.401012 min=2205.401012 med=2205.401012 max=2205.401012 p(90)=2205.401012 p(95)=2205.401012
     response_time_5................: avg=6287.894391 min=6287.894391 med=6287.894391 max=6287.894391 p(90)=6287.894391 p(95)=6287.894391
     vus............................: 1      min=1      max=1
     vus_max........................: 1      min=1      max=1


running (00m12.0s), 0/1 VUs, 1 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs  00m12.0s/10m0s  1/1 iters, 1 per VU

As we can see that each of the track metrics as suggested from the answer there report as zero in my case.

This is the first time that I'm trying with k6, please be patient.

My ultimate question/goal is, how to track metrics such as response time, status codes, and success rates etc on a per-URL basis, on every data point into a time series DB / .csv,

thanks


Solution

  • There's a lot going on in your question, let's see where to start.

    First of all, you don't need a custom metric to track request duration per URL. k6 provides that already out of the box via the (tagged) http_req_duration metric. So get rid of urlMetrics object and your custom Trend objects. Get rid of the urlMetrics[url].responseTime.add(…) call too.

    You define your thresholds as http_req_duration{url:1}, but your actual url is https://postman-echo.com/delay/1. There are at least two solutions around this:

    1. Define your threshold with the full url: http_req_duration{url:https://postman-echo.com/delay/1}

    2. Add user-defined tags to your requests: http.get(fullurl, { tags: { endpoint: url } }) and then match your threshold on this tag: http_req_duration{endpoint:1}

    (I thought about the template http.url`...`, but it doesn't help in your case)

    You cannot track transmitted and received data per URL out of the box (so you can't filter the data_sent and data_received metrics), but the k6 documentation has an example showing exactly how to solve this task: https://grafana.com/docs/k6/latest/examples/track-transmitted-data-per-url/

    If you want to have the tagged metrics in a time series DB, you don't even need to define thresholds. Simply perform your requests (http.get) and k6 will automatically tag all metric data points. InfluxDB will happily store the tags with each data point and you can later filter or aggregate depending on your needs.

    To summarize, if you want to have metrics per endpoint in a time series DB, such as Influx, the following script should be sufficient:

    import http from 'k6/http';
    import { sleep } from 'k6';
    
    // Define URLs to test
    const urls = [
      "1",
      "2",
      "5",
    ];
    
    export default function () {
    
      // Perform the HTTP GET request
      for (const url of urls) {
        const fullurl = `https://postman-echo.com/delay/${url}`;
        const resp = http.get(fullurl);
        sleep(0.2);
      };
    
      // Optional: Add a small delay between requests to simulate realistic load
      sleep(1);
    }
    

    And then run your script with the result output set to the appropriate value, e.g.:

    $ k6 run --out influxdb=http://influx:8086/k6 script.js
    

    You don't need to change anything else in your script and will get all (tagged) metrics ingested into InfluxDB.

    Of course, if you want to track data sent and received, you have to add one (!) custom metric and submit tagged metrics as outlined in the documentation.