-
Notifications
You must be signed in to change notification settings - Fork 804
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
Make Labels Optional for CounterMetric::add #1032
Make Labels Optional for CounterMetric::add #1032
Conversation
@@ -133,7 +133,7 @@ export class CounterMetric extends Metric<BoundCounter> implements api.Counter { | |||
* @param labels key-values pairs that are associated with a specific metric | |||
* that you want to record. | |||
*/ | |||
add(value: number, labels: api.Labels) { | |||
add(value: number, labels: api.Labels = {}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nice, it would be nice if you can do the same thing to measure.record
(https://github.com/astorm/opentelemetry-js/blob/astorm/labels-optional/packages/opentelemetry-metrics/src/Metric.ts#L166)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just realized, Prometheus exporter would fail after this change. Especially below line due to toString
method on undefined
:
...record.descriptor.labelKeys.map(k => record.labels[k].toString()) |
I would prefer to fix it in this same PR and do some end to end manual testing. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, in order to pass the build you need to make the same change in the API package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the guidance and patience @mayurkale22 -- I'm new to the repo and the project and I'm still getting my sea legs.
Fixing this for the MeasureMetric
in this PR makes sense. Fixing the prometheus exporter in this PR also makes sense. I presume the change in opentelemetry-api
would be to the interfaces, and that also makes sense to do in this PR.
I'll ping -- you? -- via a PR comment when that's done. If there's more to The Process™ please let me know.
Best wishes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM, just add a comment on this thread when new changes are ready to review. I usually use this example to test against prom. exporter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mayurkale22 not sure why you think the prometheus exporter would fail on that line. Can you explain? I'm hesitant to approve changes to the _registerMetric
routine in the prometheus exporter because the prom-client has some surprising behavior, and that is the logic we use to destroy and recreate the counters with the new values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mayurkale22 not sure why you think the prometheus exporter would fail on that line. Can you explain?
Looks like @astorm already mention the reason, here-> #1032 (comment) (due to toString
method on undefined
label value).
I'm hesitant to approve changes to the _registerMetric routine in the prometheus exporter because the prom-client ....
I would suggest to add new test in prom. exporter with some LabelKeys
but w/o Labels
(values). You can reuse existing test (like this one), just dont bind the labels to metric.
@mayurkale22 (or others) -- I've
Regarding Prometheus -- I left a question in the gitter room about this, but I can't get the prometheus exporter package to build cleanly. When running
Before I go off on some yak shave, does anyone reading have any advice on how I might proceed to a clean build. One I have a clean build I can make a pass at fixing the prometheus exporter so it doesn't assume counter metrics have labels. |
Codecov Report
@@ Coverage Diff @@
## master #1032 +/- ##
===========================================
- Coverage 95.09% 78.61% -16.48%
===========================================
Files 212 72 -140
Lines 8903 1791 -7112
Branches 801 252 -549
===========================================
- Hits 8466 1408 -7058
+ Misses 437 383 -54
|
I tried repro'd it locally, seems working fine for me. |
@mayurkale22 OK -- I was able to work around (but not fix) my repo/learna issues and fix the Prometheus exporter for the case where A metric's been defined with set of label keys, but values are not provided when recording the metric (either by passing a My main interest in this PR is being able to create a simple counter with no labels and increment it. As this PR sits right now, I think we've accomplished that, but if there's more to be done here please let me know. Also -- just to say it out loud -- there seems to be a non-symmetry to the API design that exists regardless of this PR. The fact you can define a set of label keys for a metric, but then not define values for those keys when recording a metric creates some ambiguity as far as what the correct behavior should be (Record with undefined values for that key(s)? Throw an error because the keys are there? Log an error but still record? Log an error but don't record?) I'm not sure if anything can/should be done about this, but if there is it feels outside the scope of this small PR. Thanks again for considering this and for the help getting oriented in the repo. |
@astorm since you're in a weird state I would suggest a complete clean and rebootstrap MAKE SURE YOU HAVE COMMITTED ANYTHING YOU WANT TO KEEP BEFORE DOING THIS # from the root of the project
lerna clean -y
git clean -fdx
npm install # This will cause the project to be built and linked by npm scripts |
@dyladan Thank you for the advice -- I gave that a try and still ran similar issues, and I tried a fresh @dyladan question -- I noticed in the sample command you gave me that you're running |
Oh sorry yes I do have lerna installed globally. The issue you're seeing looks like a compilation issue. It's possible that the $ lerna --version
3.20.2
$ node --version
v12.14.1 |
I am able to reproduce your issue on a complete rebuild. |
Yay, I am not any more insane that any other software engineer :) And I learned the project's CircleCI tests don't include a full compile cycle, so that's a good thing to know. Regardless of these build issues, this PR is ready for review. |
The CI uses a cached set of dependencies because the dep install takes so long and takes so many resources. It's unfortunate, but it is the way it is. Changing any |
@@ -184,7 +184,9 @@ export class PrometheusExporter implements MetricExporter { | |||
*/ | |||
if (metric instanceof Counter) { | |||
metric.remove( | |||
...record.descriptor.labelKeys.map(k => record.labels[k].toString()) | |||
...record.descriptor.labelKeys.map(k => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In what cases would record.labels[k]
be missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my manual testing last night this change prevented an error being thrown when a user instantiates a counter with a label key
const monotonicCounter = meter.createCounter('monotonic_counter', {
monotonic: true,
labelKeys: ['pid'],
description: 'Example of a monotonic counter',
});
but then fails to provide a value for that key.
monotonicCounter.add(1, {})
monotonicCounter.add(1)
@dyladan With my build issues sorted/understood I can (depending on how your conversation with @mayurkale22 goes) either add tests that make the use-case here clear or revert this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I understand. Instead of falling back to an empty string, I think I would prefer a filter on the list.
metric.remove(
...record.descriptor.labelKeys
.filter(k => record.labels[k] != null)
.map(k => record.labels[k].toString())
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is clever solution but feel like it won't work as expected.
AFAIK prom-client will throw "Invalid number of arguments" exception if length of keys != length of values. See: https://github.com/siimon/prom-client/blob/master/lib/util.js#L34
One option is to fall back on "value missing or unknown" as a default value when the corresponding value is not defined in any given key(s), similar to the description field. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Option 2: Instead of blindly attaching our Labelkeys
to prom-client's labelNames
, we can filter the keys based on valid value.
This is what python has implemented: https://github.com/open-telemetry/opentelemetry-python/blob/master/ext/opentelemetry-ext-prometheus/src/opentelemetry/ext/prometheus/__init__.py#L146-L150
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your feedback @mayurkale22
WDYT?
IT I've been wrangled into an bug fix that is just outside the scope of my original PR -- but I can live with that :)
Re: option 2 -- when you say
Option 2: Instead of blindly attaching our Labelkeys to prom-client's labelNames, we can filter the keys based on valid value.
My interpretation of this is it's a suggestion that, when it comes time to create the Prometheus metric, we look at the keys and values of the passed in Open Telemetry metric, remove any keys with "non-valid" values (undefined, null, -- others?) and create the Prometheus metric with this new, smaller, set of keys.
If that's the suggestion -- I don't think this is the right course of action. Label keys seem like a fundamental part of a metric. That is -- a metric with the keys [foo
, bar
, baz
] seems like a different metric than one with the keys [foo
, bar
]. Removing keys doesn't seems like the right course of action.
Give than, Option 1 seems like the better approach.
One option is to fall back on "value missing or unknown" as a default value when the corresponding value is not defined in any given key(s),
You didn't indicate whether you thought this value should be added when handling the Prometheus metric, or when recording the Open Telemetry metric. My assumption is the former, as having this extra work happen every time a metric is recorded would be excessive.
Given all that: I intend to change how Prometheus metrics are instantiated. If a value isn't present for a specific key, I will use a constant string of value missing
for its value. I will add tests to cover this case. I'll check the spec for what constitutes a valid values, and make judgment call if there are ambiguities there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dyladan would like you know your thoughts on this?
IT I've been wrangled into an bug fix that is just outside the scope of my original PR
Perhaps we can merge this PR and address prometheus exporter issue in the separate PR (btw, this won't make master branch unstable but we need to apply fix before next release). If we decide to merge, I would suggest to revert prometheus related to changes from this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think I would rather see it as two separate PRs simply for the purpose of having better history later when we have to go spelunking through PRs to discover why decisions were made. Not a strong preference though. Agree the prom changes should be reverted if this is going to merge without a proper fix.
@@ -133,7 +133,7 @@ export class CounterMetric extends Metric<BoundCounter> implements api.Counter { | |||
* @param labels key-values pairs that are associated with a specific metric | |||
* that you want to record. | |||
*/ | |||
add(value: number, labels: api.Labels) { | |||
add(value: number, labels: api.Labels = {}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mayurkale22 not sure why you think the prometheus exporter would fail on that line. Can you explain? I'm hesitant to approve changes to the _registerMetric
routine in the prometheus exporter because the prom-client has some surprising behavior, and that is the logic we use to destroy and recreate the counters with the new values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks
@open-telemetry/javascript-approvers We need more reviews for this one! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, one minor comment
* fix: homepage links * fix: add homepage for redis-4 Co-authored-by: Amir Blum <amir@aspecto.io>
* fix: homepage links * fix: add homepage for redis-4 Co-authored-by: Amir Blum <amir@aspecto.io>
* fix: homepage links * fix: add homepage for redis-4 Co-authored-by: Amir Blum <amir@aspecto.io>
Which problem is this PR solving?
This solves the problem described in #1031 -- where not providing labels to a counter metric results in an error.
Short description of the changes
This PR changes the method signature of the
add
method on theCounterMetric
class to provide a default value for thelabels
parameter. This is done so that thehashLabels
utility function does not throw an error when trying to passundefined
toObject.keys(labels);
This PR also adds a new unit test to exercise the default option.