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

feat: implement labelset #463

Merged
merged 24 commits into from
Nov 7, 2019
Merged

Conversation

xiao-lix
Copy link
Contributor

Which problem is this PR solving?

Short description of the changes

  • Implement LabelSet

Copy link
Member

@markwolff markwolff left a comment

Choose a reason for hiding this comment

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

Overall LGTM! Left a few questions/comments

packages/opentelemetry-metrics/src/Handle.ts Outdated Show resolved Hide resolved
packages/opentelemetry-types/src/metrics/Metric.ts Outdated Show resolved Hide resolved
@codecov-io
Copy link

codecov-io commented Oct 29, 2019

Codecov Report

Merging #463 into master will increase coverage by 3.2%.
The diff coverage is 99.02%.

@@            Coverage Diff            @@
##           master     #463     +/-   ##
=========================================
+ Coverage    91.6%   94.81%   +3.2%     
=========================================
  Files         124      132      +8     
  Lines        5864     6206    +342     
  Branches      551      558      +7     
=========================================
+ Hits         5372     5884    +512     
+ Misses        492      322    -170
Impacted Files Coverage Δ
packages/opentelemetry-metrics/src/Utils.ts 100% <ø> (ø)
packages/opentelemetry-metrics/src/export/types.ts 100% <ø> (ø)
packages/opentelemetry-metrics/src/Meter.ts 95.38% <100%> (ø)
.../opentelemetry-core/test/metrics/NoopMeter.test.ts 97.22% <100%> (+53.97%) ⬆️
packages/opentelemetry-metrics/src/Metric.ts 88.23% <100%> (ø)
packages/opentelemetry-metrics/test/Meter.test.ts 100% <100%> (ø)
packages/opentelemetry-metrics/src/Handle.ts 95.55% <100%> (ø)
...ckages/opentelemetry-core/src/metrics/NoopMeter.ts 100% <100%> (ø) ⬆️
packages/opentelemetry-metrics/src/LabelSet.ts 83.33% <83.33%> (ø)
...ges/opentelemetry-exporter-zipkin/src/transform.ts 100% <0%> (ø) ⬆️
... and 47 more

Copy link

@lzchen lzchen left a comment

Choose a reason for hiding this comment

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

Please see my comments.

