Skip to content

Summary: Display thresholds values even when not in summaryTrendStats #4698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 23, 2025

Conversation

joanlopez
Copy link
Contributor

What?

Makes it possible to display threshold values (since #4089) even when the aggregation on the thresholds expression (e.g. p(99.5)) isn't included as part of options.summaryTrendStats.

Why?

Now those values aren't displayed (instead, it prints undefined, which I would consider a bug), because we're not calculating values for aggregations other than options.summaryTrendStats.

Alternatively, we could just omit these lines from the summary, but I think these are valuable information for the user, and it's aligned with the goal of the revamped summary.

Checklist

  • I have performed a self-review of my code.
  • I have commented on my code, particularly in hard-to-understand areas.
  • I have added tests for my changes.
  • I have run linter and tests locally (make check) and all pass.

Checklist: Documentation (only for k6 maintainers and if relevant)

Please do not merge this PR until the following items are filled out.

  • I have added the correct milestone and labels to the PR.
  • I have updated the release notes: link
  • I have updated or added an issue to the k6-documentation: grafana/k6-docs#NUMBER if applicable
  • I have updated or added an issue to the TypeScript definitions: grafana/k6-DefinitelyTyped#NUMBER if applicable

Related PR(s)/Issue(s)

Closes #4695

@joanlopez joanlopez requested review from oleiade and codebien April 16, 2025 12:01
@joanlopez joanlopez self-assigned this Apr 16, 2025
@joanlopez joanlopez requested a review from a team as a code owner April 16, 2025 12:01
oleiade
oleiade previously approved these changes Apr 16, 2025
Copy link
Contributor

@oleiade oleiade left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 LGTM on my end 🚀

(I believe removing the logs 👇🏻 would fix the tests 🙇🏻 )

Comment on lines 947 to 949
console.log(info);
console.log(metric.values);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
console.log(info);
console.log(metric.values);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, sorry, I forgot one extra force-push before opening the PR haha 😅

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hehe no worries 😄 Been there, did that, many times 🫶

@@ -839,7 +839,7 @@ function renderThresholdResults(
: formatter.decorate(failMark, 'red');

const sourceText = formatter.decorate(
`'${threshold.source}'`,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't directly related, but it's so small that I prefer to add it as part of this PR. It's not a huge deal, but I think it's nice if we trim the threshold's source before displaying it in the summary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for trimming here? If the source includes spaces why we don't interpret it as intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the source includes spaces why we don't interpret it as intentional?

I'm a bit confused now; is there any reason for doing so?

To me, it feels like when you mistakenly add a leading or trailing whitespace in an input designed to write your name or similar.

Looking at the threshold syntax expression (ref), I can see for instance users adding (or not) whitespaces before/after the <operator>, for readability, but not why doing so at the beginning/end of the threshold definition.

Copy link
Contributor

@codebien codebien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an observation: the user experience might be tricky here. Because now we might have the potential scenarios where disabled stats appear in the summary.

I know that isn't a new limitation introduced here, instead it should highlight the need to track/untrack specific metrics as described in #1321, where we should extend the same concept to stats as well.

@@ -839,7 +839,7 @@ function renderThresholdResults(
: formatter.decorate(failMark, 'red');

const sourceText = formatter.decorate(
`'${threshold.source}'`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for trimming here? If the source includes spaces why we don't interpret it as intentional?

@@ -1061,6 +1065,10 @@ function computeSummaryInfo(metrics, renderContext, options) {
const nonTrendExtras = {};
const trendCols = {};

// While "trendCols" contain the values for each "trendStats" aggregation (e.g. p(90) as a sorted array,
// "trendKeys" is used to store specific aggregation values that aren't part of "trendStats"; mainly for thresholds.
const trendKeys = {};
Copy link
Contributor

@codebien codebien Apr 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// While "trendCols" contain the values for each "trendStats"

It doesn't sound right without applying in-depth thinking. Because Trend is itself a stat. Wouldn't it be easier to just use the concept of Threshold?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure 🤷🏻 The code/data structure is quite generic, and while it's true that this is now used for threshold, it could technically be used for anything else, so I tried to keep it consistent with the existing "conventions" (if any) - one data structure holds stats identified by "columns", and this one by "keys" 😅

Overall, that code has many aspects that could be improved (there's already some // TODOs), and @oleiade already did a great job fixing some as part of #4089, but I'd prefer if we can keep focus on fixing the issue that's been reported, and re-evaluate namings and possible improvements over this code in another PR/ as part of another issue/work.

@joanlopez
Copy link
Contributor Author

Just an observation: the user experience might be tricky here. Because now we might have the potential scenarios where disabled stats appear in the summary.

I know that isn't a new limitation introduced here, instead it should highlight the need to track/untrack specific metrics as described in #1321, where we should extend the same concept to stats as well.

I'm sorry @codebien, but I don't fully get your point here. As far as I can see, #1321 is all about metrics and sub-metrics, but here we only care about different "calculations" (percentiles, basically") of already existing metrics/sub-metrics, so I cannot see how it related 🤔 Conceptually I see those two as different, unrelated things.

@codebien
Copy link
Contributor

@joanlopez, my interpretation of the issue is that the user wants to add a threshold for a specific metric at a particular percentile without adding that percentile to all the other metrics.

If that's not the case, then I guess we could simply suggest using summaryTrendStats: [/* other stats */..., 'p(99.99)'] or on our side, skip visualizing the non-computed stats to avoid undefined values.

However, neither of these solutions addresses the user's specific requirement.

Instead, I think 1321 might address it, if we integrate the proposed API with an option for defining the stats. Something similar to the example below:

export const options = { 
  summaryTrendStats: ['max', 'p(95)'], 
};

track("http_req_duration", {percentile: 99.9})

Where without the track line, the threshold will never fail because the stats for the metric doesn't exist. Adding this feature then will lead to a breaking change, but that should be acceptable since I don't expect this being real before v2.

@joanlopez
Copy link
Contributor Author

@joanlopez, my interpretation of the issue is that the user wants to add a threshold for a specific metric at a particular percentile without adding that percentile to all the other metrics.

Let me slightly correct you, because I think it's key here:

"...at a particular percentile without displaying that percentile in summary to all the other metrics."

What I mean here is basically two things (in my humble opinion):

  1. The summaryTrendStats option is, as its name hints, an option to configure the "end-of-test summary", that let users choose what's displayed there (which percentiles values are displayed in the summary for trend metrics). NOT an option to configure what metrics are tracked/untracked.
  2. Percentiles aren't a form of "(sub)metrics tracked", but just a calculation you do over a metric, or more correctly over a sink. It's like when we refer to "min" or "max" for a given "gauge sink". What I think could make sense in the future, as you mentioned, is a mechanism to let the user choose what (sub)metrics are tracked, but less likely what calculations.

If that's not the case, then I guess we could simply suggest using summaryTrendStats: [/* other stats */..., 'p(99.99)'] or on our side, skip visualizing the non-computed stats to avoid undefined values.

I disagree with both, because:

  • I still see value of having the opportunity to define a threshold for a concrete percentile, even if you don't want to see the value of that percentile for ALL the metrics displayed in the end-of-test summary. In other words, why do I need to add to the summary the value of p(99.99) for all the trend metrics, if I only care about the p(99.99) of this particular metric X?
  • I think it's better to display the value in the thresholds section that hiding it because:
    • It keeps that behavior consistent with the whole "thresholds" section, where the value of the aggregation the threshold is defined on is always displayed. It also keeps it consistent with the rest of the summary,as the value won't be displayed in the list below, where all the metrics are displayed, according to summaryTrendStats.
    • Accompanying thresholds results with the value of the particular aggregator used by the threshold was precisely one of the main ideas of the revamped end-of-test summary, because it really makes it very easy for the user to understand why that threshold succeed/failed.

However, neither of these solutions addresses the user's specific requirement.

Instead, I think 1321 might address it, if we integrate the proposed API with an option for defining the stats. Something similar to the example below:

export const options = { 
  summaryTrendStats: ['max', 'p(95)'], 
};

track("http_req_duration", {percentile: 99.9})

Where without the track line, the threshold will never fail because the stats for the metric doesn't exist. Adding this feature then will lead to a breaking change, but that should be acceptable since I don't expect this being real before v2.

That's definitely out of the scope of this PR, so I'd postpone that discussion for whenever we design that feature, but I'm not super convinced that having to specify what calculations do we want to track is really a good idea, because calculations aren't that associated with noise/high memory consumption, which I think are the underneath goal of that feature, and doing so would make both the design and implementation of such feature way more complex.

cc/ @oleiade any take here?

@joanlopez joanlopez requested a review from codebien April 23, 2025 07:05
Copy link
Contributor

@codebien codebien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to unblock the merge for the pull request, so it mostly looks good to me. I want to check what is the context to provide an answer for #4698 (comment), but I don't have time today, I will do it at the end of the week. 🙇

@codebien
Copy link
Contributor

@joanlopez However, the CI seems to be red, can you check that is not related, please?

@joanlopez
Copy link
Contributor Author

@joanlopez However, the CI seems to be red, can you check that is not related, please?

It isn't, it's just one of the flaky Browser E2E tests that define a thresholds that isn't always satisfied.

@codebien codebien added this to the v1.0.0 milestone Apr 23, 2025
Copy link
Contributor

@oleiade oleiade left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 🍾

@joanlopez joanlopez merged commit 8d96e64 into master Apr 23, 2025
28 checks passed
@joanlopez joanlopez deleted the fix-4695 branch April 23, 2025 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

A percentile for not default values is undefined in the report
3 participants