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

Metrics proposal for Go #2

Closed
wants to merge 8 commits into from
Closed

Metrics proposal for Go #2

wants to merge 8 commits into from

Conversation

jmacd
Copy link
Owner

@jmacd jmacd commented Jul 19, 2019

This implements a proof-of-concept for https://github.com/open-telemetry/rfcs/pull/4}

See examples/grpc/metrics.go for how the gRPC metrics translate from
https://github.com/census-instrumentation/opencensus-specs/blob/master/stats/gRPC.md

Invalid Type = iota
Gauge // Supports Set()
Cumulative // Supports Inc(): only positive values
Additive // Supports Add(): positive or negative

Choose a reason for hiding this comment

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

Additive and Gauge can be unified.

Copy link
Owner Author

Choose a reason for hiding this comment

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

They could be. I was hoping to make there be a 1:1 mapping between measured value and the interpretation. If we decide to keep a Stats API (i.e., reject RFC 0003), then I feel strongly that the Metrics API should be layered on top of the Stats API, so there should be a 1:1 mapping from a metrics update into a lower-level stats measurement. If we combine Additive and Gauge, for example, then I need to know the kind of operation in order to interpret a statistic. By allowing the Additive and Gauge to be separate metric types, I can layer Metrics on top of Stats, because each Measure has only one kind. I.e., there's not a mixture of Set() and Add() calls in the same stream of measurements.

Cumulative // Supports Inc()
Invalid Type = iota
Gauge // Supports Set()
Cumulative // Supports Inc(): only positive values

Choose a reason for hiding this comment

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

Cumulative also needs a set, because the classic example for this is CPU usage. If you want to report a CPU usage it is always going up (unless you do a CumulativeGauge that remembers the previous value and Inc delta).

SUM
COUNT
MIN
MAX

Choose a reason for hiding this comment

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

Why min/max? Where is this used?

MIN
MAX
LAST_VALUE
DISTRIBUTION

Choose a reason for hiding this comment

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

For a distribution if a histogram is used user requires to also configure the buckets. If a summary is used user requires to configure the percentiles. So I cannot see how this is used.

