Skip to content
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

Add Derivative Aggregator Plugin #3762

Merged
merged 16 commits into from
Mar 3, 2021

Conversation

KarstenSchnitter
Copy link
Contributor

@KarstenSchnitter KarstenSchnitter commented Feb 7, 2018

Calculate metrics derivatives based on timestamp or other fields.

Required for all PRs:

  • Signed CLA.
  • Associated README.md updated.
  • Has appropriate unit tests.

@srebhan
Copy link
Member

srebhan commented Dec 18, 2020

@KarstenSchnitter are you still interested in getting this PR merged? If so, please make sure you have a CLA signed and indicate this in the PR-message above.

@srebhan srebhan self-assigned this Dec 18, 2020
@KarstenSchnitter
Copy link
Contributor Author

I would appreciate it very much if this PR would become part of telegraf. I have been running a fork of telegraf with this plugin in production ever since I created this PR. Signed CLA was provided for #3772 and #3773 as well, which were both merged in 2018.


func (d *Derivative) calculateDenominator(aggregate aggregate) float64 {
if variable, present := d.derivationVariableName(); present {
return aggregate.last.fields[variable] - aggregate.first.fields[variable]
Copy link
Member

Choose a reason for hiding this comment

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

You need to make sure variable is actually contained in the fields!

Copy link
Member

Choose a reason for hiding this comment

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

This one is still open see the discussion above.

if denominator := d.calculateDenominator(aggregate); denominator != 0 {
derivatives := make(map[string]interface{})
for key, start := range aggregate.first.fields {
if end, ok := aggregate.last.fields[key]; key != d.variableFieldName() && ok {
Copy link
Member

Choose a reason for hiding this comment

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

Split this in two ifs starting with skipping the denominator field.

Copy link
Member

Choose a reason for hiding this comment

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

See my new comment.

Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

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

There are only minor comments in the code. Please make sure that the information in README.md and sampleConfig match.
Furthermore, please rebase your code to retrigger CI.

Calculate derivatives based on time or fields.
Copy link
Contributor Author

@KarstenSchnitter KarstenSchnitter left a comment

Choose a reason for hiding this comment

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

Thanks for the review. I will work on the issues. Can you please give some guidance on the metric.SeriesGrouper comment, that I made?

plugins/aggregators/derivative/derivative.go Outdated Show resolved Hide resolved
* rebase to _master_
* improved documentation
* introduced `Init()` function
* check `uint64` in `convert`
* do not copy `target` in `upsertConvertedFields`
@srebhan
Copy link
Member

srebhan commented Dec 28, 2020

Thanks for the review. I will work on the issues. Can you please give some guidance on the metric.SeriesGrouper comment, that I made?

I would always only update first in this case and never replace the metric. But I'm not sure if this is ok in your use-case as you might keep very old fields this way and to circumvent that problem you would need another structure with a per-field roll-over counter.

So either you change to a per-metric-and-field cache or we stick with the current approach and describe the side-effects (see my in-code-comments to this) nicely in the readme... You decide! :-)

@KarstenSchnitter
Copy link
Contributor Author

I fixed a timestamp issue in the tests, that caused the failing checks. Now everything is green. Is there anything left to do?

Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

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

I think we are very close. Please check my comments. Regarding the testing it might be an issue with the timestamp of your test values. You are using time.Now() which might have different resolutions on your machine and the CI machines. Just use some fixed timestamps to avoid any non-deterministic behavior. Otherwise just run your tests in a loop (e.g. 100 times) and check if it fails. We sometimes have those problems when e.g. accessing maps where access is shuffled by golang...

Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

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

Perfect! Thanks for all your effort!

@srebhan srebhan added plugin/aggregator 1. Request for new aggregator plugins 2. Issues/PRs that are related to aggregator plugins ready for final review This pull request has been reviewed and/or tested by multiple users and is ready for a final review. labels Jan 19, 2021
@sjwang90 sjwang90 removed this from the Planned milestone Jan 29, 2021
Copy link
Contributor

@ssoroka ssoroka left a comment

Choose a reason for hiding this comment

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

looks really good. just some minor feedback.

plugins/aggregators/derivative/README.md Outdated Show resolved Hide resolved
time_difference
```
For each field the derivative is emitted with a naming pattern
`<fieldname>_by_time`.
Copy link
Contributor

Choose a reason for hiding this comment

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

how do you feel about _rate instead of _by_time?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually the suffix is configurable. _by_time is currently the default value. I can change it to _rate if you prefer that.

if current, ok := d.cache[id]; !ok {
// hit an uncached metric, create caches for first time:
d.cache[id] = newAggregate(in)
} else {
Copy link
Contributor

Choose a reason for hiding this comment

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

just return and flatten the else. makes it easier to read

plugins/aggregators/derivative/derivative.go Outdated Show resolved Hide resolved
plugins/aggregators/derivative/derivative.go Outdated Show resolved Hide resolved
var denominator float64
if len(d.Variable) == 0 {
// If no derivation variable is known default to timestamp
denominator = aggregate.last.time.Sub(aggregate.first.time).Seconds()
Copy link
Contributor

Choose a reason for hiding this comment

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

can you get rid of the else by making this the default value and flipping the condition?

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 do not know if I understand your suggestion. Wouldn't this mean I would always calculate the time differences, even when the are not needed?

Copy link
Member

Choose a reason for hiding this comment

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

The idea of @ssoroka is to do

denominator = aggregate.last.time.Sub(aggregate.first.time).Seconds()
if len(d.Variable) > 0 {

instead of the if/else construct. However this means that you, in the non-default-case, do a superfluous computation of the time difference. Don't know if this matters...

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 is how I understood @ssoroka. I just wanted to make sure, that I really should always calculate the time difference, even when it is not needed. I will make that change.

Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

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

Looks still good to me. @ssoroka any comments?

Copy link
Contributor

@ssoroka ssoroka left a comment

Choose a reason for hiding this comment

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

just need to make logs ness noisy.

plugins/aggregators/derivative/derivative.go Outdated Show resolved Hide resolved
plugins/aggregators/derivative/derivative.go Outdated Show resolved Hide resolved
plugins/aggregators/derivative/derivative.go Outdated Show resolved Hide resolved
Co-authored-by: Steven Soroka <ssoroka78@gmail.com>
@ssoroka ssoroka merged commit 927d34f into influxdata:master Mar 3, 2021
@KarstenSchnitter
Copy link
Contributor Author

Wow, great to see the merge. Thanks for all the help and effort.

matthijskooijman added a commit to matthijskooijman/telegraf that referenced this pull request Oct 15, 2022
This comment states that *if* the variable option is used, the name of
the resulting variable is generated differently. However, in practice
the name of the resulting variable will always just use the (specified
or default) suffix, regardless of whether the variable option is set.

It seems this behavior and this comment were both already present when
the plugin was first introduced in PR influxdata#3762 (commit 927d34f), probably
a remnant of changes during PR discussion.
matthijskooijman added a commit to matthijskooijman/telegraf that referenced this pull request Oct 15, 2022
This comment states that *if* the variable option is used, the name of
the resulting variable is generated differently. However, in practice
the name of the resulting variable will always just use the (specified
or default) suffix, regardless of whether the variable option is set.

It seems this behavior and this comment were both already present when
the plugin was first introduced in PR influxdata#3762 (commit 927d34f), probably
a remnant of changes during PR discussion.
arstercz pushed a commit to arstercz/telegraf that referenced this pull request Mar 5, 2023
Calculate derivatives based on time or fields.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new plugin plugin/aggregator 1. Request for new aggregator plugins 2. Issues/PRs that are related to aggregator plugins ready for final review This pull request has been reviewed and/or tested by multiple users and is ready for a final review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants