-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
stats/opentelemetry: Add OpenTelemetry instrumentation component #7066
Changes from 1 commit
d60d637
78fef76
796d697
9597843
179082f
4196745
e078766
84eae8c
196e201
4a14a16
1f6a60c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,21 @@ import ( | |
"go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" | ||
) | ||
|
||
func ExampleNewMetrics() { | ||
// Will disable metrics, set with no metrics specified. | ||
NewMetrics() | ||
// Will enable these two metrics. | ||
NewMetrics(ClientAttemptDuration, ServerCallDuration) | ||
// Use DefaultClientMetrics to enable default client metrics. Equivalent to | ||
// unset, which will pick up defaults. | ||
} | ||
|
||
func ExampleMetric_Remove() { | ||
// Use DefaultClientMetrics without ClientAttemptDuration and | ||
// ClientCallDurationName. | ||
DefaultClientMetrics.Remove(ClientAttemptDuration, ClientCallDurationName) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think these would be more useful on the DialOption / ServerOption, or Options, and should show how to build the DialOption. Just one line of code isn't super useful. E.g. something like: func ExampleDialOption_ExcludeMetrics() {
// To exclude specific metrics, initialize Options as follows:
otelOpts := opentelemetry.Option{
MetricsOptions: MetricsOptions{
Metrics: DefaultClientMetrics.Remove(opentelemetry.ClientAttemptDuration,
},
}
dialOption := opentelemetry.DialOption(otelOpts)
cc, _ := grpc.Dial("<target string>", dialOption)
// Handle err.
defer cc.Close()
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't the examples technically have to be linked to a single exported function from the package? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, there are many ways of attaching examples at different places in the package. Check the testing documentation for more details: https://pkg.go.dev/testing#hdr-Examples There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added numerous examples. |
||
|
||
var defaultTestTimeout = 5 * time.Second | ||
|
||
type s struct { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,20 +37,20 @@ var canonicalString = internal.CanonicalString.(func(codes.Code) string) | |
|
||
var joinDialOptions = internal.JoinDialOptions.(func(...grpc.DialOption) grpc.DialOption) | ||
|
||
// MetricName is a name of a metric. | ||
type MetricName string | ||
// Metric is an identifier for a metric provided by this package. | ||
type Metric string | ||
|
||
// Metrics is a set of metrics to record. Once created, Metrics is immutable, | ||
// however Add and Remove can make copies with specific metrics added or | ||
// removed, respectively. | ||
type Metrics struct { | ||
// metrics are the set of metrics to initialize. | ||
metrics map[MetricName]bool | ||
metrics map[Metric]bool | ||
} | ||
|
||
// NewMetrics returns a Metrics with the metrics provided specified. | ||
func NewMetrics(metrics ...MetricName) *Metrics { | ||
newMetrics := make(map[MetricName]bool) | ||
// NewMetrics returns a Metrics containing the Metric's provided. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another choice is to say "containing metrics." - directly referencing the parameter's name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, switched. |
||
func NewMetrics(metrics ...Metric) *Metrics { | ||
newMetrics := make(map[Metric]bool) | ||
for _, metric := range metrics { | ||
newMetrics[metric] = true | ||
} | ||
|
@@ -61,8 +61,8 @@ func NewMetrics(metrics ...MetricName) *Metrics { | |
|
||
// Add adds the metrics to the metrics set and returns a new copy with the | ||
// additional metrics. | ||
func (m *Metrics) Add(metrics ...MetricName) *Metrics { | ||
newMetrics := make(map[MetricName]bool) | ||
func (m *Metrics) Add(metrics ...Metric) *Metrics { | ||
newMetrics := make(map[Metric]bool) | ||
for metric := range m.metrics { | ||
newMetrics[metric] = true | ||
} | ||
|
@@ -77,8 +77,8 @@ func (m *Metrics) Add(metrics ...MetricName) *Metrics { | |
|
||
// Remove removes the metrics from the metrics set and returns a new copy with | ||
// the metrics removed. | ||
func (m *Metrics) Remove(metrics ...MetricName) *Metrics { | ||
newMetrics := make(map[MetricName]bool) | ||
func (m *Metrics) Remove(metrics ...Metric) *Metrics { | ||
newMetrics := make(map[Metric]bool) | ||
for metric := range m.metrics { | ||
newMetrics[metric] = true | ||
} | ||
|
@@ -99,17 +99,19 @@ type Options struct { | |
|
||
// MetricsOptions are the metrics options for OpenTelemetry instrumentation. | ||
type MetricsOptions struct { | ||
// MeterProvider is the MeterProvider instance that will be used for access | ||
// to Named Meter instances to instrument an application. To enable metrics | ||
// collection, set a meter provider. If unset, no metrics will be recorded. | ||
// Any implementation knobs (i.e. views, bounds) set in the passed in object | ||
// take precedence over the API calls from the interface in this component | ||
// (i.e. it will create default views for unset views). | ||
// MeterProvider is the MeterProvider instance that will be used to create | ||
// instruments. To enable metrics collection, set a meter provider. If | ||
// unset, no metrics will be recorded. Any implementation knobs (i.e. views, | ||
// bounds) set in the MeterProvider take precedence over the API calls from | ||
// this interface. (i.e. it will create default views for unset views). | ||
MeterProvider metric.MeterProvider | ||
dfawley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Metrics are the metrics to instrument. Will turn on the corresponding | ||
// metric supported by the client and server instrumentation components if | ||
// applicable. | ||
|
||
// Metrics are the metrics to instrument. Will create instrument and record telemetry | ||
// for corresponding metric supported by the client and server | ||
// instrumentation components if applicable. If not set, the default metrics | ||
// will be recorded. | ||
Metrics *Metrics | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if a user sets an unsupported metric? (E.g. if they specify server metrics when they initialize the client)? Ideally There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I remembering discussing this with Yash, and I think the decision was just to leave this as a no-op in this scenario (I.e. just ignore the metrics). Right @yashykt? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, no-op is what i'm thinking. Consider the case of experimental metrics. There might be a case where we decide to remove experimental metrics and we don't want removal of metrics to break user code (if they had enabled the experimental metrics). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah sounds good to me. Let me know what you think Doug. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OTOH, consider the case where they're initializing a If we remove an experimental metric, maybe the user wants an init-time error so they know it was removed? And in our case, that's what will happen anyway, unless we leave the const behind for the removed metric. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we're calling the metrics in A66 stable, which is why we have default + exported consts. I think the goal was the defaults now are stable (i.e. ones defined in A66). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would a user set Server Metrics for Dial Option :)? I guess the tradeoff is the scenario you mentioned earlier vs. being defensive now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By accident. Spot the bug: opentelemetry.DialOption(opentelemetry.Options{
LoggingOptions: ...,
MetricsOptions: opentelemetry.MetricsOptions{
MeterProvider: blahblahblah,
Metrics: opentelemetry.DefaultServerMetrics,
TargetAttributeFilter: func(t target) bool {
return allowedTargets[t]
},
},
TracingOptions: ...,
}) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's separate the metrics field to client and server metrics then for type safety? not entirely type safe but at least the user knows whether setting for client or sever and not tied to DialOption/ServerOption? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussed offline; decided to make it DefaultMetrics that contains both client and server, which will be ignored on the other side to the initialized option. |
||
|
||
// TargetAttributeFilter is a callback that takes the target string of the | ||
// channel and returns a bool representing whether to use target as a label | ||
// value or use the string "other". If unset, will use the target string as | ||
|
@@ -245,7 +247,7 @@ type serverMetrics struct { | |
callDuration metric.Float64Histogram | ||
} | ||
|
||
func createInt64Counter(setOfMetrics map[MetricName]bool, metricName MetricName, meter metric.Meter, options ...metric.Int64CounterOption) metric.Int64Counter { | ||
func createInt64Counter(setOfMetrics map[Metric]bool, metricName Metric, meter metric.Meter, options ...metric.Int64CounterOption) metric.Int64Counter { | ||
if _, ok := setOfMetrics[metricName]; !ok { | ||
return nil | ||
} | ||
|
@@ -257,7 +259,7 @@ func createInt64Counter(setOfMetrics map[MetricName]bool, metricName MetricName, | |
return ret | ||
} | ||
|
||
func createInt64Histogram(setOfMetrics map[MetricName]bool, metricName MetricName, meter metric.Meter, options ...metric.Int64HistogramOption) metric.Int64Histogram { | ||
func createInt64Histogram(setOfMetrics map[Metric]bool, metricName Metric, meter metric.Meter, options ...metric.Int64HistogramOption) metric.Int64Histogram { | ||
if _, ok := setOfMetrics[metricName]; !ok { | ||
return nil | ||
} | ||
|
@@ -269,7 +271,7 @@ func createInt64Histogram(setOfMetrics map[MetricName]bool, metricName MetricNam | |
return ret | ||
} | ||
|
||
func createFloat64Histogram(setOfMetrics map[MetricName]bool, metricName MetricName, meter metric.Meter, options ...metric.Float64HistogramOption) metric.Float64Histogram { | ||
func createFloat64Histogram(setOfMetrics map[Metric]bool, metricName Metric, meter metric.Meter, options ...metric.Float64HistogramOption) metric.Float64Histogram { | ||
if _, ok := setOfMetrics[metricName]; !ok { | ||
return nil | ||
} | ||
|
@@ -284,14 +286,11 @@ func createFloat64Histogram(setOfMetrics map[MetricName]bool, metricName MetricN | |
// Users of this component should use these bucket boundaries as part of their | ||
// SDK MeterProvider passed in. This component sends this as "advice" to the | ||
// API, which works, however this stability is not guaranteed, so for safety the | ||
// SDK Meter Provider should set these bounds. | ||
// SDK Meter Provider provided should set these bounds for corresponding | ||
// metrics. | ||
var ( | ||
// DefaultLatencyBounds are the default bounds for latency metrics. Users of | ||
// this component should set these bucket boundaries as part of their SDK | ||
// MeterProvider passed in for desired latency metrics. | ||
// DefaultLatencyBounds are the default bounds for latency metrics. | ||
DefaultLatencyBounds = []float64{0, 0.00001, 0.00005, 0.0001, 0.0003, 0.0006, 0.0008, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.008, 0.01, 0.013, 0.016, 0.02, 0.025, 0.03, 0.04, 0.05, 0.065, 0.08, 0.1, 0.13, 0.16, 0.2, 0.25, 0.3, 0.4, 0.5, 0.65, 0.8, 1, 2, 5, 10, 20, 50, 100} // provide "advice" through API, SDK should set this too | ||
dfawley marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would also be nice to show users how to do this, too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added as part of example. Verified it worked by playing around with example configuration wrt bounds and seeing the result. |
||
// DefaultSizeBounds are the default bounds for metrics which record size. | ||
// Users of this component should set these bucket boundaries as part of | ||
// their SDK MeterProvider passed in for desired size metrics. | ||
DefaultSizeBounds = []float64{0, 1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296} | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is still named
Name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Argh, whoops. Removed.