diff --git a/api/v1alpha1/envoygateway_metrics_types.go b/api/v1alpha1/envoygateway_metrics_types.go
index 0b827a06afa..7d796e848f6 100644
--- a/api/v1alpha1/envoygateway_metrics_types.go
+++ b/api/v1alpha1/envoygateway_metrics_types.go
@@ -5,6 +5,8 @@
package v1alpha1
+import gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
+
// EnvoyGatewayMetrics defines control plane push/pull metrics configurations.
type EnvoyGatewayMetrics struct {
// Sinks defines the metric sinks where metrics are sent to.
@@ -38,6 +40,18 @@ type EnvoyGatewayOpenTelemetrySink struct {
// +kubebuilder:validation:Minimum=0
// +kubebuilder:default=4317
Port int32 `json:"port,omitempty"`
+ // ExportInterval configures the intervening time between exports for a
+ // Sink. This option overrides any value set for the
+ // OTEL_METRIC_EXPORT_INTERVAL environment variable.
+ // If ExportInterval is less than or equal to zero, 60 seconds
+ // is used as the default.
+ ExportInterval *gatewayv1.Duration `json:"exportInterval,omitempty"`
+ // ExportTimeout 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 ExportTimeout is less than or equal to zero, 30 seconds
+ // is used as the default.
+ ExportTimeout *gatewayv1.Duration `json:"exportTimeout,omitempty"`
}
// EnvoyGatewayPrometheusProvider will expose prometheus endpoint in pull mode.
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index fd607c16af7..0dbd0c9c052 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -1307,7 +1307,7 @@ func (in *EnvoyGatewayMetricSink) DeepCopyInto(out *EnvoyGatewayMetricSink) {
if in.OpenTelemetry != nil {
in, out := &in.OpenTelemetry, &out.OpenTelemetry
*out = new(EnvoyGatewayOpenTelemetrySink)
- **out = **in
+ (*in).DeepCopyInto(*out)
}
}
@@ -1351,6 +1351,16 @@ func (in *EnvoyGatewayMetrics) DeepCopy() *EnvoyGatewayMetrics {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *EnvoyGatewayOpenTelemetrySink) DeepCopyInto(out *EnvoyGatewayOpenTelemetrySink) {
*out = *in
+ if in.ExportInterval != nil {
+ in, out := &in.ExportInterval, &out.ExportInterval
+ *out = new(apisv1.Duration)
+ **out = **in
+ }
+ if in.ExportTimeout != nil {
+ in, out := &in.ExportTimeout, &out.ExportTimeout
+ *out = new(apisv1.Duration)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyGatewayOpenTelemetrySink.
diff --git a/internal/metrics/register.go b/internal/metrics/register.go
index e6332aeb8c9..a73d433718b 100644
--- a/internal/metrics/register.go
+++ b/internal/metrics/register.go
@@ -31,7 +31,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
@@ -71,7 +75,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))
@@ -84,14 +88,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.OpenTelemetry.ExportInterval != nil && len(*config.OpenTelemetry.ExportInterval) != 0 {
+ interval, err := time.ParseDuration(string(*config.OpenTelemetry.ExportInterval))
+ if err != nil {
+ metricsLogger.Error(err, "failed to parse exporter interval time format")
+ return newOpts, err
+ }
+
+ sink.exportInterval = interval
+ }
+ if config.OpenTelemetry.ExportTimeout != nil && len(*config.OpenTelemetry.ExportTimeout) != 0 {
+ timeout, err := time.ParseDuration(string(*config.OpenTelemetry.ExportTimeout))
+ if err != nil {
+ metricsLogger.Error(err, "failed to parse exporter timeout time format")
+ return newOpts, err
+ }
+
+ sink.exportTimeout = 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.
@@ -155,7 +182,17 @@ func registerOTELHTTPexporter(otelOpts *[]metric.Option, opts registerOptions) e
return err
}
- otelreader := metric.NewPeriodicReader(httpexporter)
+ periodOpts := []metric.PeriodicReaderOption{}
+ // If we do not set the interval or timeout for the exporter,
+ // we let the upstream set the default value for it.
+ if sink.exportInterval != 0 {
+ periodOpts = append(periodOpts, metric.WithInterval(sink.exportInterval))
+ }
+ if sink.exportTimeout != 0 {
+ periodOpts = append(periodOpts, metric.WithTimeout(sink.exportTimeout))
+ }
+
+ otelreader := metric.NewPeriodicReader(httpexporter, periodOpts...)
*otelOpts = append(*otelOpts, metric.WithReader(otelreader))
metricsLogger.Info("initialized otel http metrics push endpoint", "address", address)
}
@@ -178,7 +215,17 @@ func registerOTELgRPCexporter(otelOpts *[]metric.Option, opts registerOptions) e
return err
}
- otelreader := metric.NewPeriodicReader(httpexporter)
+ periodOpts := []metric.PeriodicReaderOption{}
+ // If we do not set the interval or timeout for the exporter,
+ // we let the upstream set the default value for it.
+ if sink.exportInterval != 0 {
+ periodOpts = append(periodOpts, metric.WithInterval(sink.exportInterval))
+ }
+ if sink.exportTimeout != 0 {
+ periodOpts = append(periodOpts, metric.WithTimeout(sink.exportTimeout))
+ }
+
+ otelreader := metric.NewPeriodicReader(httpexporter, periodOpts...)
*otelOpts = append(*otelOpts, metric.WithReader(otelreader))
metricsLogger.Info("initialized otel grpc metrics push endpoint", "address", address)
}
@@ -200,7 +247,9 @@ type registerOptions struct {
}
type metricsSink struct {
- protocol string
- host string
- port int32
+ protocol string
+ host string
+ port int32
+ exportTimeout time.Duration
+ exportInterval time.Duration
}
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 6ac4fe6b123..85280beb0f5 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -1034,6 +1034,8 @@ _Appears in:_
| `host` | _string_ | true | Host define the sink service hostname. |
| `protocol` | _string_ | true | Protocol define the sink service protocol. |
| `port` | _integer_ | false | Port defines the port the sink service is exposed on. |
+| `exportInterval` | _[Duration](#duration)_ | true | ExportInterval configures the intervening time between exports for a
Sink. This option overrides any value set for the
OTEL_METRIC_EXPORT_INTERVAL environment variable.
If ExportInterval is less than or equal to zero, 60 seconds
is used as the default. |
+| `exportTimeout` | _[Duration](#duration)_ | true | ExportTimeout 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 ExportTimeout is less than or equal to zero, 30 seconds
is used as the default. |
#### EnvoyGatewayPrometheusProvider