From e4812ba4ca01eee12005527edbf733e28b98ffaa Mon Sep 17 00:00:00 2001
From: ShyunnY <1147212064@qq.com>
Date: Sat, 6 Apr 2024 17:25:41 +0800
Subject: [PATCH] feat: supports custom metrics sink export period and timeout
Signed-off-by: ShyunnY <1147212064@qq.com>
---
api/v1alpha1/envoygateway_metrics_types.go | 18 +++++
api/v1alpha1/zz_generated.deepcopy.go | 10 +++
internal/metrics/register.go | 65 ++++++++++++++++---
site/content/en/latest/api/extension_types.md | 16 +++++
4 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/api/v1alpha1/envoygateway_metrics_types.go b/api/v1alpha1/envoygateway_metrics_types.go
index 0b827a06afa..4847f4e7bff 100644
--- a/api/v1alpha1/envoygateway_metrics_types.go
+++ b/api/v1alpha1/envoygateway_metrics_types.go
@@ -24,8 +24,26 @@ type EnvoyGatewayMetricSink struct {
// OpenTelemetry defines the configuration for OpenTelemetry sink.
// It's required if the sink type is OpenTelemetry.
OpenTelemetry *EnvoyGatewayOpenTelemetrySink `json:"openTelemetry,omitempty"`
+ // ExporterInterval configures the intervening time between exports for a
+ // Sink. This option overrides any value set for the
+ // OTEL_METRIC_EXPORT_INTERVAL environment variable.
+ // If ExporterInterval is less than or equal to zero, 60 seconds
+ // is used as the default.
+ ExporterInterval *ExporterDuration `json:"exporterInterval"`
+ // ExporterTimeout configures the time a Sink waits for an export to
+ // complete before canceling it. This option overrides any value set for the
+ // OTEL_METRIC_EXPORT_TIMEOUT environment variable.
+ // If ExporterTimeout is less than or equal to zero, 30 seconds
+ // is used as the default.
+ ExporterTimeout *ExporterDuration `json:"exporterTimeout"`
}
+// ExporterDuration is used to represent the duration of the exporter.
+// It is used to represent duration as a string and parsed by time.ParseDuration function.
+// This type uses the time format in Go.
+// example: "1h30m" means a duration of 1 hour and 30 minutes, "10s" means a duration of 10 seconds.
+type ExporterDuration string
+
type EnvoyGatewayOpenTelemetrySink struct {
// Host define the sink service hostname.
Host string `json:"host"`
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index e82cda7787f..e27397323aa 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -994,6 +994,16 @@ func (in *EnvoyGatewayMetricSink) DeepCopyInto(out *EnvoyGatewayMetricSink) {
*out = new(EnvoyGatewayOpenTelemetrySink)
**out = **in
}
+ if in.ExporterInterval != nil {
+ in, out := &in.ExporterInterval, &out.ExporterInterval
+ *out = new(ExporterDuration)
+ **out = **in
+ }
+ if in.ExporterTimeout != nil {
+ in, out := &in.ExporterTimeout, &out.ExporterTimeout
+ *out = new(ExporterDuration)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyGatewayMetricSink.
diff --git a/internal/metrics/register.go b/internal/metrics/register.go
index 9c8abdf479d..82234925d41 100644
--- a/internal/metrics/register.go
+++ b/internal/metrics/register.go
@@ -32,7 +32,11 @@ const (
// Init initializes and registers the global metrics server.
func Init(cfg *config.Server) error {
- options := newOptions(cfg)
+ options, err := newOptions(cfg)
+ if err != nil {
+ return err
+ }
+
handler, err := registerForHandler(options)
if err != nil {
return err
@@ -72,7 +76,7 @@ func start(address string, handler http.Handler) error {
return nil
}
-func newOptions(svr *config.Server) registerOptions {
+func newOptions(svr *config.Server) (registerOptions, error) {
newOpts := registerOptions{}
newOpts.address = net.JoinHostPort(v1alpha1.GatewayMetricsHost, fmt.Sprint(v1alpha1.GatewayMetricsPort))
@@ -85,14 +89,37 @@ func newOptions(svr *config.Server) registerOptions {
}
for _, config := range svr.EnvoyGateway.GetEnvoyGatewayTelemetry().Metrics.Sinks {
- newOpts.pushOptions.sinks = append(newOpts.pushOptions.sinks, metricsSink{
+ sink := metricsSink{
host: config.OpenTelemetry.Host,
port: config.OpenTelemetry.Port,
protocol: config.OpenTelemetry.Protocol,
- })
+ }
+
+ // we do not explicitly set default values for ExporterInterval and ExporterTimeout
+ // instead, let the upstream repository set default values for it
+ if config.ExporterInterval != nil && len(*config.ExporterInterval) != 0 {
+ interval, err := time.ParseDuration(string(*config.ExporterInterval))
+ if err != nil {
+ metricsLogger.Error(err, "failed to parse exporter interval time format")
+ return newOpts, err
+ }
+
+ sink.exporterInterval = interval
+ }
+ if config.ExporterTimeout != nil && len(*config.ExporterTimeout) != 0 {
+ timeout, err := time.ParseDuration(string(*config.ExporterTimeout))
+ if err != nil {
+ metricsLogger.Error(err, "failed to parse exporter timeout time format")
+ return newOpts, err
+ }
+
+ sink.exporterTimeout = timeout
+ }
+
+ newOpts.pushOptions.sinks = append(newOpts.pushOptions.sinks, sink)
}
- return newOpts
+ return newOpts, nil
}
// registerForHandler sets the global metrics registry to the provided Prometheus registerer.
@@ -156,7 +183,15 @@ func registerOTELHTTPexporter(otelOpts *[]metric.Option, opts registerOptions) e
return err
}
- otelreader := metric.NewPeriodicReader(httpexporter)
+ periodOpts := []metric.PeriodicReaderOption{}
+ if sink.exporterInterval != 0 {
+ periodOpts = append(periodOpts, metric.WithInterval(sink.exporterInterval))
+ }
+ if sink.exporterTimeout != 0 {
+ periodOpts = append(periodOpts, metric.WithTimeout(sink.exporterTimeout))
+ }
+
+ otelreader := metric.NewPeriodicReader(httpexporter, periodOpts...)
*otelOpts = append(*otelOpts, metric.WithReader(otelreader))
metricsLogger.Info("initialized otel http metrics push endpoint", "address", address)
}
@@ -179,7 +214,15 @@ func registerOTELgRPCexporter(otelOpts *[]metric.Option, opts registerOptions) e
return err
}
- otelreader := metric.NewPeriodicReader(httpexporter)
+ periodOpts := []metric.PeriodicReaderOption{}
+ if sink.exporterInterval != 0 {
+ periodOpts = append(periodOpts, metric.WithInterval(sink.exporterInterval))
+ }
+ if sink.exporterTimeout != 0 {
+ periodOpts = append(periodOpts, metric.WithTimeout(sink.exporterTimeout))
+ }
+
+ otelreader := metric.NewPeriodicReader(httpexporter, periodOpts...)
*otelOpts = append(*otelOpts, metric.WithReader(otelreader))
metricsLogger.Info("initialized otel grpc metrics push endpoint", "address", address)
}
@@ -201,7 +244,9 @@ type registerOptions struct {
}
type metricsSink struct {
- protocol string
- host string
- port int32
+ protocol string
+ host string
+ port int32
+ exporterTimeout time.Duration
+ exporterInterval time.Duration
}
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index c3316f67026..92506bc3a96 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -713,6 +713,8 @@ _Appears in:_
| --- | --- | --- | --- |
| `type` | _[MetricSinkType](#metricsinktype)_ | true | Type defines the metric sink type.
EG control plane currently supports OpenTelemetry. |
| `openTelemetry` | _[EnvoyGatewayOpenTelemetrySink](#envoygatewayopentelemetrysink)_ | true | OpenTelemetry defines the configuration for OpenTelemetry sink.
It's required if the sink type is OpenTelemetry. |
+| `exporterInterval` | _[ExporterDuration](#exporterduration)_ | true | ExporterInterval configures the intervening time between exports for a
Sink. This option overrides any value set for the
OTEL_METRIC_EXPORT_INTERVAL environment variable.
If ExporterInterval is less than or equal to zero, 60 seconds
is used as the default. |
+| `exporterTimeout` | _[ExporterDuration](#exporterduration)_ | true | ExporterTimeout configures the time a Sink waits for an export to
complete before canceling it. This option overrides any value set for the
OTEL_METRIC_EXPORT_TIMEOUT environment variable.
If ExporterTimeout is less than or equal to zero, 30 seconds
is used as the default. |
#### EnvoyGatewayMetrics
@@ -990,6 +992,20 @@ _Appears in:_
+#### ExporterDuration
+
+_Underlying type:_ _string_
+
+ExporterDuration is used to represent the duration of the exporter.
+It is used to represent duration as a string and parsed by time.ParseDuration function.
+This type uses the time format in Go.
+example: "1h30m" means a duration of 1 hour and 30 minutes, "10s" means a duration of 10 seconds.
+
+_Appears in:_
+- [EnvoyGatewayMetricSink](#envoygatewaymetricsink)
+
+
+
#### ExtAuth