From 5c72c5d2a035c811fc60e6608320986ec85e4110 Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Wed, 8 May 2024 12:11:10 -0700 Subject: [PATCH] [chore] use mdatagen for exporterhelper metrics (#10094) Uses the new mdatagen capabilities to generate internal telemetry details for exporterhelper. --------- Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- cmd/mdatagen/main.go | 24 ++-- exporter/exporterhelper/doc.go | 2 + ...kage_test.go => generated_package_test.go} | 3 +- .../internal/metadata/generated_status.go | 17 +++ .../internal/metadata/generated_telemetry.go | 100 +++++++++++++++ .../metadata/generated_telemetry_test.go | 63 ++++++++++ exporter/exporterhelper/metadata.yaml | 81 +++++++++++++ exporter/exporterhelper/obsexporter.go | 114 +++--------------- 8 files changed, 296 insertions(+), 108 deletions(-) rename exporter/exporterhelper/{package_test.go => generated_package_test.go} (62%) create mode 100644 exporter/exporterhelper/internal/metadata/generated_status.go create mode 100644 exporter/exporterhelper/internal/metadata/generated_telemetry.go create mode 100644 exporter/exporterhelper/internal/metadata/generated_telemetry_test.go create mode 100644 exporter/exporterhelper/metadata.yaml diff --git a/cmd/mdatagen/main.go b/cmd/mdatagen/main.go index 8d7d1731faa..959275c0226 100644 --- a/cmd/mdatagen/main.go +++ b/cmd/mdatagen/main.go @@ -62,22 +62,22 @@ func run(ymlPath string) error { filepath.Join(codeDir, "generated_status.go"), md, "metadata"); err != nil { return err } - if err = generateFile(filepath.Join(tmplDir, "telemetry.go.tmpl"), - filepath.Join(codeDir, "generated_telemetry.go"), md, "metadata"); err != nil { - return err - } - if err = generateFile(filepath.Join(tmplDir, "telemetry_test.go.tmpl"), - filepath.Join(codeDir, "generated_telemetry_test.go"), md, "metadata"); err != nil { - return err - } if err = generateFile(filepath.Join(tmplDir, "component_test.go.tmpl"), filepath.Join(ymlDir, "generated_component_test.go"), md, packageName); err != nil { return err } - if err = generateFile(filepath.Join(tmplDir, "package_test.go.tmpl"), - filepath.Join(ymlDir, "generated_package_test.go"), md, packageName); err != nil { - return err - } + } + if err = generateFile(filepath.Join(tmplDir, "telemetry.go.tmpl"), + filepath.Join(codeDir, "generated_telemetry.go"), md, "metadata"); err != nil { + return err + } + if err = generateFile(filepath.Join(tmplDir, "telemetry_test.go.tmpl"), + filepath.Join(codeDir, "generated_telemetry_test.go"), md, "metadata"); err != nil { + return err + } + if err = generateFile(filepath.Join(tmplDir, "package_test.go.tmpl"), + filepath.Join(ymlDir, "generated_package_test.go"), md, packageName); err != nil { + return err } if _, err = os.Stat(filepath.Join(ymlDir, "README.md")); err == nil { diff --git a/exporter/exporterhelper/doc.go b/exporter/exporterhelper/doc.go index 4436c969347..ccecf255f08 100644 --- a/exporter/exporterhelper/doc.go +++ b/exporter/exporterhelper/doc.go @@ -1,5 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +//go:generate mdatagen metadata.yaml + // Package exporterhelper provides helper functions for exporters. package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" diff --git a/exporter/exporterhelper/package_test.go b/exporter/exporterhelper/generated_package_test.go similarity index 62% rename from exporter/exporterhelper/package_test.go rename to exporter/exporterhelper/generated_package_test.go index 6cf68017a7d..73b52415cde 100644 --- a/exporter/exporterhelper/package_test.go +++ b/exporter/exporterhelper/generated_package_test.go @@ -1,5 +1,4 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 +// Code generated by mdatagen. DO NOT EDIT. package exporterhelper diff --git a/exporter/exporterhelper/internal/metadata/generated_status.go b/exporter/exporterhelper/internal/metadata/generated_status.go new file mode 100644 index 00000000000..5c9e6c455ca --- /dev/null +++ b/exporter/exporterhelper/internal/metadata/generated_status.go @@ -0,0 +1,17 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "go.opentelemetry.io/collector/component" +) + +var ( + Type = component.MustNewType("exporterhelper") +) + +const ( + TracesStability = component.StabilityLevelBeta + MetricsStability = component.StabilityLevelBeta + LogsStability = component.StabilityLevelBeta +) diff --git a/exporter/exporterhelper/internal/metadata/generated_telemetry.go b/exporter/exporterhelper/internal/metadata/generated_telemetry.go new file mode 100644 index 00000000000..c74090acb7d --- /dev/null +++ b/exporter/exporterhelper/internal/metadata/generated_telemetry.go @@ -0,0 +1,100 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "errors" + + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + + "go.opentelemetry.io/collector/component" +) + +func Meter(settings component.TelemetrySettings) metric.Meter { + return settings.MeterProvider.Meter("go.opentelemetry.io/collector/exporter/exporterhelper") +} + +func Tracer(settings component.TelemetrySettings) trace.Tracer { + return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/exporter/exporterhelper") +} + +// TelemetryBuilder provides an interface for components to report telemetry +// as defined in metadata and user config. +type TelemetryBuilder struct { + ExporterEnqueueFailedLogRecords metric.Int64Counter + ExporterEnqueueFailedMetricPoints metric.Int64Counter + ExporterEnqueueFailedSpans metric.Int64Counter + ExporterSendFailedLogRecords metric.Int64Counter + ExporterSendFailedMetricPoints metric.Int64Counter + ExporterSendFailedSpans metric.Int64Counter + ExporterSentLogRecords metric.Int64Counter + ExporterSentMetricPoints metric.Int64Counter + ExporterSentSpans metric.Int64Counter +} + +// 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) + builder.ExporterEnqueueFailedLogRecords, err = meter.Int64Counter( + "exporter_enqueue_failed_log_records", + metric.WithDescription("Number of log records failed to be added to the sending queue."), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.ExporterEnqueueFailedMetricPoints, err = meter.Int64Counter( + "exporter_enqueue_failed_metric_points", + metric.WithDescription("Number of metric points failed to be added to the sending queue."), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.ExporterEnqueueFailedSpans, err = meter.Int64Counter( + "exporter_enqueue_failed_spans", + metric.WithDescription("Number of spans failed to be added to the sending queue."), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.ExporterSendFailedLogRecords, err = meter.Int64Counter( + "exporter_send_failed_log_records", + metric.WithDescription("Number of log records in failed attempts to send to destination."), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.ExporterSendFailedMetricPoints, err = meter.Int64Counter( + "exporter_send_failed_metric_points", + metric.WithDescription("Number of metric points in failed attempts to send to destination."), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.ExporterSendFailedSpans, err = meter.Int64Counter( + "exporter_send_failed_spans", + metric.WithDescription("Number of spans in failed attempts to send to destination."), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.ExporterSentLogRecords, err = meter.Int64Counter( + "exporter_sent_log_records", + metric.WithDescription("Number of log record successfully sent to destination."), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.ExporterSentMetricPoints, err = meter.Int64Counter( + "exporter_sent_metric_points", + metric.WithDescription("Number of metric points successfully sent to destination."), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + builder.ExporterSentSpans, err = meter.Int64Counter( + "exporter_sent_spans", + metric.WithDescription("Number of spans successfully sent to destination."), + metric.WithUnit("1"), + ) + errs = errors.Join(errs, err) + return &builder, errs +} diff --git a/exporter/exporterhelper/internal/metadata/generated_telemetry_test.go b/exporter/exporterhelper/internal/metadata/generated_telemetry_test.go new file mode 100644 index 00000000000..7fd14058b3a --- /dev/null +++ b/exporter/exporterhelper/internal/metadata/generated_telemetry_test.go @@ -0,0 +1,63 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "testing" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel/metric" + embeddedmetric "go.opentelemetry.io/otel/metric/embedded" + noopmetric "go.opentelemetry.io/otel/metric/noop" + "go.opentelemetry.io/otel/trace" + embeddedtrace "go.opentelemetry.io/otel/trace/embedded" + nooptrace "go.opentelemetry.io/otel/trace/noop" + + "go.opentelemetry.io/collector/component" +) + +type mockMeter struct { + noopmetric.Meter + name string +} +type mockMeterProvider struct { + embeddedmetric.MeterProvider +} + +func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { + return mockMeter{name: name} +} + +type mockTracer struct { + nooptrace.Tracer + name string +} + +type mockTracerProvider struct { + embeddedtrace.TracerProvider +} + +func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { + return mockTracer{name: name} +} + +func TestProviders(t *testing.T) { + set := component.TelemetrySettings{ + MeterProvider: mockMeterProvider{}, + TracerProvider: mockTracerProvider{}, + } + + meter := Meter(set) + if m, ok := meter.(mockMeter); ok { + require.Equal(t, "go.opentelemetry.io/collector/exporter/exporterhelper", m.name) + } else { + require.Fail(t, "returned Meter not mockMeter") + } + + tracer := Tracer(set) + if m, ok := tracer.(mockTracer); ok { + require.Equal(t, "go.opentelemetry.io/collector/exporter/exporterhelper", m.name) + } else { + require.Fail(t, "returned Meter not mockTracer") + } +} diff --git a/exporter/exporterhelper/metadata.yaml b/exporter/exporterhelper/metadata.yaml new file mode 100644 index 00000000000..1560331c1d9 --- /dev/null +++ b/exporter/exporterhelper/metadata.yaml @@ -0,0 +1,81 @@ +type: exporterhelper + +status: + class: pkg + stability: + beta: [traces, metrics, logs] + distributions: [core, contrib] + +telemetry: + metrics: + exporter_sent_spans: + enabled: true + description: Number of spans successfully sent to destination. + unit: 1 + sum: + value_type: int + monotonic: true + + exporter_send_failed_spans: + enabled: true + description: Number of spans in failed attempts to send to destination. + unit: 1 + sum: + value_type: int + monotonic: true + + exporter_enqueue_failed_spans: + enabled: true + description: Number of spans failed to be added to the sending queue. + unit: 1 + sum: + value_type: int + monotonic: true + + exporter_sent_metric_points: + enabled: true + description: Number of metric points successfully sent to destination. + unit: 1 + sum: + value_type: int + monotonic: true + + exporter_send_failed_metric_points: + enabled: true + description: Number of metric points in failed attempts to send to destination. + unit: 1 + sum: + value_type: int + monotonic: true + + exporter_enqueue_failed_metric_points: + enabled: true + description: Number of metric points failed to be added to the sending queue. + unit: 1 + sum: + value_type: int + monotonic: true + + exporter_sent_log_records: + enabled: true + description: Number of log record successfully sent to destination. + unit: 1 + sum: + value_type: int + monotonic: true + + exporter_send_failed_log_records: + enabled: true + description: Number of log records in failed attempts to send to destination. + unit: 1 + sum: + value_type: int + monotonic: true + + exporter_enqueue_failed_log_records: + enabled: true + description: Number of log records failed to be added to the sending queue. + unit: 1 + sum: + value_type: int + monotonic: true diff --git a/exporter/exporterhelper/obsexporter.go b/exporter/exporterhelper/obsexporter.go index ed490144242..e3a78c34b04 100644 --- a/exporter/exporterhelper/obsexporter.go +++ b/exporter/exporterhelper/obsexporter.go @@ -10,19 +10,15 @@ import ( "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" - "go.uber.org/multierr" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/exporter" + "go.opentelemetry.io/collector/exporter/exporterhelper/internal/metadata" "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" ) -const ( - exporterScope = obsmetrics.Scope + obsmetrics.SpanNameSep + obsmetrics.ExporterKey -) - // ObsReport is a helper to add observability to an exporter. type ObsReport struct { level configtelemetry.Level @@ -30,16 +26,8 @@ type ObsReport struct { tracer trace.Tracer logger *zap.Logger - otelAttrs []attribute.KeyValue - sentSpans metric.Int64Counter - failedToSendSpans metric.Int64Counter - failedToEnqueueSpans metric.Int64Counter - sentMetricPoints metric.Int64Counter - failedToSendMetricPoints metric.Int64Counter - failedToEnqueueMetricPoints metric.Int64Counter - sentLogRecords metric.Int64Counter - failedToSendLogRecords metric.Int64Counter - failedToEnqueueLogRecords metric.Int64Counter + otelAttrs []attribute.KeyValue + telemetryBuilder *metadata.TelemetryBuilder } // ObsReportSettings are settings for creating an ObsReport. @@ -54,7 +42,12 @@ func NewObsReport(cfg ObsReportSettings) (*ObsReport, error) { } func newExporter(cfg ObsReportSettings) (*ObsReport, error) { - exp := &ObsReport{ + telemetryBuilder, err := metadata.NewTelemetryBuilder(cfg.ExporterCreateSettings.TelemetrySettings) + if err != nil { + return nil, err + } + + return &ObsReport{ level: cfg.ExporterCreateSettings.TelemetrySettings.MetricsLevel, spanNamePrefix: obsmetrics.ExporterPrefix + cfg.ExporterID.String(), tracer: cfg.ExporterCreateSettings.TracerProvider.Tracer(cfg.ExporterID.String()), @@ -63,75 +56,8 @@ func newExporter(cfg ObsReportSettings) (*ObsReport, error) { otelAttrs: []attribute.KeyValue{ attribute.String(obsmetrics.ExporterKey, cfg.ExporterID.String()), }, - } - - if err := exp.createOtelMetrics(cfg); err != nil { - return nil, err - } - - return exp, nil -} - -func (or *ObsReport) createOtelMetrics(cfg ObsReportSettings) error { - meter := cfg.ExporterCreateSettings.MeterProvider.Meter(exporterScope) - - var errors, err error - - or.sentSpans, err = meter.Int64Counter( - obsmetrics.ExporterMetricPrefix+obsmetrics.SentSpansKey, - metric.WithDescription("Number of spans successfully sent to destination."), - metric.WithUnit("1")) - errors = multierr.Append(errors, err) - - or.failedToSendSpans, err = meter.Int64Counter( - obsmetrics.ExporterMetricPrefix+obsmetrics.FailedToSendSpansKey, - metric.WithDescription("Number of spans in failed attempts to send to destination."), - metric.WithUnit("1")) - errors = multierr.Append(errors, err) - - or.failedToEnqueueSpans, err = meter.Int64Counter( - obsmetrics.ExporterMetricPrefix+obsmetrics.FailedToEnqueueSpansKey, - metric.WithDescription("Number of spans failed to be added to the sending queue."), - metric.WithUnit("1")) - errors = multierr.Append(errors, err) - - or.sentMetricPoints, err = meter.Int64Counter( - obsmetrics.ExporterMetricPrefix+obsmetrics.SentMetricPointsKey, - metric.WithDescription("Number of metric points successfully sent to destination."), - metric.WithUnit("1")) - errors = multierr.Append(errors, err) - - or.failedToSendMetricPoints, err = meter.Int64Counter( - obsmetrics.ExporterMetricPrefix+obsmetrics.FailedToSendMetricPointsKey, - metric.WithDescription("Number of metric points in failed attempts to send to destination."), - metric.WithUnit("1")) - errors = multierr.Append(errors, err) - - or.failedToEnqueueMetricPoints, err = meter.Int64Counter( - obsmetrics.ExporterMetricPrefix+obsmetrics.FailedToEnqueueMetricPointsKey, - metric.WithDescription("Number of metric points failed to be added to the sending queue."), - metric.WithUnit("1")) - errors = multierr.Append(errors, err) - - or.sentLogRecords, err = meter.Int64Counter( - obsmetrics.ExporterMetricPrefix+obsmetrics.SentLogRecordsKey, - metric.WithDescription("Number of log record successfully sent to destination."), - metric.WithUnit("1")) - errors = multierr.Append(errors, err) - - or.failedToSendLogRecords, err = meter.Int64Counter( - obsmetrics.ExporterMetricPrefix+obsmetrics.FailedToSendLogRecordsKey, - metric.WithDescription("Number of log records in failed attempts to send to destination."), - metric.WithUnit("1")) - errors = multierr.Append(errors, err) - - or.failedToEnqueueLogRecords, err = meter.Int64Counter( - obsmetrics.ExporterMetricPrefix+obsmetrics.FailedToEnqueueLogRecordsKey, - metric.WithDescription("Number of log records failed to be added to the sending queue."), - metric.WithUnit("1")) - errors = multierr.Append(errors, err) - - return errors + telemetryBuilder: telemetryBuilder, + }, nil } // StartTracesOp is called at the start of an Export operation. @@ -192,14 +118,14 @@ func (or *ObsReport) recordMetrics(ctx context.Context, dataType component.DataT var sentMeasure, failedMeasure metric.Int64Counter switch dataType { case component.DataTypeTraces: - sentMeasure = or.sentSpans - failedMeasure = or.failedToSendSpans + sentMeasure = or.telemetryBuilder.ExporterSentSpans + failedMeasure = or.telemetryBuilder.ExporterSendFailedSpans case component.DataTypeMetrics: - sentMeasure = or.sentMetricPoints - failedMeasure = or.failedToSendMetricPoints + sentMeasure = or.telemetryBuilder.ExporterSentMetricPoints + failedMeasure = or.telemetryBuilder.ExporterSendFailedMetricPoints case component.DataTypeLogs: - sentMeasure = or.sentLogRecords - failedMeasure = or.failedToSendLogRecords + sentMeasure = or.telemetryBuilder.ExporterSentLogRecords + failedMeasure = or.telemetryBuilder.ExporterSendFailedLogRecords } sentMeasure.Add(ctx, sent, metric.WithAttributes(or.otelAttrs...)) @@ -232,11 +158,11 @@ func (or *ObsReport) recordEnqueueFailure(ctx context.Context, dataType componen var enqueueFailedMeasure metric.Int64Counter switch dataType { case component.DataTypeTraces: - enqueueFailedMeasure = or.failedToEnqueueSpans + enqueueFailedMeasure = or.telemetryBuilder.ExporterEnqueueFailedSpans case component.DataTypeMetrics: - enqueueFailedMeasure = or.failedToEnqueueMetricPoints + enqueueFailedMeasure = or.telemetryBuilder.ExporterEnqueueFailedMetricPoints case component.DataTypeLogs: - enqueueFailedMeasure = or.failedToEnqueueLogRecords + enqueueFailedMeasure = or.telemetryBuilder.ExporterEnqueueFailedLogRecords } enqueueFailedMeasure.Add(ctx, failed, metric.WithAttributes(or.otelAttrs...))