return "unknown"
// WithAggregation applies a user-recommended aggregation to this
// metric, useful particularly for Measure type metrics.
func WithAggregation(aggr aggregation.Operator) Option {

Choose a reason for hiding this comment

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

This is not compatible with OpenCensus stats which is a primary requirement for this, because we need to not allow the instrumentation plugin to define the aggregation.

Copy link
Owner Author

Choose a reason for hiding this comment

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

This is not a definition. This is a recommendation. The SDK is not bound to follow this advice. If this value is not set, the default aggregation for MeasureMetrics is None. I like this because the application programmer can suggest None as a good aggregation for measure metrics, but could also suggest Distribution.

@@ -25,10 +25,16 @@ var (
)

func SetCurrentSpan(ctx context.Context, span Span) context.Context {
if ctx == nil {

Choose a reason for hiding this comment

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

why these changes?

Copy link
Owner Author

Choose a reason for hiding this comment

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

In my exporter, I want to know the current span in order to annotate the span data with accumulated metrics, grouped by span_id. I want this to happen for all callers, without the programmer having to do anything. So this check avoids a crash when you ask for the current span and there's no context.

)

type Meter interface {
// TODO more Metric types
GetFloat64Gauge(ctx context.Context, gauge *Float64GaugeHandle, labels ...core.KeyValue) Float64Gauge
GetFloat64Gauge(context.Context, *Float64GaugeHandle, ...core.KeyValue) Float64Gauge

Choose a reason for hiding this comment

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

Why a context in this case?

Copy link
Owner Author

Choose a reason for hiding this comment

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

This allows context tags to be recorded, in case the SDK wants to do that. In addition, it allows us to associate the current active span with the measurement, which means we can reflect this metric update in the recorded span data, for example.

type Float64Measure interface {
Record(ctx context.Context, value float64, labels ...core.KeyValue)
}

type Handle struct {

Choose a reason for hiding this comment

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

What is a Handle? why does this exist?

Copy link
Owner Author

Choose a reason for hiding this comment

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

A handle is a common base type for any of the metrics. In this proposal, the only API difference between the metric types is the verb they use, the interpretation is left to the SDK. So the Handle is a thing that describes the metric independently of its verb or metric type. The properties of a metric are: variable (name), type (gauge, additive, cumulative, or measure), keys (recommended), and aggregation (recommended).

Invalid Type = iota
Gauge // Supports Set()
Cumulative // Supports Inc(): only positive values
Additive // Supports Add(): positive or negative
Copy link
Owner Author

Choose a reason for hiding this comment

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

They could be. I was hoping to make there be a 1:1 mapping between measured value and the interpretation. If we decide to keep a Stats API (i.e., reject RFC 0003), then I feel strongly that the Metrics API should be layered on top of the Stats API, so there should be a 1:1 mapping from a metrics update into a lower-level stats measurement. If we combine Additive and Gauge, for example, then I need to know the kind of operation in order to interpret a statistic. By allowing the Additive and Gauge to be separate metric types, I can layer Metrics on top of Stats, because each Measure has only one kind. I.e., there's not a mixture of Set() and Add() calls in the same stream of measurements.

)

type Meter interface {
// TODO more Metric types
GetFloat64Gauge(ctx context.Context, gauge *Float64GaugeHandle, labels ...core.KeyValue) Float64Gauge
GetFloat64Gauge(context.Context, *Float64GaugeHandle, ...core.KeyValue) Float64Gauge
Copy link
Owner Author

Choose a reason for hiding this comment

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

This allows context tags to be recorded, in case the SDK wants to do that. In addition, it allows us to associate the current active span with the measurement, which means we can reflect this metric update in the recorded span data, for example.

type Float64Measure interface {
Record(ctx context.Context, value float64, labels ...core.KeyValue)
}

type Handle struct {
Copy link
Owner Author

Choose a reason for hiding this comment

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

A handle is a common base type for any of the metrics. In this proposal, the only API difference between the metric types is the verb they use, the interpretation is left to the SDK. So the Handle is a thing that describes the metric independently of its verb or metric type. The properties of a metric are: variable (name), type (gauge, additive, cumulative, or measure), keys (recommended), and aggregation (recommended).

return "unknown"
// WithAggregation applies a user-recommended aggregation to this
// metric, useful particularly for Measure type metrics.
func WithAggregation(aggr aggregation.Operator) Option {
Copy link
Owner Author

Choose a reason for hiding this comment

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

This is not a definition. This is a recommendation. The SDK is not bound to follow this advice. If this value is not set, the default aggregation for MeasureMetrics is None. I like this because the application programmer can suggest None as a good aggregation for measure metrics, but could also suggest Distribution.

@@ -25,10 +25,16 @@ var (
)

func SetCurrentSpan(ctx context.Context, span Span) context.Context {
if ctx == nil {
Copy link
Owner Author

Choose a reason for hiding this comment

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

In my exporter, I want to know the current span in order to annotate the span data with accumulated metrics, grouped by span_id. I want this to happen for all callers, without the programmer having to do anything. So this check avoids a crash when you ask for the current span and there's no context.

read.Type = event.Type

if event.Context != nil {
span := trace.CurrentSpan(event.Context)
Copy link
Owner Author

Choose a reason for hiding this comment

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

Here, this is where the metric update is associated with a current span. This would be a nil context if for some reason the programmer passed a nil to the metrics APIs.

@jmacd jmacd closed this Aug 16, 2019
@jmacd jmacd deleted the jmacd/metrics_proposal branch October 29, 2019 21:09
jmacd pushed a commit that referenced this pull request Mar 13, 2020
* Add MinMaxSumCount stress test

* Reimplement MinMaxSumCount using StateLocker

* Address PR comments

* Round #2 of PR comments

Co-authored-by: Rahul Patel <rahulpa@google.com>
jmacd pushed a commit that referenced this pull request Jun 18, 2021
* Add ExportTimeout option

* Adjust tests

* Update CHANGELOG

* Beef up the exporter timeout test

* Beef up exporter test - attempt #2

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants