From bdd3431648b2d4bc17d0754c66d0663485f5bafb Mon Sep 17 00:00:00 2001 From: jmacd Date: Fri, 13 Sep 2019 16:25:59 -0700 Subject: [PATCH 01/16] Draft LabelSet spec --- text/0000-metric-label-set.md | 121 ++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 text/0000-metric-label-set.md diff --git a/text/0000-metric-label-set.md b/text/0000-metric-label-set.md new file mode 100644 index 000000000..a4f9cd872 --- /dev/null +++ b/text/0000-metric-label-set.md @@ -0,0 +1,121 @@ +# Metric `LabelSet` specification + +**Status:** `proposed` + +Introduce a first-class `LabelSet` API type as a handle on a pre-defined set of labels. + +## Motivation + +Labels are key-value pairs used across OpenTelemetry for categorizing spans (attributes, event fields) and metrics (labels). Treatment of labels in the metrics API is especially important because of certain optimizations that take advantage ofpre-defined labels. + +This optimization currently applies to metric instrument handles, the result of `GetHandle(Instrument, { Key : Value, ... })` on a metric instrument. By allowing the SDK to pre-compute information about the pair of `(Instrument, { Key : Value, ... })`, this reasoning goes, the metrics SDK has the opportunity make individual `Add()` and `Set()` operations on handles as fast as a few machine instructions. + +Adopting a first-class `LabelSet` extends the potential for optimization, significantly, for cases where a the `{ Key : Value, ... }` can be reused despite not re-using `(Instrument, { Key : Value, ... })` pairs. + +The current API specifies one way to use set of labels for more than one measurement, + +``` +RecordBatch({ Key1: Value1, + Key2: Value2, + ... }, + [ (Gauge, Value), + (Cumulative, Value), + (Measure, Value), + ... ]) +``` + +This RFC proposes the new `LabelSet` concept is returned by an API named like `Meter.DefineLabels({ Key: Value, ... })` which allows the SDK to potentially sort, canonicalize, or hash the set of labels once, allowing it to be re-used in several ways. For example, the `RecordBatch` above can be written as one call to `DefineLabels` and inidividual operations. + +``` +Labels := meter.DefineLabels({ Key1: Value1, + Key2: Value2, + ... }) +Cumulative.Add(Value, Labels) +Gauge.Set(Value, Labels) +Measure.Record(Value, Labels) +... +``` + +With a first-class `LabelSet`, labels can even be re-used across multiple calls to `RecordBatch`. + +## Explanation + +Metric instrument APIs which presently take labels in the form `{ Key: Value, ... }` will be updated to take an explicit `LabelSet`. The `Meter.DefineLabels` API method supports getting a `LabelSet` from the SDK, allowing the programmer to pre-define labels without being required to manage handles. This brings the numnber of ways to update a metric to three, via re-using a handle `GetHandle()`: + +``` +cumulative := metric.NewFloat64Cumulative("my_counter", [ + "required_key1", + "required_key2", + ]) +labels := meter.DefineLabels({ "required_key1": value1, + "required_key2": value2 }) +handle := cumulative.GetHandle(labels) +for ... { + handle.Add(quantity) +} +``` + +To operate on a metric instrument directly, without requiring a handle: + +``` +cumulative.Add(quantity, labels) +gauge.Set(quantity, labels) +measure.Record(quantity, labels) +``` + +To operate on a batch of labels, + +``` +RecordBatch(labels, [ + (Instrument1, Value1), + (Instrument2, Value2), + ... + ]) +``` + +Note that `meter.GetHandle(instrument, meter.DefineLabels())` is the same as `meter.GetDefaultHandle()`. + +### Ordered `LabelSet` option + +OpenCensus specified support for ordered label sets, in which values for required keys may be passed in order, allowing the implementation directly compute a unique encoding for the label set. We recognize that providing ordered values is an option that makes sense in some languages and not others, and leave this as an option. Support for ordered label sets might be arranged through ordered key sets, for example: + +``` +requiredKeys := metric.DefineKeys("key1", "key2", "key3") +labelSet := requiredKeys.DefineValues(meter, 1, 2, 3) +``` + +## Internal details + +Metric instruments are specified as SDK-independent objects, therefore metric handles were required to bind the instrument to the SDK in order to operate. In this proposal, `LabelSet` becomes responsible for binding the SDK at any call site where it is used. Other than knowing the `Meter` that defined it, `LabelSet` is an opaque interface. The three ways to use `LabelSet` in the metrics API are: + +``` +_instrument_.GetHandle(labels)._Action_(value) // Action on a handle +_instrument_._Action_(value, labels) // Single action, no handle +RecordBatch(labels, [(_instrument_, value), ...]) // Batch action, no handles +``` + +## Trade-offs and mitigations + +Each programming language should select the names for `LabelSet` and `DefineLabels` that are most idiomatic and sensible. + +In languages where overloading is a standard convenience, the metrics API may elect to offer alternate forms that elide the call to `DefineLabels`, for example this: + +``` +instrument.GetHandle(meter, { Key: Value, ... }) +``` + +as opposed to this: + +``` +instrument.GetHandle(meter.DefineLabels({ Key: Value, ... })) +``` + +A key distinction between `LabelSet` and similar concepts in existing metrics libraries is that it is a _write-only_ structure allowing the programmer to set diagnostic state, while ensuring that diagnostic state does not become application-level state. + +## Prior art and alternatives + +There is not clear prior art like `LabelSet` as defined here. + +## Open questions + +Introducing `LabelSet` makes one more step for simply using the metrics API. Can convenience libraries, utility classes, and overloaded functions make the simple API use-cases acceptable while supporting re-use of `LabelSet` objects for optimization? From 55488a549c5f69671cc139adda6242bb66f7e907 Mon Sep 17 00:00:00 2001 From: jmacd Date: Fri, 13 Sep 2019 16:33:34 -0700 Subject: [PATCH 02/16] Typos --- text/0000-metric-label-set.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/text/0000-metric-label-set.md b/text/0000-metric-label-set.md index a4f9cd872..37ff4b3d5 100644 --- a/text/0000-metric-label-set.md +++ b/text/0000-metric-label-set.md @@ -6,7 +6,7 @@ Introduce a first-class `LabelSet` API type as a handle on a pre-defined set of ## Motivation -Labels are key-value pairs used across OpenTelemetry for categorizing spans (attributes, event fields) and metrics (labels). Treatment of labels in the metrics API is especially important because of certain optimizations that take advantage ofpre-defined labels. +Labels are key-value pairs used across OpenTelemetry for categorizing spans (attributes, event fields) and metrics (labels). Treatment of labels in the metrics API is especially important because of certain optimizations that take advantage of pre-defined labels. This optimization currently applies to metric instrument handles, the result of `GetHandle(Instrument, { Key : Value, ... })` on a metric instrument. By allowing the SDK to pre-compute information about the pair of `(Instrument, { Key : Value, ... })`, this reasoning goes, the metrics SDK has the opportunity make individual `Add()` and `Set()` operations on handles as fast as a few machine instructions. @@ -24,7 +24,7 @@ RecordBatch({ Key1: Value1, ... ]) ``` -This RFC proposes the new `LabelSet` concept is returned by an API named like `Meter.DefineLabels({ Key: Value, ... })` which allows the SDK to potentially sort, canonicalize, or hash the set of labels once, allowing it to be re-used in several ways. For example, the `RecordBatch` above can be written as one call to `DefineLabels` and inidividual operations. +This RFC proposes the new `LabelSet` concept is returned by an API named `Meter.DefineLabels({ Key: Value, ... })` which allows the SDK to potentially sort, canonicalize, or hash the set of labels once, allowing it to be re-used in several ways. For example, the `RecordBatch` above can be written as one call to `DefineLabels` and inidividual operations. ``` Labels := meter.DefineLabels({ Key1: Value1, @@ -40,7 +40,7 @@ With a first-class `LabelSet`, labels can even be re-used across multiple calls ## Explanation -Metric instrument APIs which presently take labels in the form `{ Key: Value, ... }` will be updated to take an explicit `LabelSet`. The `Meter.DefineLabels` API method supports getting a `LabelSet` from the SDK, allowing the programmer to pre-define labels without being required to manage handles. This brings the numnber of ways to update a metric to three, via re-using a handle `GetHandle()`: +Metric instrument APIs which presently take labels in the form `{ Key: Value, ... }` will be updated to take an explicit `LabelSet`. The `Meter.DefineLabels` API method supports getting a `LabelSet` from the SDK, allowing the programmer to pre-define labels without being required to manage handles. This brings the number of ways to update a metric to three, via re-using a handle from `GetHandle()`: ``` cumulative := metric.NewFloat64Cumulative("my_counter", [ @@ -89,9 +89,9 @@ labelSet := requiredKeys.DefineValues(meter, 1, 2, 3) Metric instruments are specified as SDK-independent objects, therefore metric handles were required to bind the instrument to the SDK in order to operate. In this proposal, `LabelSet` becomes responsible for binding the SDK at any call site where it is used. Other than knowing the `Meter` that defined it, `LabelSet` is an opaque interface. The three ways to use `LabelSet` in the metrics API are: ``` -_instrument_.GetHandle(labels)._Action_(value) // Action on a handle -_instrument_._Action_(value, labels) // Single action, no handle -RecordBatch(labels, [(_instrument_, value), ...]) // Batch action, no handles +instrument.GetHandle(labels).Action(value) // Action on a handle +instrument.Action(value, labels) // Single action, no handle +RecordBatch(labels, [(instrument, value), ...]) // Batch action, no handles ``` ## Trade-offs and mitigations @@ -110,12 +110,14 @@ as opposed to this: instrument.GetHandle(meter.DefineLabels({ Key: Value, ... })) ``` -A key distinction between `LabelSet` and similar concepts in existing metrics libraries is that it is a _write-only_ structure allowing the programmer to set diagnostic state, while ensuring that diagnostic state does not become application-level state. +A key distinction between `LabelSet` and similar concepts in existing metrics libraries is that it is a _write-only_ structure, allowing the programmer to set diagnostic state while ensuring that diagnostic state does not become application-level state. ## Prior art and alternatives There is not clear prior art like `LabelSet` as defined here. +A potential application for `DefineLabels` is to pre-compute the bytes of the statsd encoding for a label set once, to avoid repeatedly serializing this information. + ## Open questions Introducing `LabelSet` makes one more step for simply using the metrics API. Can convenience libraries, utility classes, and overloaded functions make the simple API use-cases acceptable while supporting re-use of `LabelSet` objects for optimization? From 5037a48ec99718feffc87bcb8a3a28df41640242 Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 16 Sep 2019 11:29:50 -0700 Subject: [PATCH 03/16] Add notes on performance expectations --- text/0000-metric-label-set.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/text/0000-metric-label-set.md b/text/0000-metric-label-set.md index 37ff4b3d5..b9f4e10a0 100644 --- a/text/0000-metric-label-set.md +++ b/text/0000-metric-label-set.md @@ -94,6 +94,12 @@ instrument.Action(value, labels) // Single action, no handle RecordBatch(labels, [(instrument, value), ...]) // Batch action, no handles ``` +Metric SDKs that do not or cannot take advantage of the Handle or LabelSet optimizations are not especially burdened by having to support these APIs. It is trivial to supply implementations of the handle as a simple (`Instrument`, `LabelSet`) pair and the label set as simple list of labels. This may not be acceptible in performance-critical applications, but this is the common case in many metrics and diagnostics APIs today. + +Applications that forego the use of handles but do prefer to store and pass `LabelSet` objects may wonder what kind of performance to expect when exporting pre-computed metric data from their SDK. What should we expect of a high-performance metrics SDK in this regard? Since the SDK is involved in constructing the label set, we can presume it has performed the expensive computation of joining the labels into a lookup key or a serializable encoding, yielding a unique ID for the label set. + +What remains, at `Record` time, to update the pre-aggregation state, is to lookup a map entry using the pair (`Instrument` ID, `LabelSet` ID), which is somewhat more than the cost of `GetHandle`. It is relatively fast compared with joining the labels into a lookup key, but there are complications. The lookup has to be synchronized, which could be a problem in some cases, and the map cannot grow without bound so there is a management "tax" to consider. This is what we might expect of a high-performance metrics SDK. + ## Trade-offs and mitigations Each programming language should select the names for `LabelSet` and `DefineLabels` that are most idiomatic and sensible. From 6713f93eef963eefcb1fa2180ef0f26cbb0dd6f7 Mon Sep 17 00:00:00 2001 From: jmacd Date: Tue, 17 Sep 2019 13:25:42 -0700 Subject: [PATCH 04/16] Typo --- text/0000-metric-label-set.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-metric-label-set.md b/text/0000-metric-label-set.md index b9f4e10a0..5db827f62 100644 --- a/text/0000-metric-label-set.md +++ b/text/0000-metric-label-set.md @@ -94,7 +94,7 @@ instrument.Action(value, labels) // Single action, no handle RecordBatch(labels, [(instrument, value), ...]) // Batch action, no handles ``` -Metric SDKs that do not or cannot take advantage of the Handle or LabelSet optimizations are not especially burdened by having to support these APIs. It is trivial to supply implementations of the handle as a simple (`Instrument`, `LabelSet`) pair and the label set as simple list of labels. This may not be acceptible in performance-critical applications, but this is the common case in many metrics and diagnostics APIs today. +Metric SDKs that do not or cannot take advantage of the Handle or LabelSet optimizations are not especially burdened by having to support these APIs. It is trivial to supply implementations of the handle as a simple (`Instrument`, `LabelSet`) pair and the label set as simple list of labels. This may not be acceptable in performance-critical applications, but this is the common case in many metrics and diagnostics APIs today. Applications that forego the use of handles but do prefer to store and pass `LabelSet` objects may wonder what kind of performance to expect when exporting pre-computed metric data from their SDK. What should we expect of a high-performance metrics SDK in this regard? Since the SDK is involved in constructing the label set, we can presume it has performed the expensive computation of joining the labels into a lookup key or a serializable encoding, yielding a unique ID for the label set. From bb51cca4dca45fbff41ebb32658656743cff06b3 Mon Sep 17 00:00:00 2001 From: jmacd Date: Wed, 18 Sep 2019 14:41:35 -0700 Subject: [PATCH 05/16] Updates to use Monotonic/NonMonotonic, and NonNegtive/Signed --- text/0003-measure-metric-type.md | 22 +++++++++++++++------- text/0008-metric-observer.md | 6 +++--- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/text/0003-measure-metric-type.md b/text/0003-measure-metric-type.md index 6a17671f6..93f7dcc35 100644 --- a/text/0003-measure-metric-type.md +++ b/text/0003-measure-metric-type.md @@ -85,7 +85,7 @@ The specification will be updated with the following guidance. Likely to be the most common kind of metric, cumulative metric events express the computation of a sum. Choose this kind of metric when the value is a quantity, the sum is of primary interest, and the event count and distribution are not of primary interest. To raise (or lower) a cumulative metric, call the `Add()` method. -If the quantity in question is always non-negative, it implies that the sum never descends. This is the common case, where cumulative metrics only go up, and these _unidirectional_ cumulative metric instruments serve to compute a rate. For this reason, cumulative metrics have a `Bidirectional` option to be declared as allowing negative inputs, the uncommon case. The API will reject negative inputs to (default) unidirectional cumulative metrics, instead submitting an SDK error event, which helps ensure meaningful rate calculations. +If the quantity in question is always non-negative, it implies that the sum is monotonic. This is the common case, where cumulative metrics only go up, these metric instruments serve to compute a rate. For this reason, cumulative metrics have a `NonMonotonic` option to be declared as allowing negative inputs, the uncommon case. The SDK should reject negative inputs to monotonic cumulative metrics, but it is not required to. For cumulative metrics, the default OpenTelemetry implementation exports the sum of event values taken over an interval of time. @@ -95,7 +95,7 @@ Gauge metrics express a pre-calculated value that is either `Set()` by explicit Only the gauge kind of metric supports observing the metric via a gauge `Observer` callback (as an option, see `0008-metric-observer.md`). Semantically, there is an important difference between explicitly setting a gauge and observing it through a callback. In case of setting the gauge explicitly, the call happens inside of an implicit or explicit context. The implementation is free to associate the explicit `Set()` event with a context, for example. When observing gauge metrics via a callback, there is no context associated with the event. -As a special case, to support existing metrics infrastructure and the `Observer` pattern, a gauge metric may be declared as a precomputed, unidirectional sum using the `Unidirectional` option, in which case it is may be used to define a rate. The initial value is presumed to be zero. The API will reject descending updates to non-descending gauges, instead submitting an SDK error event. +As a special case, to support existing metrics infrastructure and the `Observer` pattern, a gauge metric may be declared as a precomputed, monotonic sum using the `Monotonic` option, in which case it is may be used to define a rate. The initial value is presumed to be zero. The SDK should reject descending updates to non-descending gauges, but it is not required to. For gauge metrics, the default OpenTelemetry implementation exports the last value that was explicitly `Set()`, or if using a callback, the current value from the `Observer`. @@ -108,7 +108,7 @@ Measure metrics express a distribution of values. This kind of metric should be The key property of a measure metric event is that computing quantiles and/or summarizing a distribution (e.g., via a histogram) may be expensive. Not only will implementations have various capabilities and algorithms for this task, users may wish to control the quality and cost of aggregating measure metrics. -Like cumulative metrics, non-negative measures are an important case because they support rate calculations. As an option, measure metrics may be declared as `NonNegative`. The API will reject negative metric events for non-negative measures, instead submitting an SDK error event. +Like cumulative metrics, non-negative measures are an important case because they support rate calculations. Like cumulative metrics, non-negative is the default case since non-negative quantities are common. As an option, measure metrics may be declared as `Signed` to support positive and negative values. The API should reject negative metric events for non-negative measures, but it is not required to. Because measure metrics have such wide application, implementations are likely to provide configurable behavior. OpenTelemetry may provide such a facility in its standard SDK, but in case no configuration is provided by the application, a low-cost policy is specified as the default behavior, which is to export the sum, the count (rate), the minimum value, and the maximum value. @@ -122,11 +122,19 @@ The optional properties of a metric instrument are: | Property | Description | Metric kind | |----------|-------------|-------------| -| Required Keys | Determines labels that are always set on metric handles | All kinds | +| Required Keys | Determines labels that are always defined on metric handles | All kinds | | Disabled | Indicates a verbose metric that does not report by default | All kinds | -| Bidirectional | Indicates a cumulative metric instrument that goes up and down | Cumulative | -| Unidirectional | Indicate a gauge that only ascends, for rate calculation | Gauge | -| NonNegative | Indicates a measure that is never negative, for rate calculation | Measure | +| NonMonotonic | Indicates a cumulative metric instrument that goes up and down | Cumulative | +| Monotonic | Indicate a gauge that only ascends (for rate calculation) | Gauge | +| Signed | Indicates a measure that is positive or negative | Measure | + +The optional modes are compared with their defaults here: + +| Metric kind | Default behavior | Alternate behavior | Support for | +|-------------|------------------|--------------------|-----------------------| +| Cumulative | Monotonic | NonMonotonic | Up-down counters | +| Gauge | NonMonotonic | Monotonic | Cumulative gauges | +| Measure | NonNegative | Signed | Negative measurements | ### RecordBatch API diff --git a/text/0008-metric-observer.md b/text/0008-metric-observer.md index b44e30c47..1035e4250 100644 --- a/text/0008-metric-observer.md +++ b/text/0008-metric-observer.md @@ -12,15 +12,15 @@ The current specification describes metric callbacks as an alternate means of ge Gauge metric instruments are typically used to reflect properties that are pre-computed by a system, where the measurement interval is arbitrary. When selecting a gauge, as opposed to the cumulative or measure kind of metric instrument, there could be significant computational cost in computing the current value. When this is the case, it is understandable that we are interested in computing them on demand to minimize cost. -Why are gauges different than cumulative and measure instruments? Measure instruments, by definition, carry information in the individual event, so the callback cannot optimize any better than the SDK can in this case. Cumulative instruments are more commonly used to record amounts that are readily available, such as the number of bytes read or written, and while this may not always be true, recall the special case of `NonDescending` gauges. +Why are gauges different than cumulative and measure instruments? Measure instruments, by definition, carry information in the individual event, so the callback cannot optimize any better than the SDK can in this case. Cumulative instruments are more commonly used to record amounts that are readily available, such as the number of bytes read or written, and while this may not always be true, recall the special case of `Monotonic` gauges. -`NonDescending` gauges owe their existence to this case, that we support non-negative cumulative metrics which, being expensive to compute, are recommended for use with `Observer` callbacks. For example, if it requires a system call or more to compute a non-descending sum, such as the _cpu seconds_ consumed by the process, we should declare a non-descending gauge `Observer` for the instrument, instead of a cumulative. This allows the cost of the metric to be reduced according to the desired monitoring frequency. +`Monotonic` gauges owe their existence to this case, that we support monotonic cumulative metrics which, being expensive to compute, are recommended for use with `Observer` callbacks. For example, if it requires a system call or more to compute a monotonic sum, such as the _cpu seconds_ consumed by the process, we should declare a monotonic gauge `Observer` for the instrument, instead of a cumulative. This allows the cost of the metric to be reduced according to the desired monitoring frequency. One significant difference between gauges that are explicitly `Set()`, as compared with observer callbacks, is that `Set()` happens inside a context, whereas the observer callback does not. ## Details -Observer callbacks are only supported for gauge metric instruments. Use the language-specific constructor for an Observer gauge (e.g., `metric.NewFloat64Observer()`). Observer gauges support the `NonDescending` option. +Observer callbacks are only supported for gauge metric instruments. Use the language-specific constructor for an Observer gauge (e.g., `metric.NewFloat64Observer()`). Observer gauges support the `Monotonic` option. Callbacks return a map from _label set_ to gauge value. Gauges declared with observer callbacks cannot also be `Set`. From 2884dcff03d619e670abd7ef521f5bf9979663e1 Mon Sep 17 00:00:00 2001 From: jmacd Date: Wed, 18 Sep 2019 14:48:29 -0700 Subject: [PATCH 06/16] Revert --- text/0003-measure-metric-type.md | 22 +++++++--------------- text/0008-metric-observer.md | 6 +++--- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/text/0003-measure-metric-type.md b/text/0003-measure-metric-type.md index 93f7dcc35..6a17671f6 100644 --- a/text/0003-measure-metric-type.md +++ b/text/0003-measure-metric-type.md @@ -85,7 +85,7 @@ The specification will be updated with the following guidance. Likely to be the most common kind of metric, cumulative metric events express the computation of a sum. Choose this kind of metric when the value is a quantity, the sum is of primary interest, and the event count and distribution are not of primary interest. To raise (or lower) a cumulative metric, call the `Add()` method. -If the quantity in question is always non-negative, it implies that the sum is monotonic. This is the common case, where cumulative metrics only go up, these metric instruments serve to compute a rate. For this reason, cumulative metrics have a `NonMonotonic` option to be declared as allowing negative inputs, the uncommon case. The SDK should reject negative inputs to monotonic cumulative metrics, but it is not required to. +If the quantity in question is always non-negative, it implies that the sum never descends. This is the common case, where cumulative metrics only go up, and these _unidirectional_ cumulative metric instruments serve to compute a rate. For this reason, cumulative metrics have a `Bidirectional` option to be declared as allowing negative inputs, the uncommon case. The API will reject negative inputs to (default) unidirectional cumulative metrics, instead submitting an SDK error event, which helps ensure meaningful rate calculations. For cumulative metrics, the default OpenTelemetry implementation exports the sum of event values taken over an interval of time. @@ -95,7 +95,7 @@ Gauge metrics express a pre-calculated value that is either `Set()` by explicit Only the gauge kind of metric supports observing the metric via a gauge `Observer` callback (as an option, see `0008-metric-observer.md`). Semantically, there is an important difference between explicitly setting a gauge and observing it through a callback. In case of setting the gauge explicitly, the call happens inside of an implicit or explicit context. The implementation is free to associate the explicit `Set()` event with a context, for example. When observing gauge metrics via a callback, there is no context associated with the event. -As a special case, to support existing metrics infrastructure and the `Observer` pattern, a gauge metric may be declared as a precomputed, monotonic sum using the `Monotonic` option, in which case it is may be used to define a rate. The initial value is presumed to be zero. The SDK should reject descending updates to non-descending gauges, but it is not required to. +As a special case, to support existing metrics infrastructure and the `Observer` pattern, a gauge metric may be declared as a precomputed, unidirectional sum using the `Unidirectional` option, in which case it is may be used to define a rate. The initial value is presumed to be zero. The API will reject descending updates to non-descending gauges, instead submitting an SDK error event. For gauge metrics, the default OpenTelemetry implementation exports the last value that was explicitly `Set()`, or if using a callback, the current value from the `Observer`. @@ -108,7 +108,7 @@ Measure metrics express a distribution of values. This kind of metric should be The key property of a measure metric event is that computing quantiles and/or summarizing a distribution (e.g., via a histogram) may be expensive. Not only will implementations have various capabilities and algorithms for this task, users may wish to control the quality and cost of aggregating measure metrics. -Like cumulative metrics, non-negative measures are an important case because they support rate calculations. Like cumulative metrics, non-negative is the default case since non-negative quantities are common. As an option, measure metrics may be declared as `Signed` to support positive and negative values. The API should reject negative metric events for non-negative measures, but it is not required to. +Like cumulative metrics, non-negative measures are an important case because they support rate calculations. As an option, measure metrics may be declared as `NonNegative`. The API will reject negative metric events for non-negative measures, instead submitting an SDK error event. Because measure metrics have such wide application, implementations are likely to provide configurable behavior. OpenTelemetry may provide such a facility in its standard SDK, but in case no configuration is provided by the application, a low-cost policy is specified as the default behavior, which is to export the sum, the count (rate), the minimum value, and the maximum value. @@ -122,19 +122,11 @@ The optional properties of a metric instrument are: | Property | Description | Metric kind | |----------|-------------|-------------| -| Required Keys | Determines labels that are always defined on metric handles | All kinds | +| Required Keys | Determines labels that are always set on metric handles | All kinds | | Disabled | Indicates a verbose metric that does not report by default | All kinds | -| NonMonotonic | Indicates a cumulative metric instrument that goes up and down | Cumulative | -| Monotonic | Indicate a gauge that only ascends (for rate calculation) | Gauge | -| Signed | Indicates a measure that is positive or negative | Measure | - -The optional modes are compared with their defaults here: - -| Metric kind | Default behavior | Alternate behavior | Support for | -|-------------|------------------|--------------------|-----------------------| -| Cumulative | Monotonic | NonMonotonic | Up-down counters | -| Gauge | NonMonotonic | Monotonic | Cumulative gauges | -| Measure | NonNegative | Signed | Negative measurements | +| Bidirectional | Indicates a cumulative metric instrument that goes up and down | Cumulative | +| Unidirectional | Indicate a gauge that only ascends, for rate calculation | Gauge | +| NonNegative | Indicates a measure that is never negative, for rate calculation | Measure | ### RecordBatch API diff --git a/text/0008-metric-observer.md b/text/0008-metric-observer.md index 1035e4250..b44e30c47 100644 --- a/text/0008-metric-observer.md +++ b/text/0008-metric-observer.md @@ -12,15 +12,15 @@ The current specification describes metric callbacks as an alternate means of ge Gauge metric instruments are typically used to reflect properties that are pre-computed by a system, where the measurement interval is arbitrary. When selecting a gauge, as opposed to the cumulative or measure kind of metric instrument, there could be significant computational cost in computing the current value. When this is the case, it is understandable that we are interested in computing them on demand to minimize cost. -Why are gauges different than cumulative and measure instruments? Measure instruments, by definition, carry information in the individual event, so the callback cannot optimize any better than the SDK can in this case. Cumulative instruments are more commonly used to record amounts that are readily available, such as the number of bytes read or written, and while this may not always be true, recall the special case of `Monotonic` gauges. +Why are gauges different than cumulative and measure instruments? Measure instruments, by definition, carry information in the individual event, so the callback cannot optimize any better than the SDK can in this case. Cumulative instruments are more commonly used to record amounts that are readily available, such as the number of bytes read or written, and while this may not always be true, recall the special case of `NonDescending` gauges. -`Monotonic` gauges owe their existence to this case, that we support monotonic cumulative metrics which, being expensive to compute, are recommended for use with `Observer` callbacks. For example, if it requires a system call or more to compute a monotonic sum, such as the _cpu seconds_ consumed by the process, we should declare a monotonic gauge `Observer` for the instrument, instead of a cumulative. This allows the cost of the metric to be reduced according to the desired monitoring frequency. +`NonDescending` gauges owe their existence to this case, that we support non-negative cumulative metrics which, being expensive to compute, are recommended for use with `Observer` callbacks. For example, if it requires a system call or more to compute a non-descending sum, such as the _cpu seconds_ consumed by the process, we should declare a non-descending gauge `Observer` for the instrument, instead of a cumulative. This allows the cost of the metric to be reduced according to the desired monitoring frequency. One significant difference between gauges that are explicitly `Set()`, as compared with observer callbacks, is that `Set()` happens inside a context, whereas the observer callback does not. ## Details -Observer callbacks are only supported for gauge metric instruments. Use the language-specific constructor for an Observer gauge (e.g., `metric.NewFloat64Observer()`). Observer gauges support the `Monotonic` option. +Observer callbacks are only supported for gauge metric instruments. Use the language-specific constructor for an Observer gauge (e.g., `metric.NewFloat64Observer()`). Observer gauges support the `NonDescending` option. Callbacks return a map from _label set_ to gauge value. Gauges declared with observer callbacks cannot also be `Set`. From fe54cd80757187dd6855615c0ba82c06d66d41e0 Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 21 Oct 2019 20:38:53 -0700 Subject: [PATCH 07/16] PR number 49 --- text/{0000-metric-label-set.md => 0049-metric-label-set.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename text/{0000-metric-label-set.md => 0049-metric-label-set.md} (100%) diff --git a/text/0000-metric-label-set.md b/text/0049-metric-label-set.md similarity index 100% rename from text/0000-metric-label-set.md rename to text/0049-metric-label-set.md From d40d2fc875c476629eea8122be1f0b28cf926857 Mon Sep 17 00:00:00 2001 From: jmacd Date: Tue, 22 Oct 2019 14:13:25 -0700 Subject: [PATCH 08/16] Major revision to match the already-merged specification on LabelSet --- text/0049-metric-label-set.md | 128 ++++++++++++++-------------------- 1 file changed, 52 insertions(+), 76 deletions(-) diff --git a/text/0049-metric-label-set.md b/text/0049-metric-label-set.md index 5db827f62..755e0dbc4 100644 --- a/text/0049-metric-label-set.md +++ b/text/0049-metric-label-set.md @@ -2,109 +2,83 @@ **Status:** `proposed` -Introduce a first-class `LabelSet` API type as a handle on a pre-defined set of labels. +Introduce a first-class `LabelSet` API type as a handle on a pre-defined set of labels for the Metrics API. ## Motivation -Labels are key-value pairs used across OpenTelemetry for categorizing spans (attributes, event fields) and metrics (labels). Treatment of labels in the metrics API is especially important because of certain optimizations that take advantage of pre-defined labels. +Labels are the term for key-value pairs used in the OpenTelemetry Metrics API. Treatment of labels in the metrics API is especially important for performance, across a variety of export strategies. -This optimization currently applies to metric instrument handles, the result of `GetHandle(Instrument, { Key : Value, ... })` on a metric instrument. By allowing the SDK to pre-compute information about the pair of `(Instrument, { Key : Value, ... })`, this reasoning goes, the metrics SDK has the opportunity make individual `Add()` and `Set()` operations on handles as fast as a few machine instructions. +Whether pushing or pulling metrics, whether aggregating metric events in the process or not, it is an expensive computation to translate a set of labels into either a serialized representation or a unique lookup key. Users of the metrics API stand to benefit by re-using label sets whenever possible, because manipulating label sets often dominates the cost of processing metric events. -Adopting a first-class `LabelSet` extends the potential for optimization, significantly, for cases where a the `{ Key : Value, ... }` can be reused despite not re-using `(Instrument, { Key : Value, ... })` pairs. +The Metrics API supports three calling conventions: the Handle convention, the Direct convention, and the Batch convention. Each of these conventions stands to benefit when a `LabelSet` is re-used, as it allows the SDK to process the label set once instead of once per call. Whenever more than one handle will be created with the same labels, whenever more than one instrument will be called directly with the same labels, and whenever more than one batch of metric events will be recorded with the same labels, re-using a `LabelSet` makes it possible for the SDK to improve performance. -The current API specifies one way to use set of labels for more than one measurement, - -``` -RecordBatch({ Key1: Value1, - Key2: Value2, - ... }, - [ (Gauge, Value), - (Cumulative, Value), - (Measure, Value), - ... ]) -``` +## Explanation -This RFC proposes the new `LabelSet` concept is returned by an API named `Meter.DefineLabels({ Key: Value, ... })` which allows the SDK to potentially sort, canonicalize, or hash the set of labels once, allowing it to be re-used in several ways. For example, the `RecordBatch` above can be written as one call to `DefineLabels` and inidividual operations. +Metric instrument APIs which presently take labels in the form `{ Key: Value, ... }` will be updated to take an explicit `LabelSet`. The `Meter.Labels()` API method supports getting a `LabelSet` from the SDK, allowing the programmer to acquire a pre-define label set. Here are several examples of `LabelSet` re-use. Assume we have two instruments: +```golang +var ( + cumulative = metric.NewFloat64Cumulative("my_counter") + gauge = metric.NewFloat64Gauge("my_gauge") +) ``` -Labels := meter.DefineLabels({ Key1: Value1, - Key2: Value2, - ... }) -Cumulative.Add(Value, Labels) -Gauge.Set(Value, Labels) -Measure.Record(Value, Labels) -... -``` - -With a first-class `LabelSet`, labels can even be re-used across multiple calls to `RecordBatch`. -## Explanation - -Metric instrument APIs which presently take labels in the form `{ Key: Value, ... }` will be updated to take an explicit `LabelSet`. The `Meter.DefineLabels` API method supports getting a `LabelSet` from the SDK, allowing the programmer to pre-define labels without being required to manage handles. This brings the number of ways to update a metric to three, via re-using a handle from `GetHandle()`: +Use a `LabelSet` to construct multiple Handles: -``` -cumulative := metric.NewFloat64Cumulative("my_counter", [ - "required_key1", - "required_key2", - ]) -labels := meter.DefineLabels({ "required_key1": value1, - "required_key2": value2 }) -handle := cumulative.GetHandle(labels) +```golang +var ( + labels = meter.Labels({ "required_key1": value1, "required_key2": value2 }) + chandle = cumulative.GetHandle(labels) + ghandle = gauge.GetHandle(labels) +) for ... { - handle.Add(quantity) + // ... + chandle.Add(...) + ghandle.Set(...) } ``` -To operate on a metric instrument directly, without requiring a handle: +Use a `LabelSet` to for multiple Direct calls: -``` +```golang +labels := meter.Labels({ "required_key1": value1, "required_key2": value2 }) cumulative.Add(quantity, labels) gauge.Set(quantity, labels) -measure.Record(quantity, labels) -``` - -To operate on a batch of labels, - -``` -RecordBatch(labels, [ - (Instrument1, Value1), - (Instrument2, Value2), - ... - ]) ``` -Note that `meter.GetHandle(instrument, meter.DefineLabels())` is the same as `meter.GetDefaultHandle()`. +Of course, repeated calls to `Meter.RecordBatch()` could re-use a `LabelSet` as well. ### Ordered `LabelSet` option -OpenCensus specified support for ordered label sets, in which values for required keys may be passed in order, allowing the implementation directly compute a unique encoding for the label set. We recognize that providing ordered values is an option that makes sense in some languages and not others, and leave this as an option. Support for ordered label sets might be arranged through ordered key sets, for example: +As a language-level decision, APIs may support _ordered_ LabelSet +construction, in which a pre-defined set of ordered label keys is +defined such that values can be supplied in order. This allows a +faster code path to construct the `LabelSet`. For example, -``` -requiredKeys := metric.DefineKeys("key1", "key2", "key3") -labelSet := requiredKeys.DefineValues(meter, 1, 2, 3) -``` +```golang -## Internal details +var rpcLabelKeys = meter.OrderedLabelKeys("a", "b", "c") -Metric instruments are specified as SDK-independent objects, therefore metric handles were required to bind the instrument to the SDK in order to operate. In this proposal, `LabelSet` becomes responsible for binding the SDK at any call site where it is used. Other than knowing the `Meter` that defined it, `LabelSet` is an opaque interface. The three ways to use `LabelSet` in the metrics API are: +for _, input := range stream { + labels := rpcLabelKeys.Values(1, 2, 3) // a=1, b=2, c=3 -``` -instrument.GetHandle(labels).Action(value) // Action on a handle -instrument.Action(value, labels) // Single action, no handle -RecordBatch(labels, [(instrument, value), ...]) // Batch action, no handles + // ... +} ``` -Metric SDKs that do not or cannot take advantage of the Handle or LabelSet optimizations are not especially burdened by having to support these APIs. It is trivial to supply implementations of the handle as a simple (`Instrument`, `LabelSet`) pair and the label set as simple list of labels. This may not be acceptable in performance-critical applications, but this is the common case in many metrics and diagnostics APIs today. +This is specified as a language-optional feature because its safety, +and therefore its value as an input for monitoring, depends on the +availability of type-checking in the source language. Passing +unordered labels (i.e., a list of bound keys and values) to +`Meter.Labels(...)` is considered the safer alternative. -Applications that forego the use of handles but do prefer to store and pass `LabelSet` objects may wonder what kind of performance to expect when exporting pre-computed metric data from their SDK. What should we expect of a high-performance metrics SDK in this regard? Since the SDK is involved in constructing the label set, we can presume it has performed the expensive computation of joining the labels into a lookup key or a serializable encoding, yielding a unique ID for the label set. +## Internal details -What remains, at `Record` time, to update the pre-aggregation state, is to lookup a map entry using the pair (`Instrument` ID, `LabelSet` ID), which is somewhat more than the cost of `GetHandle`. It is relatively fast compared with joining the labels into a lookup key, but there are complications. The lookup has to be synchronized, which could be a problem in some cases, and the map cannot grow without bound so there is a management "tax" to consider. This is what we might expect of a high-performance metrics SDK. +Metric SDKs that do not or cannot take advantage of the LabelSet optimizations are not especially burdened by having to support these APIs. It is trivial to supply an implementation of `LabelSet` that simply stores a list of labels. This may not be acceptable in performance-critical applications, but this is the common case in many metrics and diagnostics APIs today. ## Trade-offs and mitigations -Each programming language should select the names for `LabelSet` and `DefineLabels` that are most idiomatic and sensible. - -In languages where overloading is a standard convenience, the metrics API may elect to offer alternate forms that elide the call to `DefineLabels`, for example this: +In languages where overloading is a standard convenience, the metrics API may elect to offer alternate forms that elide the call to `Meter.Labels()`, for example: ``` instrument.GetHandle(meter, { Key: Value, ... }) @@ -113,17 +87,19 @@ instrument.GetHandle(meter, { Key: Value, ... }) as opposed to this: ``` -instrument.GetHandle(meter.DefineLabels({ Key: Value, ... })) +instrument.GetHandle(meter.Labels({ Key: Value, ... })) ``` -A key distinction between `LabelSet` and similar concepts in existing metrics libraries is that it is a _write-only_ structure, allowing the programmer to set diagnostic state while ensuring that diagnostic state does not become application-level state. +A key distinction between `LabelSet` and similar concepts in existing metrics libraries is that it is a _write-only_ structure. `LabelSet` allows the developer to input metric labels without being able to read them back. This avoids forcing the SDK to retain a reference to memory that is not required. ## Prior art and alternatives -There is not clear prior art like `LabelSet` as defined here. +Some existing metrics APIs support this concept. For example, see `Scope` in the [Tally metric API for Go](https://godoc.org/github.com/uber-go/tally#Scope). -A potential application for `DefineLabels` is to pre-compute the bytes of the statsd encoding for a label set once, to avoid repeatedly serializing this information. +Some libraries take `LabelSet` one step further. In the future, we may add to the the `LabelSet` API a method to extend the label set with additional labels. For example: -## Open questions - -Introducing `LabelSet` makes one more step for simply using the metrics API. Can convenience libraries, utility classes, and overloaded functions make the simple API use-cases acceptable while supporting re-use of `LabelSet` objects for optimization? +``` +serviceLabels := meter.Labels({ "k1": "v1", "k2": "v2" }) +// ... +requestLabels := serviceLabels.With({ "k3": "v3", "k4": "v4" }) +``` From 33288d4a2ca29a09fd388047efcfc2d0003f6d17 Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Mon, 28 Oct 2019 13:17:18 -0700 Subject: [PATCH 09/16] Update text/0049-metric-label-set.md Co-Authored-By: dyladan --- text/0049-metric-label-set.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0049-metric-label-set.md b/text/0049-metric-label-set.md index 755e0dbc4..00cc29f3a 100644 --- a/text/0049-metric-label-set.md +++ b/text/0049-metric-label-set.md @@ -6,7 +6,7 @@ Introduce a first-class `LabelSet` API type as a handle on a pre-defined set of ## Motivation -Labels are the term for key-value pairs used in the OpenTelemetry Metrics API. Treatment of labels in the metrics API is especially important for performance, across a variety of export strategies. +Labels are the term for key-value pairs used in the OpenTelemetry Metrics API. Treatment of labels in the Metrics API is especially important for performance across a variety of export strategies. Whether pushing or pulling metrics, whether aggregating metric events in the process or not, it is an expensive computation to translate a set of labels into either a serialized representation or a unique lookup key. Users of the metrics API stand to benefit by re-using label sets whenever possible, because manipulating label sets often dominates the cost of processing metric events. From f292c229cbd29fc8c782abbd148ff27d44e9fbd7 Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Mon, 28 Oct 2019 13:17:48 -0700 Subject: [PATCH 10/16] Update text/0049-metric-label-set.md Co-Authored-By: dyladan --- text/0049-metric-label-set.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0049-metric-label-set.md b/text/0049-metric-label-set.md index 00cc29f3a..3a6d198b6 100644 --- a/text/0049-metric-label-set.md +++ b/text/0049-metric-label-set.md @@ -10,7 +10,7 @@ Labels are the term for key-value pairs used in the OpenTelemetry Metrics API. Whether pushing or pulling metrics, whether aggregating metric events in the process or not, it is an expensive computation to translate a set of labels into either a serialized representation or a unique lookup key. Users of the metrics API stand to benefit by re-using label sets whenever possible, because manipulating label sets often dominates the cost of processing metric events. -The Metrics API supports three calling conventions: the Handle convention, the Direct convention, and the Batch convention. Each of these conventions stands to benefit when a `LabelSet` is re-used, as it allows the SDK to process the label set once instead of once per call. Whenever more than one handle will be created with the same labels, whenever more than one instrument will be called directly with the same labels, and whenever more than one batch of metric events will be recorded with the same labels, re-using a `LabelSet` makes it possible for the SDK to improve performance. +The Metrics API supports three calling conventions: the Handle convention, the Direct convention, and the Batch convention. Each of these conventions stands to benefit when a `LabelSet` is re-used, as it allows the SDK to process the label set once instead of once per call. Whenever more than one handle will be created with the same labels, more than one instrument will be called directly with the same labels, or more than one batch of metric events will be recorded with the same labels, re-using a `LabelSet` makes it possible for the SDK to improve performance. ## Explanation From 55ac75a95210c0ba50fa3e923df3c37904be327c Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Mon, 28 Oct 2019 13:17:58 -0700 Subject: [PATCH 11/16] Update text/0049-metric-label-set.md Co-Authored-By: dyladan --- text/0049-metric-label-set.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0049-metric-label-set.md b/text/0049-metric-label-set.md index 3a6d198b6..6da1958b2 100644 --- a/text/0049-metric-label-set.md +++ b/text/0049-metric-label-set.md @@ -14,7 +14,7 @@ The Metrics API supports three calling conventions: the Handle convention, the D ## Explanation -Metric instrument APIs which presently take labels in the form `{ Key: Value, ... }` will be updated to take an explicit `LabelSet`. The `Meter.Labels()` API method supports getting a `LabelSet` from the SDK, allowing the programmer to acquire a pre-define label set. Here are several examples of `LabelSet` re-use. Assume we have two instruments: +Metric instrument APIs which presently take labels in the form `{ Key: Value, ... }` will be updated to take an explicit `LabelSet`. The `Meter.Labels()` API method supports getting a `LabelSet` from the SDK, allowing the programmer to acquire a pre-defined label set. Here are several examples of `LabelSet` re-use. Assume we have two instruments: ```golang var ( From 38e33a30651bcbeccfd212eb3a5256fd2e560dc5 Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 28 Oct 2019 13:21:55 -0700 Subject: [PATCH 12/16] Accept suggested phrasing --- go.mod | 8 ++- go.sum | 115 ++++++++++++++++++++++++++++++++++ text/0049-metric-label-set.md | 2 +- 3 files changed, 123 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 1d6a9deaa..ffe35d0b9 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,10 @@ module github.com/open-telemetry/oteps go 1.12 -require github.com/client9/misspell v0.3.4 +require ( + github.com/census-instrumentation/opencensus-proto v0.2.1 // indirect + github.com/client9/misspell v0.3.4 + github.com/orijtech/prometheus-go-metrics-exporter v0.0.2 // indirect + github.com/prometheus/client_golang v1.2.1 // indirect + go.opencensus.io v0.22.1 // indirect +) diff --git a/go.sum b/go.sum index ee5948021..6963c6409 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,117 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= +github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/orijtech/prometheus-go-metrics-exporter v0.0.2 h1:XZGTMsJ8xM4VyrFGwHkdpZNnexxmAzFaq1//gUWqyKE= +github.com/orijtech/prometheus-go-metrics-exporter v0.0.2/go.mod h1:+Mu9w51Uc2RNKSUTA95d6Pvy8cxFiRX3ANRPlCcnGLA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= +github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +go.opencensus.io v0.22.1 h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/text/0049-metric-label-set.md b/text/0049-metric-label-set.md index 6da1958b2..7863bdb27 100644 --- a/text/0049-metric-label-set.md +++ b/text/0049-metric-label-set.md @@ -8,7 +8,7 @@ Introduce a first-class `LabelSet` API type as a handle on a pre-defined set of Labels are the term for key-value pairs used in the OpenTelemetry Metrics API. Treatment of labels in the Metrics API is especially important for performance across a variety of export strategies. -Whether pushing or pulling metrics, whether aggregating metric events in the process or not, it is an expensive computation to translate a set of labels into either a serialized representation or a unique lookup key. Users of the metrics API stand to benefit by re-using label sets whenever possible, because manipulating label sets often dominates the cost of processing metric events. +Label serialization is often one of the most expensive tasks when processing metric events. Creating a `LabelSet` once and re-using it many times can greatly reduce the overall cost of processing many events. The Metrics API supports three calling conventions: the Handle convention, the Direct convention, and the Batch convention. Each of these conventions stands to benefit when a `LabelSet` is re-used, as it allows the SDK to process the label set once instead of once per call. Whenever more than one handle will be created with the same labels, more than one instrument will be called directly with the same labels, or more than one batch of metric events will be recorded with the same labels, re-using a `LabelSet` makes it possible for the SDK to improve performance. From 31cef6ba59399a2eb3b8e60b4d5f2f0f1b5b75ca Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 28 Oct 2019 13:27:38 -0700 Subject: [PATCH 13/16] Revert mod changes eh? --- go.mod | 8 +--- go.sum | 115 --------------------------------------------------------- 2 files changed, 1 insertion(+), 122 deletions(-) diff --git a/go.mod b/go.mod index ffe35d0b9..1d6a9deaa 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,4 @@ module github.com/open-telemetry/oteps go 1.12 -require ( - github.com/census-instrumentation/opencensus-proto v0.2.1 // indirect - github.com/client9/misspell v0.3.4 - github.com/orijtech/prometheus-go-metrics-exporter v0.0.2 // indirect - github.com/prometheus/client_golang v1.2.1 // indirect - go.opencensus.io v0.22.1 // indirect -) +require github.com/client9/misspell v0.3.4 diff --git a/go.sum b/go.sum index 6963c6409..ee5948021 100644 --- a/go.sum +++ b/go.sum @@ -1,117 +1,2 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= -github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/orijtech/prometheus-go-metrics-exporter v0.0.2 h1:XZGTMsJ8xM4VyrFGwHkdpZNnexxmAzFaq1//gUWqyKE= -github.com/orijtech/prometheus-go-metrics-exporter v0.0.2/go.mod h1:+Mu9w51Uc2RNKSUTA95d6Pvy8cxFiRX3ANRPlCcnGLA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= -github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= -github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -go.opencensus.io v0.22.1 h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50= -go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 9eab901cbb525c967fca68a6a3e5e6492985da52 Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Wed, 6 Nov 2019 10:11:55 -0800 Subject: [PATCH 14/16] Update text/0049-metric-label-set.md Co-Authored-By: Tyler Yahn --- text/0049-metric-label-set.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0049-metric-label-set.md b/text/0049-metric-label-set.md index 7863bdb27..cfe0a7d1c 100644 --- a/text/0049-metric-label-set.md +++ b/text/0049-metric-label-set.md @@ -38,7 +38,7 @@ for ... { } ``` -Use a `LabelSet` to for multiple Direct calls: +Use a `LabelSet` to make multiple Direct calls: ```golang labels := meter.Labels({ "required_key1": value1, "required_key2": value2 }) From 0e520029d9e5d7de835546f572b45f1817113596 Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Mon, 11 Nov 2019 08:21:40 -0800 Subject: [PATCH 15/16] Update text/0049-metric-label-set.md Co-Authored-By: Isobel Redelmeier --- text/0049-metric-label-set.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0049-metric-label-set.md b/text/0049-metric-label-set.md index cfe0a7d1c..9bdf9232c 100644 --- a/text/0049-metric-label-set.md +++ b/text/0049-metric-label-set.md @@ -14,7 +14,7 @@ The Metrics API supports three calling conventions: the Handle convention, the D ## Explanation -Metric instrument APIs which presently take labels in the form `{ Key: Value, ... }` will be updated to take an explicit `LabelSet`. The `Meter.Labels()` API method supports getting a `LabelSet` from the SDK, allowing the programmer to acquire a pre-defined label set. Here are several examples of `LabelSet` re-use. Assume we have two instruments: +Metric instrument APIs which presently take labels in the form `{ Key: Value, ... }` will be updated to take an explicit `LabelSet`. The `Meter.Labels()` API method supports getting a `LabelSet` from the API, allowing the programmer to acquire a pre-defined label set. Here are several examples of `LabelSet` re-use. Assume we have two instruments: ```golang var ( From 1ccd9ed05c21401624dd49bb2bf8c2b8fd0fdb01 Mon Sep 17 00:00:00 2001 From: jmacd Date: Wed, 13 Nov 2019 15:20:35 -0800 Subject: [PATCH 16/16] Remove explicit meter argument where not necessary --- text/0049-metric-label-set.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0049-metric-label-set.md b/text/0049-metric-label-set.md index 7863bdb27..f73eade31 100644 --- a/text/0049-metric-label-set.md +++ b/text/0049-metric-label-set.md @@ -81,7 +81,7 @@ Metric SDKs that do not or cannot take advantage of the LabelSet optimizations a In languages where overloading is a standard convenience, the metrics API may elect to offer alternate forms that elide the call to `Meter.Labels()`, for example: ``` -instrument.GetHandle(meter, { Key: Value, ... }) +instrument.GetHandle({ Key: Value, ... }) ``` as opposed to this: