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

[mdatagen] use mdatagen to produce component internal telemetry #10054

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .chloggen/codeboten_mdatagen-for-batch-metrics.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
component: mdatagen

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: add ability to use metadata.yaml to automatically generate instruments for components

# One or more tracking issues or pull requests related to the change
issues: [10054]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext: |
The `telemetry` section in metadata.yaml is used to generate
instruments for components to measure telemetry about themselves.

# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: []

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions cmd/mdatagen/internal/samplereceiver/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,19 @@ metrics:
monotonic: true
aggregation_temporality: cumulative
attributes: [ string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr ]

telemetry:
metrics:
batch_size_trigger_send:
enabled: true
description: Number of times the batch was sent due to a size trigger
unit: 1
sum:
value_type: int
monotonic: true
request_duration:
enabled: true
description: Duration of request
unit: s
histogram:
value_type: double
11 changes: 11 additions & 0 deletions cmd/mdatagen/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@
Sum *sum `mapstructure:"sum,omitempty"`
// Gauge stores metadata for gauge metric type
Gauge *gauge `mapstructure:"gauge,omitempty"`
// Gauge stores metadata for gauge metric type
Histogram *histogram `mapstructure:"histogram,omitempty"`

// Attributes is the list of attributes that the metric emits.
Attributes []attributeName `mapstructure:"attributes"`
Expand All @@ -135,6 +137,9 @@
if m.Gauge != nil {
return m.Gauge
}
if m.Histogram != nil {
return m.Histogram

Check warning on line 141 in cmd/mdatagen/loader.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/loader.go#L140-L141

Added lines #L140 - L141 were not covered by tests
}
return nil
}

Expand Down Expand Up @@ -221,13 +226,19 @@
ExpectConsumerError bool `mapstructure:"expect_consumer_error"`
}

type telemetry struct {
Metrics map[metricName]metric `mapstructure:"metrics"`
}

type metadata struct {
// Type of the component.
Type string `mapstructure:"type"`
// Type of the parent component (applicable to subcomponents).
Parent string `mapstructure:"parent"`
// Status information for the component.
Status *Status `mapstructure:"status"`
// Telemetry information for the component.
Telemetry telemetry `mapstructure:"telemetry"`
// SemConvVersion is a version number of OpenTelemetry semantic conventions applied to the scraped metrics.
SemConvVersion string `mapstructure:"sem_conv_version"`
// ResourceAttributes that can be emitted by the component.
Expand Down
26 changes: 21 additions & 5 deletions cmd/mdatagen/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,27 @@ func TestLoadMetadata(t *testing.T) {
Attributes: []attributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr"},
},
},
Telemetry: telemetry{
Metrics: map[metricName]metric{
"batch_size_trigger_send": {
Enabled: true,
Description: "Number of times the batch was sent due to a size trigger",
Unit: strPtr("1"),
Sum: &sum{
MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeInt},
Mono: Mono{Monotonic: true},
},
},
"request_duration": {
Enabled: true,
Description: "Duration of request",
Unit: strPtr("s"),
Histogram: &histogram{
MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeDouble},
},
},
},
},
ScopeName: "go.opentelemetry.io/collector/internal/receiver/samplereceiver",
ShortFolderName: "sample",
},
Expand Down Expand Up @@ -264,11 +285,6 @@ func TestLoadMetadata(t *testing.T) {
name: "testdata/unknown_value_type.yaml",
wantErr: "1 error(s) decoding:\n\n* error decoding 'metrics[system.cpu.time]': 1 error(s) decoding:\n\n* error decoding 'sum': 1 error(s) decoding:\n\n* error decoding 'value_type': invalid value_type: \"unknown\"",
},
{
name: "testdata/no_aggregation.yaml",
want: metadata{},
wantErr: "1 error(s) decoding:\n\n* error decoding 'metrics[default.metric]': 1 error(s) decoding:\n\n* error decoding 'sum': missing required field: `aggregation_temporality`",
},
{
name: "testdata/invalid_aggregation.yaml",
want: metadata{},
Expand Down
33 changes: 33 additions & 0 deletions cmd/mdatagen/metadata-schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,36 @@ tests:
ignore:
top: [string] # Optional: array of strings representing functions that should be ignore via IgnoreTopFunction
any: [string] # Optional: array of strings representing functions that should be ignore via IgnoreAnyFunction


# Optional: map of metric names with the key being the metric name and value
# being described below.
telemetry:
<metric.name>:
# Required: whether the metric is collected by default.
enabled: bool
# Required: metric description.
description:
# Optional: extended documentation of the metric.
extended_documentation:
# Optional: warnings that will be shown to user under specified conditions.
warnings:
# A warning that will be displayed if the metric is enabled in user config.
# Should be used for deprecated default metrics that will be removed soon.
if_enabled:
# A warning that will be displayed if `enabled` field is not set explicitly in user config.
# Should be used for metrics that will be turned from default to optional or vice versa.
if_enabled_not_set:
# A warning that will be displayed if the metrics is configured by user in any way.
# Should be used for deprecated optional metrics that will be removed soon.
if_configured:
# Required: metric unit as defined by https://ucum.org/ucum.html.
unit:
# Required: metric type with its settings.
<sum|gauge|histogram>:
# Required for sum and gauge metrics: type of number data point values.
value_type: <int|double>
# Required for sum metric: whether the metric is monotonic (no negative delta values).
monotonic: bool
# Optional: array of attributes that were defined in the attributes section that are emitted by this metric.
attributes: [string]
54 changes: 51 additions & 3 deletions cmd/mdatagen/metricdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
"errors"
"fmt"

"golang.org/x/text/cases"
"golang.org/x/text/language"

"go.opentelemetry.io/collector/confmap"
"go.opentelemetry.io/collector/pdata/pmetric"
)