packages/opentelemetry-metrics/src/types.ts Outdated Show resolved Hide resolved
packages/opentelemetry-metrics/src/types.ts Outdated Show resolved Hide resolved
packages/opentelemetry-metrics/src/export/types.ts Outdated Show resolved Hide resolved
packages/opentelemetry-types/src/metrics/Metric.ts Outdated Show resolved Hide resolved
@@ -23,5 +23,5 @@ const COMMA_SEPARATOR = ',';
* @returns The hashed label values string.
*/
export function hashLabelValues(labelValues: string[]): string {
return labelValues.sort().join(COMMA_SEPARATOR);
return labelValues.join(COMMA_SEPARATOR);
Copy link
Contributor Author

@xiao-lix xiao-lix Oct 30, 2019

Choose a reason for hiding this comment

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

I removed sort() here because per the specs, meter.labels(...) function is called before calling any instrument function, thus labels passing to any instrument should be already sorted based on keys. I think we should keep hashLabelValues function to map values and the handle that created the certain values. @mayurkale22 WDYT? Also this may create mistake on user's end when user misuses instrument's method without calling meter.labels(...) and pass an unsorted labels directly.

Copy link
Member

Choose a reason for hiding this comment

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

this may create mistake on user's end when user misuses instrument's method without calling meter.labels(...) and pass an unsorted labels directly.

This is a valid point, I am gonna give another read on specs. Let us know if you have a better solution to handle this.

Copy link
Member

@mayurkale22 mayurkale22 left a comment

Choose a reason for hiding this comment

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

Added a few comments, overall looks like things are coming together.

packages/opentelemetry-core/src/metrics/NoopMeter.ts Outdated Show resolved Hide resolved
packages/opentelemetry-metrics/src/export/types.ts Outdated Show resolved Hide resolved
@@ -23,5 +23,5 @@ const COMMA_SEPARATOR = ',';
* @returns The hashed label values string.
*/
export function hashLabelValues(labelValues: string[]): string {
return labelValues.sort().join(COMMA_SEPARATOR);
return labelValues.join(COMMA_SEPARATOR);
Copy link
Member

Choose a reason for hiding this comment

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

this may create mistake on user's end when user misuses instrument's method without calling meter.labels(...) and pass an unsorted labels directly.

This is a valid point, I am gonna give another read on specs. Let us know if you have a better solution to handle this.

packages/opentelemetry-types/src/metrics/Metric.ts Outdated Show resolved Hide resolved
Comment on lines 128 to 134
let labelSetKey = keys.reduce((result, key) => {
if (result.length > 2) {
result += ',';
}
result = result + key + ':' + labels[key];
return result;
}, '|#');
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Generate labelSetKey as "|#key1:val1,key2:val2", not sure if we need the prefix "|#", just be consistent with GO here.

* @param labelValues The list of the label values.
* @returns The hashed label values string.
*/
export function hashLabelValues(labelValues: string[]): string {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

With labelSetKey, there's no need to have this function.

export type Labels = Record<string, string>;

/**
* Canonicalized labels with an unique string labelSetKey.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* Canonicalized labels with an unique string labelSetKey.
* Canonicalized labels with a unique string labelSetKey.

Copy link
Member

Choose a reason for hiding this comment

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

If labelSetKey is renamed, would need to adjust this based on that :)

* Canonicalized labels with an unique string labelSetKey.
*/
export interface LabelSet {
labelSetKey: string;
Copy link
Member

Choose a reason for hiding this comment

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

What do you think about calling this something like encoded? I think we should avoid having the word "key" or "value" in this to prevent someone from thinking this is part of the actual dictionary

Copy link
Member

Choose a reason for hiding this comment

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

I would prefer something like identifier that doesn't have as much implied meaning as encoded. To me, encoded implies that it is a decodable version of the LabelSet, where I don't think that is actually guaranteed by the spec. I think it's just meant to be a unique identifier.

Copy link

Choose a reason for hiding this comment

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

@dyladan is correct in that it is meant to be a unique identifier. We are using encoded in Python as well as Go implementation however.

Copy link
Member

Choose a reason for hiding this comment

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

I am okay with identifier as well. It diverges from other SDKs, but I think it is more clear

Comment on lines 132 to 133
result = result + key + ':' + labels[key];
return result;
Copy link
Member

Choose a reason for hiding this comment

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

result += key + ':' + labels[key];
return result;

or maybe even just

return result += key + ':' + labels[key];

@@ -13,15 +13,3 @@
* See the License for the specific language governing permissions and
Copy link
Member

Choose a reason for hiding this comment

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

Maybe delete Utils.ts?

@@ -69,3 +69,13 @@ export const DEFAULT_METRIC_OPTIONS = {
labelKeys: [],
valueType: ValueType.DOUBLE,
};

export class LabelSet implements LabelSet {
Copy link
Member

Choose a reason for hiding this comment

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

Few suggestions:

  1. Add JSDoc comment
  2. Move LabelSet to separate module (LabelSet.ts) (?)
  3. LabelSet implements LabelSet looks typo or is this intentional stuff?

Copy link

@lzchen lzchen left a comment

Choose a reason for hiding this comment

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

LGTM

*/
export class CounterHandle extends BaseHandle implements types.CounterHandle {
constructor(
_labelSet: types.LabelSet,
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this isn't private should this just be named labelSet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@draffensperger Yeah that makes sense, then should the _data above be named as data ? thanks.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, no _data is an actual member of the class. We underscore prefix those so that it's clear in the generated JS that they are private. But here labelSet is only a parameter, not a property of the object.

}
return (result += key + ':' + labels[key]);
}, '|#');
let sortedLabels = {} as types.Labels;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this work as let sortedLabels: types.Labels = {}? That's generally a better pattern because it makes sure that the object actually fits the type rather than doing a forceful cast to it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@draffensperger Thanks, will fix it.

*/
labels(labels: types.Labels): types.LabelSet {
let keys = Object.keys(labels).sort();
let identifier = keys.reduce((result, key) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this imply that we don't support , and : in metric label values? Do we enforce that validation anywhere and document it?

@mayurkale22 mayurkale22 merged commit f47c2de into open-telemetry:master Nov 7, 2019
@xiao-lix xiao-lix deleted the xiao/labelset branch November 15, 2019 22:13
pichlermarc pushed a commit to dynatrace-oss-contrib/opentelemetry-js that referenced this pull request Dec 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement LabelSet in metrics
8 participants