From 3eb1670dd98dae6a7a4510c52bb3ac5234f387f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20SZKIBA?= Date: Mon, 16 Oct 2023 16:07:24 +0200 Subject: [PATCH 1/4] feat: Add missing charts to the "TIMINGS" tab sections HTTP - Request Failed Rate - Request Rate - Request Blocked Browser - Request Failed Rate - WebSockets - Transfer Rate - Sessions Rate gRPC - Transfer Rate - Streams Rate Closes #77 --- .../assets/packages/config/dist/config.json | 108 ++++++++++++++++-- .../assets/packages/config/src/config.js | 36 ++++++ 2 files changed, 133 insertions(+), 11 deletions(-) diff --git a/dashboard/assets/packages/config/dist/config.json b/dashboard/assets/packages/config/dist/config.json index 3328148..aa29676 100644 --- a/dashboard/assets/packages/config/dist/config.json +++ b/dashboard/assets/packages/config/dist/config.json @@ -138,6 +138,26 @@ "id": "tab-1.section-0.panel-0", "kind": "chart" }, + { + "series": [ + { + "query": "http_req_failed[?!tags && rate ]" + } + ], + "title": "Request Failed Rate", + "id": "tab-1.section-0.panel-1", + "kind": "chart" + }, + { + "series": [ + { + "query": "http_reqs[?!tags && rate]" + } + ], + "title": "Request Rate", + "id": "tab-1.section-0.panel-2", + "kind": "chart" + }, { "series": [ { @@ -145,7 +165,7 @@ } ], "title": "Request Waiting", - "id": "tab-1.section-0.panel-1", + "id": "tab-1.section-0.panel-3", "kind": "chart" }, { @@ -155,7 +175,7 @@ } ], "title": "TLS handshaking", - "id": "tab-1.section-0.panel-2", + "id": "tab-1.section-0.panel-4", "kind": "chart" }, { @@ -165,7 +185,7 @@ } ], "title": "Request Sending", - "id": "tab-1.section-0.panel-3", + "id": "tab-1.section-0.panel-5", "kind": "chart" }, { @@ -175,7 +195,7 @@ } ], "title": "Request Connecting", - "id": "tab-1.section-0.panel-4", + "id": "tab-1.section-0.panel-6", "kind": "chart" }, { @@ -185,7 +205,17 @@ } ], "title": "Request Receiving", - "id": "tab-1.section-0.panel-5", + "id": "tab-1.section-0.panel-7", + "kind": "chart" + }, + { + "series": [ + { + "query": "http_req_blocked[?!tags && (avg || p90 || p95 || p99)]" + } + ], + "title": "Request Blocked", + "id": "tab-1.section-0.panel-8", "kind": "chart" } ], @@ -205,6 +235,16 @@ "id": "tab-1.section-1.panel-0", "kind": "chart" }, + { + "series": [ + { + "query": "browser_http_req_failed[?!tags && rate ]" + } + ], + "title": "Request Failed Rate", + "id": "tab-1.section-1.panel-1", + "kind": "chart" + }, { "series": [ { @@ -212,7 +252,7 @@ } ], "title": "Largest Contentful Paint", - "id": "tab-1.section-1.panel-1", + "id": "tab-1.section-1.panel-2", "kind": "chart" }, { @@ -222,7 +262,7 @@ } ], "title": "First Input Delay", - "id": "tab-1.section-1.panel-2", + "id": "tab-1.section-1.panel-3", "kind": "chart" }, { @@ -232,7 +272,7 @@ } ], "title": "Cumulative Layout Shift", - "id": "tab-1.section-1.panel-3", + "id": "tab-1.section-1.panel-4", "kind": "chart" }, { @@ -242,7 +282,7 @@ } ], "title": "Time to First Byte", - "id": "tab-1.section-1.panel-4", + "id": "tab-1.section-1.panel-5", "kind": "chart" }, { @@ -252,7 +292,7 @@ } ], "title": "First Contentful Paint", - "id": "tab-1.section-1.panel-5", + "id": "tab-1.section-1.panel-6", "kind": "chart" }, { @@ -262,7 +302,7 @@ } ], "title": "Interaction to Next Paint", - "id": "tab-1.section-1.panel-6", + "id": "tab-1.section-1.panel-7", "kind": "chart" } ], @@ -301,6 +341,29 @@ "title": "Pong Duration", "id": "tab-1.section-2.panel-2", "kind": "chart" + }, + { + "series": [ + { + "query": "ws_msgs_sent[?!tags && rate]" + }, + { + "query": "ws_msgs_received[?!tags && rate]" + } + ], + "title": "Transfer Rate", + "id": "tab-1.section-2.panel-3", + "kind": "chart" + }, + { + "series": [ + { + "query": "ws_sessions[?!tags && rate]" + } + ], + "title": "Sessions Rate", + "id": "tab-1.section-2.panel-4", + "kind": "chart" } ], "title": "WebSocket", @@ -318,6 +381,29 @@ "title": "Request Duration", "id": "tab-1.section-3.panel-0", "kind": "chart" + }, + { + "series": [ + { + "query": "grpc_streams_msgs_sent[?!tags && rate]" + }, + { + "query": "grpc_streams_msgs_received[?!tags && rate]" + } + ], + "title": "Transfer Rate", + "id": "tab-1.section-3.panel-1", + "kind": "chart" + }, + { + "series": [ + { + "query": "grpc_streams[?!tags && rate]" + } + ], + "title": "Streams Rate", + "id": "tab-1.section-3.panel-2", + "kind": "chart" } ], "title": "gRPC", diff --git a/dashboard/assets/packages/config/src/config.js b/dashboard/assets/packages/config/src/config.js index 6ad4a15..e216adb 100644 --- a/dashboard/assets/packages/config/src/config.js +++ b/dashboard/assets/packages/config/src/config.js @@ -62,6 +62,15 @@ export default (config, { tab }) => { panel("Request Duration", ({ serie }) => { serie(trend("http_req_duration")) }) + + panel("Request Failed Rate", ({ serie }) => { + serie("http_req_failed[?!tags && rate ]") + }) + + panel("Request Rate", ({ serie }) => { + serie("http_reqs[?!tags && rate]") + }) + panel("Request Waiting", ({ serie }) => { serie(trend("http_req_waiting")) }) @@ -77,6 +86,10 @@ export default (config, { tab }) => { panel("Request Receiving", ({ serie }) => { serie(trend("http_req_receiving")) }) + + panel("Request Blocked", ({ serie }) => { + serie(trend("http_req_blocked")) + }) }) section("Browser", ({ section, panel }) => { @@ -85,6 +98,11 @@ export default (config, { tab }) => { panel("Request Duration", ({ serie }) => { serie(trend("browser_http_req_duration")) }) + + panel("Request Failed Rate", ({ serie }) => { + serie("browser_http_req_failed[?!tags && rate ]") + }) + panel("Largest Contentful Paint", ({ serie }) => { serie(trend("browser_web_vital_lcp")) }) @@ -117,6 +135,15 @@ export default (config, { tab }) => { panel("Pong Duration", ({ serie }) => { serie(trend("ws_ping")) }) + + panel("Transfer Rate", ({ serie }) => { + serie("ws_msgs_sent[?!tags && rate]") + serie("ws_msgs_received[?!tags && rate]") + }) + + panel("Sessions Rate", ({ serie }) => { + serie("ws_sessions[?!tags && rate]") + }) }) section("gRPC", ({ section, panel }) => { @@ -125,6 +152,15 @@ export default (config, { tab }) => { panel("Request Duration", ({ serie }) => { serie(trend("grpc_req_duration")) }) + + panel("Transfer Rate", ({ serie }) => { + serie("grpc_streams_msgs_sent[?!tags && rate]") + serie("grpc_streams_msgs_received[?!tags && rate]") + }) + + panel("Streams Rate", ({ serie }) => { + serie("grpc_streams[?!tags && rate]") + }) }) }) From 5dbd1b0ef3bdc3ab0160f3d0a535db3c020c1f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20SZKIBA?= Date: Mon, 16 Oct 2023 16:09:10 +0200 Subject: [PATCH 2/4] fix: Rename WebSockets "Pong Duration" to "Ping Duration" The official name is "ping", so rename it back to the official name (however the measured value is the response time) closes #78 --- dashboard/assets/packages/config/dist/config.json | 2 +- dashboard/assets/packages/config/src/config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dashboard/assets/packages/config/dist/config.json b/dashboard/assets/packages/config/dist/config.json index aa29676..7880914 100644 --- a/dashboard/assets/packages/config/dist/config.json +++ b/dashboard/assets/packages/config/dist/config.json @@ -338,7 +338,7 @@ "query": "ws_ping[?!tags && (avg || p90 || p95 || p99)]" } ], - "title": "Pong Duration", + "title": "Ping Duration", "id": "tab-1.section-2.panel-2", "kind": "chart" }, diff --git a/dashboard/assets/packages/config/src/config.js b/dashboard/assets/packages/config/src/config.js index e216adb..0bb1d4a 100644 --- a/dashboard/assets/packages/config/src/config.js +++ b/dashboard/assets/packages/config/src/config.js @@ -132,7 +132,7 @@ export default (config, { tab }) => { panel("Session Duration", ({ serie }) => { serie(trend("ws_session_duration")) }) - panel("Pong Duration", ({ serie }) => { + panel("Ping Duration", ({ serie }) => { serie(trend("ws_ping")) }) From aa2d6dd8df68b90d8af58fde825f590774376a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20SZKIBA?= Date: Mon, 16 Oct 2023 16:23:45 +0200 Subject: [PATCH 3/4] feat: Enable short descriptions of graphs Add "summary" configuration property (and placeholder value) to panels configuration. closes #79 --- .../assets/packages/config/dist/config.json | 59 +++++-- .../assets/packages/config/src/config.js | 156 +++++++++++++----- .../{index-e3a4a8c8.js => index-6b9b59c9.js} | 2 +- dashboard/assets/packages/ui/dist/index.html | 2 +- .../assets/packages/view/dist/config.d.ts | 3 +- dashboard/assets/packages/view/dist/config.js | 4 +- dashboard/assets/packages/view/dist/index.js | 4 +- dashboard/assets/packages/view/src/Config.ts | 4 +- 8 files changed, 179 insertions(+), 55 deletions(-) rename dashboard/assets/packages/ui/dist/assets/{index-e3a4a8c8.js => index-6b9b59c9.js} (96%) diff --git a/dashboard/assets/packages/config/dist/config.json b/dashboard/assets/packages/config/dist/config.json index 7880914..51f2db9 100644 --- a/dashboard/assets/packages/config/dist/config.json +++ b/dashboard/assets/packages/config/dist/config.json @@ -13,7 +13,8 @@ ], "title": "Iteration Rate", "kind": "stat", - "id": "tab-0.section-0.panel-0" + "id": "tab-0.section-0.panel-0", + "summary": "" }, { "series": [ @@ -23,7 +24,8 @@ ], "title": "VUs", "kind": "stat", - "id": "tab-0.section-0.panel-1" + "id": "tab-0.section-0.panel-1", + "summary": "" }, { "series": [ @@ -33,7 +35,8 @@ ], "title": "HTTP Request Rate", "kind": "stat", - "id": "tab-0.section-0.panel-2" + "id": "tab-0.section-0.panel-2", + "summary": "" }, { "series": [ @@ -43,7 +46,8 @@ ], "title": "HTTP Request Duration", "kind": "stat", - "id": "tab-0.section-0.panel-3" + "id": "tab-0.section-0.panel-3", + "summary": "" }, { "series": [ @@ -53,7 +57,8 @@ ], "title": "Received Rate", "kind": "stat", - "id": "tab-0.section-0.panel-4" + "id": "tab-0.section-0.panel-4", + "summary": "" }, { "series": [ @@ -63,7 +68,8 @@ ], "title": "Sent Rate", "kind": "stat", - "id": "tab-0.section-0.panel-5" + "id": "tab-0.section-0.panel-5", + "summary": "" } ], "id": "tab-0.section-0" @@ -81,6 +87,7 @@ ], "title": "VUs", "id": "tab-0.section-1.panel-0", + "summary": "", "kind": "chart" }, { @@ -94,6 +101,7 @@ ], "title": "Transfer Rate", "id": "tab-0.section-1.panel-1", + "summary": "", "kind": "chart" }, { @@ -104,6 +112,7 @@ ], "title": "HTTP Request Duration", "id": "tab-0.section-1.panel-2", + "summary": "", "kind": "chart" }, { @@ -114,6 +123,7 @@ ], "title": "Iteration Duration", "id": "tab-0.section-1.panel-3", + "summary": "", "kind": "chart" } ], @@ -136,6 +146,7 @@ ], "title": "Request Duration", "id": "tab-1.section-0.panel-0", + "summary": "", "kind": "chart" }, { @@ -146,6 +157,7 @@ ], "title": "Request Failed Rate", "id": "tab-1.section-0.panel-1", + "summary": "", "kind": "chart" }, { @@ -156,6 +168,7 @@ ], "title": "Request Rate", "id": "tab-1.section-0.panel-2", + "summary": "", "kind": "chart" }, { @@ -166,6 +179,7 @@ ], "title": "Request Waiting", "id": "tab-1.section-0.panel-3", + "summary": "", "kind": "chart" }, { @@ -176,6 +190,7 @@ ], "title": "TLS handshaking", "id": "tab-1.section-0.panel-4", + "summary": "", "kind": "chart" }, { @@ -186,6 +201,7 @@ ], "title": "Request Sending", "id": "tab-1.section-0.panel-5", + "summary": "", "kind": "chart" }, { @@ -196,6 +212,7 @@ ], "title": "Request Connecting", "id": "tab-1.section-0.panel-6", + "summary": "", "kind": "chart" }, { @@ -206,6 +223,7 @@ ], "title": "Request Receiving", "id": "tab-1.section-0.panel-7", + "summary": "", "kind": "chart" }, { @@ -216,6 +234,7 @@ ], "title": "Request Blocked", "id": "tab-1.section-0.panel-8", + "summary": "", "kind": "chart" } ], @@ -233,6 +252,7 @@ ], "title": "Request Duration", "id": "tab-1.section-1.panel-0", + "summary": "", "kind": "chart" }, { @@ -243,6 +263,7 @@ ], "title": "Request Failed Rate", "id": "tab-1.section-1.panel-1", + "summary": "", "kind": "chart" }, { @@ -253,6 +274,7 @@ ], "title": "Largest Contentful Paint", "id": "tab-1.section-1.panel-2", + "summary": "", "kind": "chart" }, { @@ -263,6 +285,7 @@ ], "title": "First Input Delay", "id": "tab-1.section-1.panel-3", + "summary": "", "kind": "chart" }, { @@ -273,6 +296,7 @@ ], "title": "Cumulative Layout Shift", "id": "tab-1.section-1.panel-4", + "summary": "", "kind": "chart" }, { @@ -283,6 +307,7 @@ ], "title": "Time to First Byte", "id": "tab-1.section-1.panel-5", + "summary": "", "kind": "chart" }, { @@ -293,6 +318,7 @@ ], "title": "First Contentful Paint", "id": "tab-1.section-1.panel-6", + "summary": "", "kind": "chart" }, { @@ -303,6 +329,7 @@ ], "title": "Interaction to Next Paint", "id": "tab-1.section-1.panel-7", + "summary": "", "kind": "chart" } ], @@ -320,6 +347,7 @@ ], "title": "Connect Duration", "id": "tab-1.section-2.panel-0", + "summary": "", "kind": "chart" }, { @@ -330,6 +358,7 @@ ], "title": "Session Duration", "id": "tab-1.section-2.panel-1", + "summary": "", "kind": "chart" }, { @@ -340,6 +369,7 @@ ], "title": "Ping Duration", "id": "tab-1.section-2.panel-2", + "summary": "", "kind": "chart" }, { @@ -353,6 +383,7 @@ ], "title": "Transfer Rate", "id": "tab-1.section-2.panel-3", + "summary": "", "kind": "chart" }, { @@ -363,6 +394,7 @@ ], "title": "Sessions Rate", "id": "tab-1.section-2.panel-4", + "summary": "", "kind": "chart" } ], @@ -380,6 +412,7 @@ ], "title": "Request Duration", "id": "tab-1.section-3.panel-0", + "summary": "", "kind": "chart" }, { @@ -393,6 +426,7 @@ ], "title": "Transfer Rate", "id": "tab-1.section-3.panel-1", + "summary": "", "kind": "chart" }, { @@ -403,6 +437,7 @@ ], "title": "Streams Rate", "id": "tab-1.section-3.panel-2", + "summary": "", "kind": "chart" } ], @@ -427,7 +462,8 @@ ], "title": "Trends", "kind": "summary", - "id": "tab-2.section-0.panel-0" + "id": "tab-2.section-0.panel-0", + "summary": "" } ], "title": "", @@ -443,7 +479,8 @@ ], "title": "Counters", "kind": "summary", - "id": "tab-2.section-1.panel-0" + "id": "tab-2.section-1.panel-0", + "summary": "" }, { "series": [ @@ -453,7 +490,8 @@ ], "title": "Rates", "kind": "summary", - "id": "tab-2.section-1.panel-1" + "id": "tab-2.section-1.panel-1", + "summary": "" }, { "series": [ @@ -463,7 +501,8 @@ ], "title": "Gauges", "kind": "summary", - "id": "tab-2.section-1.panel-2" + "id": "tab-2.section-1.panel-2", + "summary": "" } ], "title": "", diff --git a/dashboard/assets/packages/config/src/config.js b/dashboard/assets/packages/config/src/config.js index 0bb1d4a..bdd7561 100644 --- a/dashboard/assets/packages/config/src/config.js +++ b/dashboard/assets/packages/config/src/config.js @@ -14,40 +14,60 @@ export default (config, { tab }) => { // stat section section(({ panel }) => { - panel("Iteration Rate", "stat", ({ serie }) => { + panel("Iteration Rate", "stat", ({ panel, serie }) => { + panel.summary = "" + serie("iterations[?!tags && rate]") }) - panel("VUs", "stat", ({ serie }) => { + panel("VUs", "stat", ({ panel, serie }) => { + panel.summary = "" + serie("vus[?!tags && value]") }) - panel("HTTP Request Rate", "stat", ({ serie }) => { + panel("HTTP Request Rate", "stat", ({ panel, serie }) => { + panel.summary = "" + serie("http_reqs[?!tags && rate]") }) - panel("HTTP Request Duration", "stat", ({ serie }) => { + panel("HTTP Request Duration", "stat", ({ panel, serie }) => { + panel.summary = "" + serie("http_req_duration[?!tags && avg]") }) - panel("Received Rate", "stat", ({ serie }) => { + panel("Received Rate", "stat", ({ panel, serie }) => { + panel.summary = "" + serie("data_received[?!tags && rate]") }) - panel("Sent Rate", "stat", ({ serie }) => { + panel("Sent Rate", "stat", ({ panel, serie }) => { + panel.summary = "" + serie("data_sent[?!tags && rate]") }) }) // chart section section(({ panel }) => { - panel("VUs", ({ serie }) => { + panel("VUs", ({ panel, serie }) => { + panel.summary = "" + serie("vus[?!tags && value]") serie("http_reqs[?!tags && rate ]") }) - panel("Transfer Rate", ({ serie }) => { + panel("Transfer Rate", ({ panel, serie }) => { + panel.summary = "" + serie("data_received[?!tags && rate]") serie("data_sent[?!tags && rate]") }) - panel("HTTP Request Duration", ({ serie }) => { + panel("HTTP Request Duration", ({ panel, serie }) => { + panel.summary = "" + serie(trend("http_req_duration")) }) - panel("Iteration Duration", ({ serie }) => { + panel("Iteration Duration", ({ panel, serie }) => { + panel.summary = "" + serie(trend("iteration_duration")) }) }) @@ -59,35 +79,53 @@ export default (config, { tab }) => { section("HTTP", ({ section, panel }) => { section.summary = `These metrics are generated only when the test makes HTTP requests.` - panel("Request Duration", ({ serie }) => { + panel("Request Duration", ({ panel, serie }) => { + panel.summary = "" + serie(trend("http_req_duration")) }) - panel("Request Failed Rate", ({ serie }) => { + panel("Request Failed Rate", ({ panel, serie }) => { + panel.summary = "" + serie("http_req_failed[?!tags && rate ]") }) - panel("Request Rate", ({ serie }) => { + panel("Request Rate", ({ panel, serie }) => { + panel.summary = "" + serie("http_reqs[?!tags && rate]") }) - panel("Request Waiting", ({ serie }) => { + panel("Request Waiting", ({ panel, serie }) => { + panel.summary = "" + serie(trend("http_req_waiting")) }) - panel("TLS handshaking", ({ serie }) => { + panel("TLS handshaking", ({ panel, serie }) => { + panel.summary = "" + serie(trend("http_req_tls_handshaking")) }) - panel("Request Sending", ({ serie }) => { + panel("Request Sending", ({ panel, serie }) => { + panel.summary = "" + serie(trend("http_req_sending")) }) - panel("Request Connecting", ({ serie }) => { + panel("Request Connecting", ({ panel, serie }) => { + panel.summary = "" + serie(trend("http_req_connecting")) }) - panel("Request Receiving", ({ serie }) => { + panel("Request Receiving", ({ panel, serie }) => { + panel.summary = "" + serie(trend("http_req_receiving")) }) - panel("Request Blocked", ({ serie }) => { + panel("Request Blocked", ({ panel, serie }) => { + panel.summary = "" + serie(trend("http_req_blocked")) }) }) @@ -95,30 +133,46 @@ export default (config, { tab }) => { section("Browser", ({ section, panel }) => { section.summary = `The k6 browser module emits its own metrics based on the Core Web Vitals and Other Web Vitals.` - panel("Request Duration", ({ serie }) => { + panel("Request Duration", ({ panel, serie }) => { + panel.summary = "" + serie(trend("browser_http_req_duration")) }) - panel("Request Failed Rate", ({ serie }) => { + panel("Request Failed Rate", ({ panel, serie }) => { + panel.summary = "" + serie("browser_http_req_failed[?!tags && rate ]") }) - panel("Largest Contentful Paint", ({ serie }) => { + panel("Largest Contentful Paint", ({ panel, serie }) => { + panel.summary = "" + serie(trend("browser_web_vital_lcp")) }) - panel("First Input Delay", ({ serie }) => { + panel("First Input Delay", ({ panel, serie }) => { + panel.summary = "" + serie(trend("browser_web_vital_fid")) }) - panel("Cumulative Layout Shift", ({ serie }) => { + panel("Cumulative Layout Shift", ({ panel, serie }) => { + panel.summary = "" + serie(trend("browser_web_vital_cls")) }) - panel("Time to First Byte", ({ serie }) => { + panel("Time to First Byte", ({ panel, serie }) => { + panel.summary = "" + serie(trend("browser_web_vital_ttfb")) }) - panel("First Contentful Paint", ({ serie }) => { + panel("First Contentful Paint", ({ panel, serie }) => { + panel.summary = "" + serie(trend("browser_web_vital_fcp")) }) - panel("Interaction to Next Paint", ({ serie }) => { + panel("Interaction to Next Paint", ({ panel, serie }) => { + panel.summary = "" + serie(trend("browser_web_vital_inp")) }) }) @@ -126,22 +180,32 @@ export default (config, { tab }) => { section("WebSocket", ({ section, panel }) => { section.summary = `k6 emits the following metrics when interacting with a WebSocket service through the experimental or legacy websockets API.` - panel("Connect Duration", ({ serie }) => { + panel("Connect Duration", ({ panel, serie }) => { + panel.summary = "" + serie(trend("ws_connecting")) }) - panel("Session Duration", ({ serie }) => { + panel("Session Duration", ({ panel, serie }) => { + panel.summary = "" + serie(trend("ws_session_duration")) }) - panel("Ping Duration", ({ serie }) => { + panel("Ping Duration", ({ panel, serie }) => { + panel.summary = "" + serie(trend("ws_ping")) }) - panel("Transfer Rate", ({ serie }) => { + panel("Transfer Rate", ({ panel, serie }) => { + panel.summary = "" + serie("ws_msgs_sent[?!tags && rate]") serie("ws_msgs_received[?!tags && rate]") }) - panel("Sessions Rate", ({ serie }) => { + panel("Sessions Rate", ({ panel, serie }) => { + panel.summary = "" + serie("ws_sessions[?!tags && rate]") }) }) @@ -149,16 +213,22 @@ export default (config, { tab }) => { section("gRPC", ({ section, panel }) => { section.summary = `k6 emits the following metrics when it interacts with a service through the gRPC API.` - panel("Request Duration", ({ serie }) => { + panel("Request Duration", ({ panel, serie }) => { + panel.summary = "" + serie(trend("grpc_req_duration")) }) - panel("Transfer Rate", ({ serie }) => { + panel("Transfer Rate", ({ panel, serie }) => { + panel.summary = "" + serie("grpc_streams_msgs_sent[?!tags && rate]") serie("grpc_streams_msgs_received[?!tags && rate]") }) - panel("Streams Rate", ({ serie }) => { + panel("Streams Rate", ({ panel, serie }) => { + panel.summary = "" + serie("grpc_streams[?!tags && rate]") }) }) @@ -168,19 +238,27 @@ export default (config, { tab }) => { tab.summary = `This chapter provides a summary of the test run metrics. The tables contains the aggregated values of the metrics for the entire test run.` section("", ({ panel }) => { - panel("Trends", "summary", ({ serie }) => { + panel("Trends", "summary", ({ panel, serie }) => { + panel.summary = "" + serie("[?!tags && trend]") }) }) section("", ({ panel }) => { - panel("Counters", "summary", ({ serie }) => { + panel("Counters", "summary", ({ panel, serie }) => { + panel.summary = "" + serie("[?!tags && counter]") }) - panel("Rates", "summary", ({ serie }) => { + panel("Rates", "summary", ({ panel, serie }) => { + panel.summary = "" + serie("[?!tags && rate]") }) - panel("Gauges", "summary", ({ serie }) => { + panel("Gauges", "summary", ({ panel, serie }) => { + panel.summary = "" + serie("[?!tags && gauge]") }) }) diff --git a/dashboard/assets/packages/ui/dist/assets/index-e3a4a8c8.js b/dashboard/assets/packages/ui/dist/assets/index-6b9b59c9.js similarity index 96% rename from dashboard/assets/packages/ui/dist/assets/index-e3a4a8c8.js rename to dashboard/assets/packages/ui/dist/assets/index-6b9b59c9.js index e94c496..027fa45 100644 --- a/dashboard/assets/packages/ui/dist/assets/index-e3a4a8c8.js +++ b/dashboard/assets/packages/ui/dist/assets/index-6b9b59c9.js @@ -158,4 +158,4 @@ Error generating stack: `+i.message+` {MM}-{DD} {HH}:{mm}`,null,` {HH}:{mm}`,null,1]];function A5(e){return function(t,n,r,o){return o==null?"--":n==null?"":Pc(e,n)}}var Lx=class{constructor(e,t,n){Se(this,"samples");Se(this,"series");const r=t.series.map(o=>o.query);this.samples=e.samples.select(r),this.samples.empty||(this.series=this.buildSeries(t.series,n))}get empty(){return this.samples.empty}get data(){const e=new Array;for(let t=0;t0&&(i=e[r].legend),n.push({stroke:t[o].stroke,fill:t[o].fill,value:A5(this.samples[r].unit),points:{show:!1},label:i,scale:this.samples[r].unit})}return n}};function I5(e){let t;function n(i){t=document.createElement("div");const l={display:"none",position:"absolute",padding:"0.2rem",border:"1px solid #7b65fa",zIndex:"10",pointerEvents:"none",margin:"0.5rem",fontSize:"smaller"};Object.assign(t.style,l),i.over.appendChild(t),i.over.onmouseleave=()=>{t.style.display="none"},i.over.onmouseenter=()=>{t.style.display="block"}}function r(i){o(i)}function o(i){const l=i.over.getBoundingClientRect();t.style.background=e;const s=D5(i);if(!s){t.style.display="none";return}t.innerHTML=s;const{left:u,top:a}=i.cursor,c=u??0,p=a??0;t.innerHTML=s,ci.over.focus()}}}function D5(e){const{idx:t}=e.cursor;if(t==null)return"";let n;e.legend.values?n=e.legend.values[0]._:n="";let r=``;for(let o=1;o`}return r+="
${n}
${B5(i,l)}${s}${u}
",r}function B5(e,t){return``}var Aa=(e=>(e.chart="chart",e.stat="stat",e.summary="summary",e))(Aa||{}),F5=class{constructor(e,t){Se(this,"view");Se(this,"metrics");this.metrics=t.metrics;const n=e.series.map(r=>r.query);this.view=t.summary.select(n)}get empty(){return this.view.empty}get cols(){return this.view.aggregates.length}get header(){return new Array("metric",...this.view.aggregates.map(e=>e))}get body(){const e=new Array;for(let t=0;tthis.format(this.view[t],r))),e.push(n)}return e}format(e,t){var n;const r=this.metrics.unit(((n=e.metric)==null?void 0:n.name)??"",t);return Pc(r,e.values[t],!0)}};function j5(e,t){for(let n=0;nr.query)).empty}function U5(e,t){return t.summary.select(e.series.map(r=>r.query)).empty}var Ax={exports:{}};const V5=xw(C5);(function(e,t){(function(r,o){e.exports=o(L,V5)})(self,(n,r)=>(()=>{var o={"./common/index.ts":(u,a,c)=>{c.r(a),c.d(a,{dataMatch:()=>h,optionsUpdateState:()=>f});var p=function(x,v){var C={};for(var w in x)Object.prototype.hasOwnProperty.call(x,w)&&v.indexOf(w)<0&&(C[w]=x[w]);if(x!=null&&typeof Object.getOwnPropertySymbols=="function")for(var m=0,w=Object.getOwnPropertySymbols(x);m{u.exports=n},uplot:u=>{u.exports=r}},i={};function l(u){var a=i[u];if(a!==void 0)return a.exports;var c=i[u]={exports:{}};return o[u](c,c.exports,l),c.exports}l.n=u=>{var a=u&&u.__esModule?()=>u.default:()=>u;return l.d(a,{a}),a},l.d=(u,a)=>{for(var c in a)l.o(a,c)&&!l.o(u,c)&&Object.defineProperty(u,c,{enumerable:!0,get:a[c]})},l.o=(u,a)=>Object.prototype.hasOwnProperty.call(u,a),l.r=u=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(u,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(u,"__esModule",{value:!0})};var s={};return(()=>{/*!*******************************!*\ !*** ./react/uplot-react.tsx ***! - \*******************************/l.r(s),l.d(s,{default:()=>h});var u=l("react"),a=l.n(u),c=l("uplot"),p=l.n(c),f=l("./common/index.ts");function h(x){var v=x.options,C=x.data,w=x.target,m=x.onDelete,S=m===void 0?function(){}:m,E=x.onCreate,P=E===void 0?function(){}:E,N=x.resetScales,R=N===void 0?!0:N,z=(0,u.useRef)(null),j=(0,u.useRef)(null);function O(V){V&&(S(V),V.destroy(),z.current=null)}function D(){var V=new(p())(v,C,w||j.current);z.current=V,P(V)}(0,u.useEffect)(function(){return D(),function(){O(z.current)}},[]);var U=(0,u.useRef)({options:v,data:C,target:w}).current;return(0,u.useEffect)(function(){if(U.options!==v){var V=(0,f.optionsUpdateState)(U.options,v);!z.current||V==="create"?(O(z.current),D()):V==="update"&&z.current.setSize({width:v.width,height:v.height})}return U.data!==C&&(z.current?(0,f.dataMatch)(U.data,C)||(R?z.current.setData(C,!0):(z.current.setData(C,!1),z.current.redraw())):D()),U.target!==w&&(O(z.current),D()),function(){U.options=v,U.data=C,U.target=w}},[v,C,w,R]),w?null:a().createElement("div",{ref:j})}})(),s=s.default,s})())})(Ax);var K5=Ax.exports;const Ix=bs(K5);const G5="k6 dashboard",Y5=[{sections:[{panels:[{series:[{query:"iterations[?!tags && rate]"}],title:"Iteration Rate",kind:"stat",id:"tab-0.section-0.panel-0"},{series:[{query:"vus[?!tags && value]"}],title:"VUs",kind:"stat",id:"tab-0.section-0.panel-1"},{series:[{query:"http_reqs[?!tags && rate]"}],title:"HTTP Request Rate",kind:"stat",id:"tab-0.section-0.panel-2"},{series:[{query:"http_req_duration[?!tags && avg]"}],title:"HTTP Request Duration",kind:"stat",id:"tab-0.section-0.panel-3"},{series:[{query:"data_received[?!tags && rate]"}],title:"Received Rate",kind:"stat",id:"tab-0.section-0.panel-4"},{series:[{query:"data_sent[?!tags && rate]"}],title:"Sent Rate",kind:"stat",id:"tab-0.section-0.panel-5"}],id:"tab-0.section-0"},{panels:[{series:[{query:"vus[?!tags && value]"},{query:"http_reqs[?!tags && rate ]"}],title:"VUs",id:"tab-0.section-1.panel-0",kind:"chart"},{series:[{query:"data_received[?!tags && rate]"},{query:"data_sent[?!tags && rate]"}],title:"Transfer Rate",id:"tab-0.section-1.panel-1",kind:"chart"},{series:[{query:"http_req_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"HTTP Request Duration",id:"tab-0.section-1.panel-2",kind:"chart"},{series:[{query:"iteration_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"Iteration Duration",id:"tab-0.section-1.panel-3",kind:"chart"}],id:"tab-0.section-1"}],title:"Overview",summary:"This chapter provides an overview of the most important metrics of the test run. Graphs plot the value of metrics over time.",id:"tab-0"},{sections:[{panels:[{series:[{query:"http_req_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Duration",id:"tab-1.section-0.panel-0",kind:"chart"},{series:[{query:"http_req_waiting[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Waiting",id:"tab-1.section-0.panel-1",kind:"chart"},{series:[{query:"http_req_tls_handshaking[?!tags && (avg || p90 || p95 || p99)]"}],title:"TLS handshaking",id:"tab-1.section-0.panel-2",kind:"chart"},{series:[{query:"http_req_sending[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Sending",id:"tab-1.section-0.panel-3",kind:"chart"},{series:[{query:"http_req_connecting[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Connecting",id:"tab-1.section-0.panel-4",kind:"chart"},{series:[{query:"http_req_receiving[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Receiving",id:"tab-1.section-0.panel-5",kind:"chart"}],title:"HTTP",summary:"These metrics are generated only when the test makes HTTP requests.",id:"tab-1.section-0"},{panels:[{series:[{query:"browser_http_req_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Duration",id:"tab-1.section-1.panel-0",kind:"chart"},{series:[{query:"browser_web_vital_lcp[?!tags && (avg || p90 || p95 || p99)]"}],title:"Largest Contentful Paint",id:"tab-1.section-1.panel-1",kind:"chart"},{series:[{query:"browser_web_vital_fid[?!tags && (avg || p90 || p95 || p99)]"}],title:"First Input Delay",id:"tab-1.section-1.panel-2",kind:"chart"},{series:[{query:"browser_web_vital_cls[?!tags && (avg || p90 || p95 || p99)]"}],title:"Cumulative Layout Shift",id:"tab-1.section-1.panel-3",kind:"chart"},{series:[{query:"browser_web_vital_ttfb[?!tags && (avg || p90 || p95 || p99)]"}],title:"Time to First Byte",id:"tab-1.section-1.panel-4",kind:"chart"},{series:[{query:"browser_web_vital_fcp[?!tags && (avg || p90 || p95 || p99)]"}],title:"First Contentful Paint",id:"tab-1.section-1.panel-5",kind:"chart"},{series:[{query:"browser_web_vital_inp[?!tags && (avg || p90 || p95 || p99)]"}],title:"Interaction to Next Paint",id:"tab-1.section-1.panel-6",kind:"chart"}],title:"Browser",summary:"The k6 browser module emits its own metrics based on the Core Web Vitals and Other Web Vitals.",id:"tab-1.section-1"},{panels:[{series:[{query:"ws_connecting[?!tags && (avg || p90 || p95 || p99)]"}],title:"Connect Duration",id:"tab-1.section-2.panel-0",kind:"chart"},{series:[{query:"ws_session_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"Session Duration",id:"tab-1.section-2.panel-1",kind:"chart"},{series:[{query:"ws_ping[?!tags && (avg || p90 || p95 || p99)]"}],title:"Pong Duration",id:"tab-1.section-2.panel-2",kind:"chart"}],title:"WebSocket",summary:"k6 emits the following metrics when interacting with a WebSocket service through the experimental or legacy websockets API.",id:"tab-1.section-2"},{panels:[{series:[{query:"grpc_req_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Duration",id:"tab-1.section-3.panel-0",kind:"chart"}],title:"gRPC",summary:"k6 emits the following metrics when it interacts with a service through the gRPC API.",id:"tab-1.section-3"}],title:"Timings",summary:"This chapter provides an overview of test run HTTP timing metrics. Graphs plot the value of metrics over time.",id:"tab-1"},{sections:[{panels:[{series:[{query:"[?!tags && trend]"}],title:"Trends",kind:"summary",id:"tab-2.section-0.panel-0"}],title:"",id:"tab-2.section-0"},{panels:[{series:[{query:"[?!tags && counter]"}],title:"Counters",kind:"summary",id:"tab-2.section-1.panel-0"},{series:[{query:"[?!tags && rate]"}],title:"Rates",kind:"summary",id:"tab-2.section-1.panel-1"},{series:[{query:"[?!tags && gauge]"}],title:"Gauges",kind:"summary",id:"tab-2.section-1.panel-2"}],title:"",id:"tab-2.section-1"}],title:"Summary",summary:"This chapter provides a summary of the test run metrics. The tables contains the aggregated values of the metrics for the entire test run.",id:"tab-2"}],Dx={title:G5,tabs:Y5},yh=Vt.createContext(()=>new jd({config:Dx}));yh.displayName="Digest";function q5({endpoint:e="/events",children:t}){const[n,r]=L.useState(null),[o,i]=L.useState(new jd({config:new N5(Dx)}));return L.useEffect(()=>{if(n==null){const l=new EventSource(e),s=u=>{o.handleEvent(u),i(new jd(o))};for(const u in zx)l.addEventListener(u,s);r(l)}},[]),F.jsx(yh.Provider,{value:()=>o,children:t})}function Os(){const e=Vt.useContext(yh);if(e===void 0)throw new Error("useDigest must be used within a DigestProvider");return e()}const Q5=Gt.sync("chart");function Bx({panel:e}){const[t,n]=L.useState(0),r=L.useRef(null),o=Os(),i=mo();L.useLayoutEffect(()=>{let p=()=>n(r.current.offsetWidth);return p(),window.addEventListener("resize",p),()=>window.removeEventListener("resize",p)});const l=new Lx(o,e,i.palette.color);if(l.empty)return F.jsx("div",{ref:r});let s={width:t,height:250,title:e.title,cursor:{sync:{key:Q5.key}},legend:{live:!1},series:l.series,axes:[{}],plugins:[I5(i.palette.background.paper)]},u=i.palette.mode=="dark"?"#202020":"#f0f0f0";s.axes=l.samples.units.map(p=>({stroke:i.palette.text.primary,grid:{stroke:u},ticks:{stroke:u},values:(f,h)=>h.map(x=>Pc(p,x)),size:70,scale:p})),delete s.axes[0].size,s.axes[0].values=L5,s.axes.length>2&&(s.axes[2].side=1);let a=i.palette.mode=="dark"?"#60606080":"#d0d0d080";function c(p){p.root.querySelector(".u-select").style.background=a}return F.jsx(xc,{ref:r,className:"chart panel",item:!0,md:12,lg:6,children:F.jsx(Ix,{options:s,data:l.data,onCreate:c})})}Bx.propTypes={panel:_r.PropTypes.any.isRequired};function Fx({panel:e}){const[t,n]=L.useState(0),r=L.useRef(null),o=Os(),i=mo();L.useLayoutEffect(()=>{let p=()=>n(r.current.offsetWidth);return p(),window.addEventListener("resize",p),()=>window.removeEventListener("resize",p)});const l=e.series[0].query,s=new Lx(o,e,i.palette.color);if(s.empty)return F.jsx("div",{ref:r});const u=o.samples.query(l);var a=0;u&&Array.isArray(u.values)&&u.values.length!=0&&(a=Pc(u.unit,Number(u.values.slice(-1)),!0));let c={width:t,height:32,title:a,series:s.series,axes:[{show:!1},{show:!1}],legend:{show:!1},cursor:{show:!1}};return F.jsxs(xc,{item:!0,className:"panel stat",xs:6,sm:4,md:2,children:[F.jsx(Ri,{sx:{fontSize:"0.8rem"},color:"text.secondary",gutterBottom:!0,align:"center",children:e.title}),F.jsx("div",{ref:r,children:F.jsx(Ix,{options:c,data:s.data})})]})}Fx.propTypes={panel:_r.PropTypes.any.isRequired};function jx({panel:e}){const t=Os(),n=mo(),r=new F5(e,t);if(r.empty)return F.jsx("div",{});const o=r.view.aggregates.length,i=o>6?12:o>1?6:3,l=o>6||o>1?12:6,s=n.palette.mode=="dark"?"#202020c0":"#f6f6f6c0";return F.jsx(xc,{className:"panel",item:!0,xs:12,md:l,lg:i,children:F.jsx(S3,{className:"summary",sx:{background:s},children:F.jsxs(e3,{children:[F.jsx("caption",{children:e.title}),F.jsx(P3,{children:F.jsx(jm,{children:r.header.map((u,a)=>F.jsx(Im,{align:a==0?"left":"right",children:u},e.id+"header"+u))})}),F.jsx(a3,{children:r.body.map((u,a)=>F.jsx(jm,{hover:!0,sx:{"&:last-child td, &:last-child th":{border:0}},children:u.map((c,p)=>F.jsx(Im,{align:p==0?"left":"right",children:c},e.id+"_value_"+a+"_"+p))},e.id+"row"+a))})]})},e.id)})}jx.propTypes={panel:_r.PropTypes.any.isRequired};function Wx({panel:e}){if(e.kind==Aa.chart)return F.jsx(Bx,{panel:e});if(e.kind==Aa.stat)return F.jsx(Fx,{panel:e});if(e.kind==Aa.summary)return F.jsx(jx,{panel:e})}Wx.propTypes={panel:_r.PropTypes.any.isRequired};function Ig({section:e}){return F.jsx(xc,{container:!0,spacing:1,columns:12,children:e.panels.map(t=>F.jsx(Wx,{panel:t},t.id))})}function Hx({section:e}){const[t,n]=Vt.useState(!0),r=Os();return j5(e,r)?F.jsx(F.Fragment,{}):e.title?F.jsxs(pu,{className:"section",sx:{border:"1px dotted #80808080",marginBottom:"1rem"},children:[F.jsxs(Ri,{variant:"h6",onClick:()=>n(!t),sx:{"&:hover":{cursor:"pointer",opacity:.5}},children:[t?F.jsx(g4,{}):F.jsx(y4,{}),e.title]}),F.jsxs(sC,{in:t,children:[t?F.jsx(Ri,{children:e.summary}):F.jsx(F.Fragment,{}),F.jsx(Ig,{section:e})]})]}):F.jsxs(pu,{className:"section",sx:{border:"1px dotted #80808040",marginBottom:"1rem"},children:[F.jsx(Ri,{variant:"h6",children:e.title}),F.jsx(Ri,{children:e.summary}),F.jsx(Ig,{section:e})]})}Hx.propTypes={section:_r.PropTypes.any.isRequired};function Ux({tab:e}){return F.jsx(F.Fragment,{children:e.sections.map(t=>F.jsx(Hx,{section:t},t.id))})}Ux.propTypes={tab:_r.PropTypes.any.isRequired};function X5(e){return{id:`tab-${e}`,"aria-controls":`tabpanel-${e}`}}function Vx({children:e,active:t,idx:n,...r}){return F.jsx("div",{role:"tabpanel",hidden:t!==n,id:`tabpanel-${n}`,"aria-labelledby":`tab-${n}`,...r,children:F.jsx(pu,{p:3,sx:{padding:"0.5rem"},children:e})})}Vx.propTypes={children:_r.PropTypes.node,idx:_r.PropTypes.any.isRequired,active:_r.PropTypes.any.isRequired};function Z5(){const e=Os().config,[t,n]=Vt.useState(0);return F.jsxs(F.Fragment,{children:[F.jsx(m4,{config:e}),F.jsx(pu,{sx:{borderBottom:1,borderColor:"divider"},children:F.jsx(d4,{value:t,onChange:(r,o)=>n(o),children:e.tabs.map((r,o)=>F.jsx(GT,{label:r.title,...X5(o)},r.id))})}),e.tabs.map((r,o)=>F.jsx(Vx,{active:t,idx:o,children:F.jsx(Ux,{tab:r})},r.id))]})}const J5=new URLSearchParams(window.location.search).get("endpoint")||"http://localhost:5665/";Nf.createRoot(document.getElementById("root")).render(F.jsx(F.Fragment,{children:F.jsx(q1,{children:F.jsx(q5,{endpoint:J5+"events",children:F.jsx(Z5,{})})})})); + \*******************************/l.r(s),l.d(s,{default:()=>h});var u=l("react"),a=l.n(u),c=l("uplot"),p=l.n(c),f=l("./common/index.ts");function h(x){var v=x.options,C=x.data,w=x.target,m=x.onDelete,S=m===void 0?function(){}:m,E=x.onCreate,P=E===void 0?function(){}:E,N=x.resetScales,R=N===void 0?!0:N,z=(0,u.useRef)(null),j=(0,u.useRef)(null);function O(V){V&&(S(V),V.destroy(),z.current=null)}function D(){var V=new(p())(v,C,w||j.current);z.current=V,P(V)}(0,u.useEffect)(function(){return D(),function(){O(z.current)}},[]);var U=(0,u.useRef)({options:v,data:C,target:w}).current;return(0,u.useEffect)(function(){if(U.options!==v){var V=(0,f.optionsUpdateState)(U.options,v);!z.current||V==="create"?(O(z.current),D()):V==="update"&&z.current.setSize({width:v.width,height:v.height})}return U.data!==C&&(z.current?(0,f.dataMatch)(U.data,C)||(R?z.current.setData(C,!0):(z.current.setData(C,!1),z.current.redraw())):D()),U.target!==w&&(O(z.current),D()),function(){U.options=v,U.data=C,U.target=w}},[v,C,w,R]),w?null:a().createElement("div",{ref:j})}})(),s=s.default,s})())})(Ax);var K5=Ax.exports;const Ix=bs(K5);const G5="k6 dashboard",Y5=[{sections:[{panels:[{series:[{query:"iterations[?!tags && rate]"}],title:"Iteration Rate",kind:"stat",id:"tab-0.section-0.panel-0",summary:""},{series:[{query:"vus[?!tags && value]"}],title:"VUs",kind:"stat",id:"tab-0.section-0.panel-1",summary:""},{series:[{query:"http_reqs[?!tags && rate]"}],title:"HTTP Request Rate",kind:"stat",id:"tab-0.section-0.panel-2",summary:""},{series:[{query:"http_req_duration[?!tags && avg]"}],title:"HTTP Request Duration",kind:"stat",id:"tab-0.section-0.panel-3",summary:""},{series:[{query:"data_received[?!tags && rate]"}],title:"Received Rate",kind:"stat",id:"tab-0.section-0.panel-4",summary:""},{series:[{query:"data_sent[?!tags && rate]"}],title:"Sent Rate",kind:"stat",id:"tab-0.section-0.panel-5",summary:""}],id:"tab-0.section-0"},{panels:[{series:[{query:"vus[?!tags && value]"},{query:"http_reqs[?!tags && rate ]"}],title:"VUs",id:"tab-0.section-1.panel-0",summary:"",kind:"chart"},{series:[{query:"data_received[?!tags && rate]"},{query:"data_sent[?!tags && rate]"}],title:"Transfer Rate",id:"tab-0.section-1.panel-1",summary:"",kind:"chart"},{series:[{query:"http_req_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"HTTP Request Duration",id:"tab-0.section-1.panel-2",summary:"",kind:"chart"},{series:[{query:"iteration_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"Iteration Duration",id:"tab-0.section-1.panel-3",summary:"",kind:"chart"}],id:"tab-0.section-1"}],title:"Overview",summary:"This chapter provides an overview of the most important metrics of the test run. Graphs plot the value of metrics over time.",id:"tab-0"},{sections:[{panels:[{series:[{query:"http_req_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Duration",id:"tab-1.section-0.panel-0",summary:"",kind:"chart"},{series:[{query:"http_req_failed[?!tags && rate ]"}],title:"Request Failed Rate",id:"tab-1.section-0.panel-1",summary:"",kind:"chart"},{series:[{query:"http_reqs[?!tags && rate]"}],title:"Request Rate",id:"tab-1.section-0.panel-2",summary:"",kind:"chart"},{series:[{query:"http_req_waiting[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Waiting",id:"tab-1.section-0.panel-3",summary:"",kind:"chart"},{series:[{query:"http_req_tls_handshaking[?!tags && (avg || p90 || p95 || p99)]"}],title:"TLS handshaking",id:"tab-1.section-0.panel-4",summary:"",kind:"chart"},{series:[{query:"http_req_sending[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Sending",id:"tab-1.section-0.panel-5",summary:"",kind:"chart"},{series:[{query:"http_req_connecting[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Connecting",id:"tab-1.section-0.panel-6",summary:"",kind:"chart"},{series:[{query:"http_req_receiving[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Receiving",id:"tab-1.section-0.panel-7",summary:"",kind:"chart"},{series:[{query:"http_req_blocked[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Blocked",id:"tab-1.section-0.panel-8",summary:"",kind:"chart"}],title:"HTTP",summary:"These metrics are generated only when the test makes HTTP requests.",id:"tab-1.section-0"},{panels:[{series:[{query:"browser_http_req_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Duration",id:"tab-1.section-1.panel-0",summary:"",kind:"chart"},{series:[{query:"browser_http_req_failed[?!tags && rate ]"}],title:"Request Failed Rate",id:"tab-1.section-1.panel-1",summary:"",kind:"chart"},{series:[{query:"browser_web_vital_lcp[?!tags && (avg || p90 || p95 || p99)]"}],title:"Largest Contentful Paint",id:"tab-1.section-1.panel-2",summary:"",kind:"chart"},{series:[{query:"browser_web_vital_fid[?!tags && (avg || p90 || p95 || p99)]"}],title:"First Input Delay",id:"tab-1.section-1.panel-3",summary:"",kind:"chart"},{series:[{query:"browser_web_vital_cls[?!tags && (avg || p90 || p95 || p99)]"}],title:"Cumulative Layout Shift",id:"tab-1.section-1.panel-4",summary:"",kind:"chart"},{series:[{query:"browser_web_vital_ttfb[?!tags && (avg || p90 || p95 || p99)]"}],title:"Time to First Byte",id:"tab-1.section-1.panel-5",summary:"",kind:"chart"},{series:[{query:"browser_web_vital_fcp[?!tags && (avg || p90 || p95 || p99)]"}],title:"First Contentful Paint",id:"tab-1.section-1.panel-6",summary:"",kind:"chart"},{series:[{query:"browser_web_vital_inp[?!tags && (avg || p90 || p95 || p99)]"}],title:"Interaction to Next Paint",id:"tab-1.section-1.panel-7",summary:"",kind:"chart"}],title:"Browser",summary:"The k6 browser module emits its own metrics based on the Core Web Vitals and Other Web Vitals.",id:"tab-1.section-1"},{panels:[{series:[{query:"ws_connecting[?!tags && (avg || p90 || p95 || p99)]"}],title:"Connect Duration",id:"tab-1.section-2.panel-0",summary:"",kind:"chart"},{series:[{query:"ws_session_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"Session Duration",id:"tab-1.section-2.panel-1",summary:"",kind:"chart"},{series:[{query:"ws_ping[?!tags && (avg || p90 || p95 || p99)]"}],title:"Ping Duration",id:"tab-1.section-2.panel-2",summary:"",kind:"chart"},{series:[{query:"ws_msgs_sent[?!tags && rate]"},{query:"ws_msgs_received[?!tags && rate]"}],title:"Transfer Rate",id:"tab-1.section-2.panel-3",summary:"",kind:"chart"},{series:[{query:"ws_sessions[?!tags && rate]"}],title:"Sessions Rate",id:"tab-1.section-2.panel-4",summary:"",kind:"chart"}],title:"WebSocket",summary:"k6 emits the following metrics when interacting with a WebSocket service through the experimental or legacy websockets API.",id:"tab-1.section-2"},{panels:[{series:[{query:"grpc_req_duration[?!tags && (avg || p90 || p95 || p99)]"}],title:"Request Duration",id:"tab-1.section-3.panel-0",summary:"",kind:"chart"},{series:[{query:"grpc_streams_msgs_sent[?!tags && rate]"},{query:"grpc_streams_msgs_received[?!tags && rate]"}],title:"Transfer Rate",id:"tab-1.section-3.panel-1",summary:"",kind:"chart"},{series:[{query:"grpc_streams[?!tags && rate]"}],title:"Streams Rate",id:"tab-1.section-3.panel-2",summary:"",kind:"chart"}],title:"gRPC",summary:"k6 emits the following metrics when it interacts with a service through the gRPC API.",id:"tab-1.section-3"}],title:"Timings",summary:"This chapter provides an overview of test run HTTP timing metrics. Graphs plot the value of metrics over time.",id:"tab-1"},{sections:[{panels:[{series:[{query:"[?!tags && trend]"}],title:"Trends",kind:"summary",id:"tab-2.section-0.panel-0",summary:""}],title:"",id:"tab-2.section-0"},{panels:[{series:[{query:"[?!tags && counter]"}],title:"Counters",kind:"summary",id:"tab-2.section-1.panel-0",summary:""},{series:[{query:"[?!tags && rate]"}],title:"Rates",kind:"summary",id:"tab-2.section-1.panel-1",summary:""},{series:[{query:"[?!tags && gauge]"}],title:"Gauges",kind:"summary",id:"tab-2.section-1.panel-2",summary:""}],title:"",id:"tab-2.section-1"}],title:"Summary",summary:"This chapter provides a summary of the test run metrics. The tables contains the aggregated values of the metrics for the entire test run.",id:"tab-2"}],Dx={title:G5,tabs:Y5},yh=Vt.createContext(()=>new jd({config:Dx}));yh.displayName="Digest";function q5({endpoint:e="/events",children:t}){const[n,r]=L.useState(null),[o,i]=L.useState(new jd({config:new N5(Dx)}));return L.useEffect(()=>{if(n==null){const l=new EventSource(e),s=u=>{o.handleEvent(u),i(new jd(o))};for(const u in zx)l.addEventListener(u,s);r(l)}},[]),F.jsx(yh.Provider,{value:()=>o,children:t})}function Os(){const e=Vt.useContext(yh);if(e===void 0)throw new Error("useDigest must be used within a DigestProvider");return e()}const Q5=Gt.sync("chart");function Bx({panel:e}){const[t,n]=L.useState(0),r=L.useRef(null),o=Os(),i=mo();L.useLayoutEffect(()=>{let p=()=>n(r.current.offsetWidth);return p(),window.addEventListener("resize",p),()=>window.removeEventListener("resize",p)});const l=new Lx(o,e,i.palette.color);if(l.empty)return F.jsx("div",{ref:r});let s={width:t,height:250,title:e.title,cursor:{sync:{key:Q5.key}},legend:{live:!1},series:l.series,axes:[{}],plugins:[I5(i.palette.background.paper)]},u=i.palette.mode=="dark"?"#202020":"#f0f0f0";s.axes=l.samples.units.map(p=>({stroke:i.palette.text.primary,grid:{stroke:u},ticks:{stroke:u},values:(f,h)=>h.map(x=>Pc(p,x)),size:70,scale:p})),delete s.axes[0].size,s.axes[0].values=L5,s.axes.length>2&&(s.axes[2].side=1);let a=i.palette.mode=="dark"?"#60606080":"#d0d0d080";function c(p){p.root.querySelector(".u-select").style.background=a}return F.jsx(xc,{ref:r,className:"chart panel",item:!0,md:12,lg:6,children:F.jsx(Ix,{options:s,data:l.data,onCreate:c})})}Bx.propTypes={panel:_r.PropTypes.any.isRequired};function Fx({panel:e}){const[t,n]=L.useState(0),r=L.useRef(null),o=Os(),i=mo();L.useLayoutEffect(()=>{let p=()=>n(r.current.offsetWidth);return p(),window.addEventListener("resize",p),()=>window.removeEventListener("resize",p)});const l=e.series[0].query,s=new Lx(o,e,i.palette.color);if(s.empty)return F.jsx("div",{ref:r});const u=o.samples.query(l);var a=0;u&&Array.isArray(u.values)&&u.values.length!=0&&(a=Pc(u.unit,Number(u.values.slice(-1)),!0));let c={width:t,height:32,title:a,series:s.series,axes:[{show:!1},{show:!1}],legend:{show:!1},cursor:{show:!1}};return F.jsxs(xc,{item:!0,className:"panel stat",xs:6,sm:4,md:2,children:[F.jsx(Ri,{sx:{fontSize:"0.8rem"},color:"text.secondary",gutterBottom:!0,align:"center",children:e.title}),F.jsx("div",{ref:r,children:F.jsx(Ix,{options:c,data:s.data})})]})}Fx.propTypes={panel:_r.PropTypes.any.isRequired};function jx({panel:e}){const t=Os(),n=mo(),r=new F5(e,t);if(r.empty)return F.jsx("div",{});const o=r.view.aggregates.length,i=o>6?12:o>1?6:3,l=o>6||o>1?12:6,s=n.palette.mode=="dark"?"#202020c0":"#f6f6f6c0";return F.jsx(xc,{className:"panel",item:!0,xs:12,md:l,lg:i,children:F.jsx(S3,{className:"summary",sx:{background:s},children:F.jsxs(e3,{children:[F.jsx("caption",{children:e.title}),F.jsx(P3,{children:F.jsx(jm,{children:r.header.map((u,a)=>F.jsx(Im,{align:a==0?"left":"right",children:u},e.id+"header"+u))})}),F.jsx(a3,{children:r.body.map((u,a)=>F.jsx(jm,{hover:!0,sx:{"&:last-child td, &:last-child th":{border:0}},children:u.map((c,p)=>F.jsx(Im,{align:p==0?"left":"right",children:c},e.id+"_value_"+a+"_"+p))},e.id+"row"+a))})]})},e.id)})}jx.propTypes={panel:_r.PropTypes.any.isRequired};function Wx({panel:e}){if(e.kind==Aa.chart)return F.jsx(Bx,{panel:e});if(e.kind==Aa.stat)return F.jsx(Fx,{panel:e});if(e.kind==Aa.summary)return F.jsx(jx,{panel:e})}Wx.propTypes={panel:_r.PropTypes.any.isRequired};function Ig({section:e}){return F.jsx(xc,{container:!0,spacing:1,columns:12,children:e.panels.map(t=>F.jsx(Wx,{panel:t},t.id))})}function Hx({section:e}){const[t,n]=Vt.useState(!0),r=Os();return j5(e,r)?F.jsx(F.Fragment,{}):e.title?F.jsxs(pu,{className:"section",sx:{border:"1px dotted #80808080",marginBottom:"1rem"},children:[F.jsxs(Ri,{variant:"h6",onClick:()=>n(!t),sx:{"&:hover":{cursor:"pointer",opacity:.5}},children:[t?F.jsx(g4,{}):F.jsx(y4,{}),e.title]}),F.jsxs(sC,{in:t,children:[t?F.jsx(Ri,{children:e.summary}):F.jsx(F.Fragment,{}),F.jsx(Ig,{section:e})]})]}):F.jsxs(pu,{className:"section",sx:{border:"1px dotted #80808040",marginBottom:"1rem"},children:[F.jsx(Ri,{variant:"h6",children:e.title}),F.jsx(Ri,{children:e.summary}),F.jsx(Ig,{section:e})]})}Hx.propTypes={section:_r.PropTypes.any.isRequired};function Ux({tab:e}){return F.jsx(F.Fragment,{children:e.sections.map(t=>F.jsx(Hx,{section:t},t.id))})}Ux.propTypes={tab:_r.PropTypes.any.isRequired};function X5(e){return{id:`tab-${e}`,"aria-controls":`tabpanel-${e}`}}function Vx({children:e,active:t,idx:n,...r}){return F.jsx("div",{role:"tabpanel",hidden:t!==n,id:`tabpanel-${n}`,"aria-labelledby":`tab-${n}`,...r,children:F.jsx(pu,{p:3,sx:{padding:"0.5rem"},children:e})})}Vx.propTypes={children:_r.PropTypes.node,idx:_r.PropTypes.any.isRequired,active:_r.PropTypes.any.isRequired};function Z5(){const e=Os().config,[t,n]=Vt.useState(0);return F.jsxs(F.Fragment,{children:[F.jsx(m4,{config:e}),F.jsx(pu,{sx:{borderBottom:1,borderColor:"divider"},children:F.jsx(d4,{value:t,onChange:(r,o)=>n(o),children:e.tabs.map((r,o)=>F.jsx(GT,{label:r.title,...X5(o)},r.id))})}),e.tabs.map((r,o)=>F.jsx(Vx,{active:t,idx:o,children:F.jsx(Ux,{tab:r})},r.id))]})}const J5=new URLSearchParams(window.location.search).get("endpoint")||"http://localhost:5665/";Nf.createRoot(document.getElementById("root")).render(F.jsx(F.Fragment,{children:F.jsx(q1,{children:F.jsx(q5,{endpoint:J5+"events",children:F.jsx(Z5,{})})})})); diff --git a/dashboard/assets/packages/ui/dist/index.html b/dashboard/assets/packages/ui/dist/index.html index 7254e6f..ece43bf 100644 --- a/dashboard/assets/packages/ui/dist/index.html +++ b/dashboard/assets/packages/ui/dist/index.html @@ -11,7 +11,7 @@ k6 dashboard - + diff --git a/dashboard/assets/packages/view/dist/config.d.ts b/dashboard/assets/packages/view/dist/config.d.ts index 14e7c3a..5c77d55 100644 --- a/dashboard/assets/packages/view/dist/config.d.ts +++ b/dashboard/assets/packages/view/dist/config.d.ts @@ -15,9 +15,10 @@ declare enum PanelKind { declare class Panel { title?: string; id?: string; + summary?: string; kind?: PanelKind; series: Serie[]; - constructor({ title, id, kind, series }?: Panel); + constructor({ title, id, summary, kind, series }?: Panel); } declare class Section { title?: string; diff --git a/dashboard/assets/packages/view/dist/config.js b/dashboard/assets/packages/view/dist/config.js index 7463c45..58b36c2 100644 --- a/dashboard/assets/packages/view/dist/config.js +++ b/dashboard/assets/packages/view/dist/config.js @@ -20,11 +20,13 @@ var PanelKind = /* @__PURE__ */ ((PanelKind2) => { var Panel = class { title; id; + summary; kind; series; - constructor({ title, id, kind = "chart" /* chart */, series = [] } = {}) { + constructor({ title, id, summary, kind = "chart" /* chart */, series = [] } = {}) { this.title = title; this.id = id; + this.summary = summary; this.kind = kind; this.series = series; } diff --git a/dashboard/assets/packages/view/dist/index.js b/dashboard/assets/packages/view/dist/index.js index 23b8d0c..7dbff79 100644 --- a/dashboard/assets/packages/view/dist/index.js +++ b/dashboard/assets/packages/view/dist/index.js @@ -227,11 +227,13 @@ var PanelKind = /* @__PURE__ */ ((PanelKind2) => { var Panel = class { title; id; + summary; kind; series; - constructor({ title, id, kind = "chart" /* chart */, series = [] } = {}) { + constructor({ title, id, summary, kind = "chart" /* chart */, series = [] } = {}) { this.title = title; this.id = id; + this.summary = summary; this.kind = kind; this.series = series; } diff --git a/dashboard/assets/packages/view/src/Config.ts b/dashboard/assets/packages/view/src/Config.ts index cd0fbbb..7106cd2 100644 --- a/dashboard/assets/packages/view/src/Config.ts +++ b/dashboard/assets/packages/view/src/Config.ts @@ -20,11 +20,13 @@ export enum PanelKind { export class Panel { title?: string id?: string + summary?: string kind?: PanelKind series: Serie[] - constructor({ title, id, kind = PanelKind.chart, series = [] }: Panel = {} as Panel) { + constructor({ title, id, summary, kind = PanelKind.chart, series = [] }: Panel = {} as Panel) { this.title = title this.id = id + this.summary = summary this.kind = kind this.series = series } From 08028e3491817a13ca017a32a92022f083314277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20SZKIBA?= Date: Mon, 16 Oct 2023 16:29:38 +0200 Subject: [PATCH 4/4] build: prepare v0.6.1 release notes --- releases/v0.6.1.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 releases/v0.6.1.md diff --git a/releases/v0.6.1.md b/releases/v0.6.1.md new file mode 100644 index 0000000..7ea67dd --- /dev/null +++ b/releases/v0.6.1.md @@ -0,0 +1,37 @@ + + +xk6-dashboard `v0.6.1` is here 🎉! This release includes: + +- [#77](https://github.com/grafana/xk6-dashboard/issues/77) Add missing charts to the *TIMINGS* tab sections +- [#78](https://github.com/grafana/xk6-dashboard/issues/78) Rename WebSockets *Pong Duration* to *Ping Duration* +- [#79](https://github.com/grafana/xk6-dashboard/issues/79) Enable short descriptions of graphs + +### Add missing charts to the *TIMINGS* tab sections + +#### HTTP +- Request Failed Rate +- Request Rate +- Request Blocked + +#### Browser +- Request Failed Rate + +#### WebSockets +- Transfer Rate +- Sessions Rate + +#### gRPC +- Transfer Rate +- Streams Rate + +### Rename WebSockets *Pong Duration* to *Ping Duration* + +The official name is "ping", so renameed it back to the official name (however the measured value is the response time) + +### Enable short descriptions of graphs + +Added "summary" configuration property (and placeholder value) to panels configuration.