var (
_ MetricData = &gauge{}
_ MetricData = &sum{}
_ MetricData = &histogram{}
)

// MetricData is generic interface for all metric datatypes.
Expand All @@ -22,6 +26,7 @@
HasMonotonic() bool
HasAggregated() bool
HasMetricInputType() bool
Instrument() string
}

// AggregationTemporality defines a metric aggregation type.
Expand Down Expand Up @@ -140,6 +145,10 @@
return false
}

func (d gauge) Instrument() string {
return ""

Check warning on line 149 in cmd/mdatagen/metricdata.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/metricdata.go#L148-L149

Added lines #L148 - L149 were not covered by tests
}

type sum struct {
AggregationTemporality `mapstructure:"aggregation_temporality"`
Mono `mapstructure:",squash"`
Expand All @@ -149,9 +158,6 @@

// Unmarshal is a custom unmarshaler for sum. Needed mostly to avoid MetricValueType.Unmarshal inheritance.
func (d *sum) Unmarshal(parser *confmap.Conf) error {
if !parser.IsSet("aggregation_temporality") {
return errors.New("missing required field: `aggregation_temporality`")
}
if err := d.MetricValueType.Unmarshal(parser); err != nil {
return err
}
Expand Down Expand Up @@ -180,3 +186,45 @@
func (d sum) HasAggregated() bool {
return true
}

func (d sum) Instrument() string {
instrumentName := cases.Title(language.English).String(d.MetricValueType.BasicType())

Check warning on line 191 in cmd/mdatagen/metricdata.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/metricdata.go#L190-L191

Added lines #L190 - L191 were not covered by tests

if !d.Monotonic {
instrumentName += "UpDown"

Check warning on line 194 in cmd/mdatagen/metricdata.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/metricdata.go#L193-L194

Added lines #L193 - L194 were not covered by tests
}
instrumentName += "Counter"
return instrumentName

Check warning on line 197 in cmd/mdatagen/metricdata.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/metricdata.go#L196-L197

Added lines #L196 - L197 were not covered by tests
}

type histogram struct {
AggregationTemporality `mapstructure:"aggregation_temporality"`
Mono `mapstructure:",squash"`
MetricValueType `mapstructure:"value_type"`
MetricInputType `mapstructure:",squash"`
}

func (d histogram) Type() string {
return "Histogram"

Check warning on line 208 in cmd/mdatagen/metricdata.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/metricdata.go#L207-L208

Added lines #L207 - L208 were not covered by tests
}

func (d histogram) HasMonotonic() bool {
return true

Check warning on line 212 in cmd/mdatagen/metricdata.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/metricdata.go#L211-L212

Added lines #L211 - L212 were not covered by tests
}

func (d histogram) HasAggregated() bool {
return true

Check warning on line 216 in cmd/mdatagen/metricdata.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/metricdata.go#L215-L216

Added lines #L215 - L216 were not covered by tests
}

func (d histogram) Instrument() string {
instrumentName := cases.Title(language.English).String(d.MetricValueType.BasicType())
return instrumentName + d.Type()

Check warning on line 221 in cmd/mdatagen/metricdata.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/metricdata.go#L219-L221

Added lines #L219 - L221 were not covered by tests
}

// Unmarshal is a custom unmarshaler for histogram. Needed mostly to avoid MetricValueType.Unmarshal inheritance.
func (d *histogram) Unmarshal(parser *confmap.Conf) error {
if err := d.MetricValueType.Unmarshal(parser); err != nil {
return err

Check warning on line 227 in cmd/mdatagen/metricdata.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/metricdata.go#L227

Added line #L227 was not covered by tests
}
return parser.Unmarshal(d, confmap.WithIgnoreUnused())
}
35 changes: 35 additions & 0 deletions cmd/mdatagen/templates/telemetry.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
package {{ .Package }}

import (
{{- if .Telemetry.Metrics }}
"errors"
{{- end }}

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/trace"
Expand All @@ -15,3 +19,34 @@ func Meter(settings component.TelemetrySettings) metric.Meter {
func Tracer(settings component.TelemetrySettings) trace.Tracer {
return settings.TracerProvider.Tracer("{{ .ScopeName }}")
}
{{- if .Telemetry.Metrics }}

// TelemetryBuilder provides an interface for components to report telemetry
// as defined in metadata and user config.
type TelemetryBuilder struct {
{{- range $name, $metric := .Telemetry.Metrics }}
{{ $name.Render }} metric.{{ $metric.Data.Instrument }}
{{- end }}
}

// telemetryBuilderOption applies changes to default builder.
type telemetryBuilderOption func(*TelemetryBuilder)

// NewTelemetryBuilder provides a struct with methods to update all internal telemetry
// for a component
func NewTelemetryBuilder(settings component.TelemetrySettings, options ...telemetryBuilderOption) (*TelemetryBuilder, error) {
builder := TelemetryBuilder{}
var err, errs error
meter := Meter(settings)
{{- range $name, $metric := .Telemetry.Metrics }}
builder.{{ $name.Render }}, err = meter.{{ $metric.Data.Instrument }}(
"{{ $name }}",
metric.WithDescription("{{ $metric.Description }}"),
metric.WithUnit("{{ $metric.Unit }}"),
)
errs = errors.Join(errs, err)
{{- end }}
return &builder, errs
}

{{- end }}
Loading
Loading