diff --git a/api/v1alpha1/envoyproxy_metric_types.go b/api/v1alpha1/envoyproxy_metric_types.go
index 848eff29c0b..52b17cf627b 100644
--- a/api/v1alpha1/envoyproxy_metric_types.go
+++ b/api/v1alpha1/envoyproxy_metric_types.go
@@ -27,6 +27,10 @@ type ProxyMetrics struct {
// EnableVirtualHostStats enables envoy stat metrics for virtual hosts.
EnableVirtualHostStats bool `json:"enableVirtualHostStats,omitempty"`
+
+ // EnablePerEndpointStats enables per endpoint envoy stats metrics.
+ // Please use with caution.
+ EnablePerEndpointStats bool `json:"enablePerEndpointStats,omitempty"`
}
// ProxyMetricSink defines the sink of metrics.
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
index 9673de5eb6d..7db1fdd8e81 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
@@ -9905,6 +9905,11 @@ spec:
description: Metrics defines metrics configuration for managed
proxies.
properties:
+ enablePerEndpointStats:
+ description: |-
+ EnablePerEndpointStats enables per endpoint envoy stats metrics.
+ Please use with caution.
+ type: boolean
enableVirtualHostStats:
description: EnableVirtualHostStats enables envoy stat metrics
for virtual hosts.
diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go
index 3c7aa41945c..bab7c4c17c2 100644
--- a/internal/gatewayapi/listener.go
+++ b/internal/gatewayapi/listener.go
@@ -290,5 +290,6 @@ func processMetrics(envoyproxy *egv1a1.EnvoyProxy) *ir.Metrics {
}
return &ir.Metrics{
EnableVirtualHostStats: envoyproxy.Spec.Telemetry.Metrics.EnableVirtualHostStats,
+ EnablePerEndpointStats: envoyproxy.Spec.Telemetry.Metrics.EnablePerEndpointStats,
}
}
diff --git a/internal/gatewayapi/listener_test.go b/internal/gatewayapi/listener_test.go
index 92384872bbc..1da6638f9a8 100644
--- a/internal/gatewayapi/listener_test.go
+++ b/internal/gatewayapi/listener_test.go
@@ -204,6 +204,21 @@ func TestProcessMetrics(t *testing.T) {
EnableVirtualHostStats: true,
},
},
+ {
+ name: "peer endpoint stats enabled",
+ proxy: &egcfgv1a1.EnvoyProxy{
+ Spec: egcfgv1a1.EnvoyProxySpec{
+ Telemetry: &egcfgv1a1.ProxyTelemetry{
+ Metrics: &egcfgv1a1.ProxyMetrics{
+ EnablePerEndpointStats: true,
+ },
+ },
+ },
+ },
+ expected: &ir.Metrics{
+ EnablePerEndpointStats: true,
+ },
+ },
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
diff --git a/internal/ir/xds.go b/internal/ir/xds.go
index 7db99e3b6e8..95bcb5b3a9b 100644
--- a/internal/ir/xds.go
+++ b/internal/ir/xds.go
@@ -1440,6 +1440,7 @@ type Tracing struct {
// +k8s:deepcopy-gen=true
type Metrics struct {
EnableVirtualHostStats bool `json:"enableVirtualHostStats" yaml:"enableVirtualHostStats"`
+ EnablePerEndpointStats bool `json:"enablePerEndpointStats" yaml:"enablePerEndpointStats"`
}
// TCPKeepalive define the TCP Keepalive configuration.
diff --git a/internal/xds/translator/accesslog.go b/internal/xds/translator/accesslog.go
index a74315a255e..63e6d46c9fd 100644
--- a/internal/xds/translator/accesslog.go
+++ b/internal/xds/translator/accesslog.go
@@ -233,7 +233,7 @@ func convertToKeyValueList(attributes map[string]string, additionalLabels bool)
return keyValueList
}
-func processClusterForAccessLog(tCtx *types.ResourceVersionTable, al *ir.AccessLog) error {
+func processClusterForAccessLog(tCtx *types.ResourceVersionTable, al *ir.AccessLog, metrics *ir.Metrics) error {
if al == nil {
return nil
}
@@ -251,6 +251,7 @@ func processClusterForAccessLog(tCtx *types.ResourceVersionTable, al *ir.AccessL
settings: []*ir.DestinationSetting{ds},
tSocket: nil,
endpointType: EndpointTypeDNS,
+ metrics: metrics,
}); err != nil && !errors.Is(err, ErrXdsClusterExists) {
return err
}
diff --git a/internal/xds/translator/cluster.go b/internal/xds/translator/cluster.go
index 0d2593f9cc6..6cbe45def02 100644
--- a/internal/xds/translator/cluster.go
+++ b/internal/xds/translator/cluster.go
@@ -49,6 +49,7 @@ type xdsClusterArgs struct {
http1Settings *ir.HTTP1Settings
timeout *ir.Timeout
tcpkeepalive *ir.TCPKeepalive
+ metrics *ir.Metrics
}
type EndpointType int
@@ -87,6 +88,13 @@ func buildXdsCluster(args *xdsClusterArgs) *clusterv3.Cluster {
cluster.ConnectTimeout = buildConnectTimeout(args.timeout)
+ // set peer endpoint stats
+ if args.metrics != nil && args.metrics.EnablePerEndpointStats {
+ cluster.TrackClusterStats = &clusterv3.TrackClusterStats{
+ PerEndpointStats: args.metrics.EnablePerEndpointStats,
+ }
+ }
+
// Set Proxy Protocol
if args.proxyProtocol != nil {
cluster.TransportSocket = buildProxyProtocolSocket(args.proxyProtocol, args.tSocket)
diff --git a/internal/xds/translator/ratelimit.go b/internal/xds/translator/ratelimit.go
index 6fb3e2d86db..02b1c3d6048 100644
--- a/internal/xds/translator/ratelimit.go
+++ b/internal/xds/translator/ratelimit.go
@@ -462,7 +462,7 @@ func buildRateLimitTLSocket() (*corev3.TransportSocket, error) {
}, nil
}
-func (t *Translator) createRateLimitServiceCluster(tCtx *types.ResourceVersionTable, irListener *ir.HTTPListener) error {
+func (t *Translator) createRateLimitServiceCluster(tCtx *types.ResourceVersionTable, irListener *ir.HTTPListener, metrics *ir.Metrics) error {
// Return early if rate limits don't exist.
if !t.isRateLimitPresent(irListener) {
return nil
@@ -486,6 +486,7 @@ func (t *Translator) createRateLimitServiceCluster(tCtx *types.ResourceVersionTa
settings: []*ir.DestinationSetting{ds},
tSocket: tSocket,
endpointType: EndpointTypeDNS,
+ metrics: metrics,
}); err != nil && !errors.Is(err, ErrXdsClusterExists) {
return err
}
diff --git a/internal/xds/translator/testdata/in/xds-ir/accesslog-endpoint-stats.yaml b/internal/xds/translator/testdata/in/xds-ir/accesslog-endpoint-stats.yaml
new file mode 100644
index 00000000000..ca71bbad491
--- /dev/null
+++ b/internal/xds/translator/testdata/in/xds-ir/accesslog-endpoint-stats.yaml
@@ -0,0 +1,46 @@
+name: "accesslog"
+metrics:
+ enablePerEndpointStats: true
+accesslog:
+ text:
+ - path: "/dev/stdout"
+ format: |
+ [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"
+ json:
+ - path: "/dev/stdout"
+ json:
+ start_time: "%START_TIME%"
+ method: "%REQ(:METHOD)%"
+ path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
+ protocol: "%PROTOCOL%"
+ response_code: "%RESPONSE_CODE%"
+ openTelemetry:
+ - text: |
+ [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"
+ attributes:
+ "response_code": "%RESPONSE_CODE%"
+ resources:
+ "cluster_name": "cluster1"
+ host: otel-collector.default.svc.cluster.local
+ port: 4317
+http:
+ - name: "first-listener"
+ address: "0.0.0.0"
+ port: 10080
+ hostnames:
+ - "*"
+ path:
+ mergeSlashes: true
+ escapedSlashesAction: UnescapeAndRedirect
+ routes:
+ - name: "direct-route"
+ hostname: "*"
+ destination:
+ name: "direct-route-dest"
+ settings:
+ - endpoints:
+ - host: "1.2.3.4"
+ port: 50000
+ directResponse:
+ body: "Unknown custom filter type: UnsupportedType"
+ statusCode: 500
diff --git a/internal/xds/translator/testdata/in/xds-ir/http-endpoint-stats.yaml b/internal/xds/translator/testdata/in/xds-ir/http-endpoint-stats.yaml
new file mode 100644
index 00000000000..12fc177bde8
--- /dev/null
+++ b/internal/xds/translator/testdata/in/xds-ir/http-endpoint-stats.yaml
@@ -0,0 +1,21 @@
+name: "metrics-endpoint-stats"
+metrics:
+ enablePerEndpointStats: true
+http:
+ - name: "listener-enable-endpoint-stats"
+ address: "0.0.0.0"
+ port: 10080
+ hostnames:
+ - "*"
+ path:
+ mergeSlashes: true
+ escapedSlashesAction: UnescapeAndRedirect
+ routes:
+ - name: "first-route"
+ hostname: "*"
+ destination:
+ name: "first-route-dest"
+ settings:
+ - endpoints:
+ - host: "1.2.3.4"
+ port: 50000
diff --git a/internal/xds/translator/testdata/in/xds-ir/ratelimit-endpoint-stats.yaml b/internal/xds/translator/testdata/in/xds-ir/ratelimit-endpoint-stats.yaml
new file mode 100644
index 00000000000..56a4b8d4869
--- /dev/null
+++ b/internal/xds/translator/testdata/in/xds-ir/ratelimit-endpoint-stats.yaml
@@ -0,0 +1,66 @@
+metrics:
+ enablePerEndpointStats: true
+http:
+ - name: "first-listener"
+ address: "0.0.0.0"
+ port: 10080
+ hostnames:
+ - "*"
+ path:
+ mergeSlashes: true
+ escapedSlashesAction: UnescapeAndRedirect
+ routes:
+ - name: "first-route"
+ hostname: "*"
+ rateLimit:
+ global:
+ rules:
+ - headerMatches:
+ - name: "x-user-id"
+ exact: "one"
+ limit:
+ requests: 5
+ unit: second
+ pathMatch:
+ exact: "foo/bar"
+ destination:
+ name: "first-route-dest"
+ settings:
+ - endpoints:
+ - host: "1.2.3.4"
+ port: 50000
+ - name: "second-route"
+ hostname: "*"
+ rateLimit:
+ global:
+ rules:
+ - headerMatches:
+ - name: "x-user-id"
+ distinct: true
+ limit:
+ requests: 5
+ unit: second
+ pathMatch:
+ exact: "example"
+ destination:
+ name: "second-route-dest"
+ settings:
+ - endpoints:
+ - host: "1.2.3.4"
+ port: 50000
+ - name: "third-route"
+ hostname: "*"
+ rateLimit:
+ global:
+ rules:
+ - limit:
+ requests: 5
+ unit: second
+ pathMatch:
+ exact: "test"
+ destination:
+ name: "third-route-dest"
+ settings:
+ - endpoints:
+ - host: "1.2.3.4"
+ port: 50000
diff --git a/internal/xds/translator/testdata/in/xds-ir/tcp-endpoint-stats.yaml b/internal/xds/translator/testdata/in/xds-ir/tcp-endpoint-stats.yaml
new file mode 100644
index 00000000000..60176773c96
--- /dev/null
+++ b/internal/xds/translator/testdata/in/xds-ir/tcp-endpoint-stats.yaml
@@ -0,0 +1,15 @@
+name: "metrics-endpoint-stats"
+metrics:
+ enablePerEndpointStats: true
+tcp:
+- name: "tcp-route-enable-endpoint-stats"
+ address: "0.0.0.0"
+ port: 10080
+ destination:
+ name: "tcp-route-simple-dest"
+ settings:
+ - endpoints:
+ - host: "1.2.3.4"
+ port: 50000
+ - host: "5.6.7.8"
+ port: 50001
diff --git a/internal/xds/translator/testdata/in/xds-ir/tracing-endpoint-stats.yaml b/internal/xds/translator/testdata/in/xds-ir/tracing-endpoint-stats.yaml
new file mode 100644
index 00000000000..4a566033560
--- /dev/null
+++ b/internal/xds/translator/testdata/in/xds-ir/tracing-endpoint-stats.yaml
@@ -0,0 +1,44 @@
+name: "tracing"
+metrics:
+ enablePerEndpointStats: true
+tracing:
+ serviceName: "fake-name.fake-ns"
+ samplingRate: 90
+ customTags:
+ "literal1":
+ type: Literal
+ literal:
+ value: "value1"
+ "env1":
+ type: Environment
+ environment:
+ name: "env1"
+ defaultValue: "-"
+ "req1":
+ type: RequestHeader
+ requestHeader:
+ name: "X-Request-Id"
+ defaultValue: "-"
+ host: otel-collector.monitoring.svc.cluster.local
+ port: 4317
+http:
+ - name: "first-listener"
+ address: "0.0.0.0"
+ port: 10080
+ hostnames:
+ - "*"
+ path:
+ mergeSlashes: true
+ escapedSlashesAction: UnescapeAndRedirect
+ routes:
+ - name: "direct-route"
+ hostname: "*"
+ destination:
+ name: "direct-route-dest"
+ settings:
+ - endpoints:
+ - host: "1.2.3.4"
+ port: 50000
+ directResponse:
+ body: "Unknown custom filter type: UnsupportedType"
+ statusCode: 500
diff --git a/internal/xds/translator/testdata/in/xds-ir/udp-endpoint-stats.yaml b/internal/xds/translator/testdata/in/xds-ir/udp-endpoint-stats.yaml
new file mode 100644
index 00000000000..4b5b9982aee
--- /dev/null
+++ b/internal/xds/translator/testdata/in/xds-ir/udp-endpoint-stats.yaml
@@ -0,0 +1,15 @@
+name: "metrics-endpoint-stats"
+metrics:
+ enablePerEndpointStats: true
+udp:
+- name: "udp-route-enable-endpoint-stats"
+ address: "0.0.0.0"
+ port: 10080
+ destination:
+ name: "udp-route-dest"
+ settings:
+ - endpoints:
+ - host: "1.2.3.4"
+ port: 50000
+ - host: "5.6.7.8"
+ port: 50001
diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.clusters.yaml
new file mode 100644
index 00000000000..ac33653a54f
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.clusters.yaml
@@ -0,0 +1,53 @@
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ edsClusterConfig:
+ edsConfig:
+ ads: {}
+ resourceApiVersion: V3
+ serviceName: direct-route-dest
+ lbPolicy: LEAST_REQUEST
+ name: direct-route-dest
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ trackClusterStats:
+ perEndpointStats: true
+ type: EDS
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ dnsRefreshRate: 30s
+ lbPolicy: LEAST_REQUEST
+ loadAssignment:
+ clusterName: accesslog|otel-collector.default.svc.cluster.local|4317
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: otel-collector.default.svc.cluster.local
+ portValue: 4317
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: accesslog|otel-collector.default.svc.cluster.local|4317/backend/0
+ name: accesslog|otel-collector.default.svc.cluster.local|4317
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ respectDnsTtl: true
+ trackClusterStats:
+ perEndpointStats: true
+ type: STRICT_DNS
+ typedExtensionProtocolOptions:
+ envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
+ '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
+ explicitHttpConfig:
+ http2ProtocolOptions: {}
diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.endpoints.yaml
new file mode 100644
index 00000000000..20c80b3aaaa
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.endpoints.yaml
@@ -0,0 +1,12 @@
+- clusterName: direct-route-dest
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: 1.2.3.4
+ portValue: 50000
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: direct-route-dest/backend/0
diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.listeners.yaml
new file mode 100644
index 00000000000..e6d5535eb15
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.listeners.yaml
@@ -0,0 +1,144 @@
+- accessLog:
+ - filter:
+ responseFlagFilter:
+ flags:
+ - NR
+ name: envoy.access_loggers.file
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
+ logFormat:
+ textFormatSource:
+ inlineString: |
+ [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"
+ path: /dev/stdout
+ - filter:
+ responseFlagFilter:
+ flags:
+ - NR
+ name: envoy.access_loggers.file
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
+ logFormat:
+ jsonFormat:
+ method: '%REQ(:METHOD)%'
+ path: '%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%'
+ protocol: '%PROTOCOL%'
+ response_code: '%RESPONSE_CODE%'
+ start_time: '%START_TIME%'
+ path: /dev/stdout
+ - filter:
+ responseFlagFilter:
+ flags:
+ - NR
+ name: envoy.access_loggers.open_telemetry
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.access_loggers.open_telemetry.v3.OpenTelemetryAccessLogConfig
+ attributes:
+ values:
+ - key: k8s.namespace.name
+ value:
+ stringValue: '%ENVIRONMENT(ENVOY_GATEWAY_NAMESPACE)%'
+ - key: k8s.pod.name
+ value:
+ stringValue: '%ENVIRONMENT(ENVOY_POD_NAME)%'
+ - key: response_code
+ value:
+ stringValue: '%RESPONSE_CODE%'
+ body:
+ stringValue: |
+ [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"
+ commonConfig:
+ grpcService:
+ envoyGrpc:
+ authority: otel-collector.default.svc.cluster.local
+ clusterName: accesslog|otel-collector.default.svc.cluster.local|4317
+ logName: otel_envoy_accesslog
+ transportApiVersion: V3
+ resourceAttributes:
+ values:
+ - key: cluster_name
+ value:
+ stringValue: cluster1
+ address:
+ socketAddress:
+ address: 0.0.0.0
+ portValue: 10080
+ defaultFilterChain:
+ filters:
+ - name: envoy.filters.network.http_connection_manager
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
+ accessLog:
+ - name: envoy.access_loggers.file
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
+ logFormat:
+ textFormatSource:
+ inlineString: |
+ [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"
+ path: /dev/stdout
+ - name: envoy.access_loggers.file
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
+ logFormat:
+ jsonFormat:
+ method: '%REQ(:METHOD)%'
+ path: '%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%'
+ protocol: '%PROTOCOL%'
+ response_code: '%RESPONSE_CODE%'
+ start_time: '%START_TIME%'
+ path: /dev/stdout
+ - name: envoy.access_loggers.open_telemetry
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.access_loggers.open_telemetry.v3.OpenTelemetryAccessLogConfig
+ attributes:
+ values:
+ - key: k8s.namespace.name
+ value:
+ stringValue: '%ENVIRONMENT(ENVOY_GATEWAY_NAMESPACE)%'
+ - key: k8s.pod.name
+ value:
+ stringValue: '%ENVIRONMENT(ENVOY_POD_NAME)%'
+ - key: response_code
+ value:
+ stringValue: '%RESPONSE_CODE%'
+ body:
+ stringValue: |
+ [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"
+ commonConfig:
+ grpcService:
+ envoyGrpc:
+ authority: otel-collector.default.svc.cluster.local
+ clusterName: accesslog|otel-collector.default.svc.cluster.local|4317
+ logName: otel_envoy_accesslog
+ transportApiVersion: V3
+ resourceAttributes:
+ values:
+ - key: cluster_name
+ value:
+ stringValue: cluster1
+ commonHttpProtocolOptions:
+ headersWithUnderscoresAction: REJECT_REQUEST
+ http2ProtocolOptions:
+ initialConnectionWindowSize: 1048576
+ initialStreamWindowSize: 65536
+ maxConcurrentStreams: 100
+ httpFilters:
+ - name: envoy.filters.http.router
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
+ suppressEnvoyHeaders: true
+ mergeSlashes: true
+ normalizePath: true
+ pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT
+ rds:
+ configSource:
+ ads: {}
+ resourceApiVersion: V3
+ routeConfigName: first-listener
+ serverHeaderTransformation: PASS_THROUGH
+ statPrefix: http
+ useRemoteAddress: true
+ drainType: MODIFY_ONLY
+ name: first-listener
+ perConnectionBufferLimitBytes: 32768
diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.routes.yaml
new file mode 100644
index 00000000000..d4a7fa5ae20
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-endpoint-stats.routes.yaml
@@ -0,0 +1,14 @@
+- ignorePortInHostMatching: true
+ name: first-listener
+ virtualHosts:
+ - domains:
+ - '*'
+ name: first-listener/*
+ routes:
+ - directResponse:
+ body:
+ inlineString: 'Unknown custom filter type: UnsupportedType'
+ status: 500
+ match:
+ prefix: /
+ name: direct-route
diff --git a/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.clusters.yaml
new file mode 100644
index 00000000000..e9ea29c138f
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.clusters.yaml
@@ -0,0 +1,19 @@
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ edsClusterConfig:
+ edsConfig:
+ ads: {}
+ resourceApiVersion: V3
+ serviceName: first-route-dest
+ lbPolicy: LEAST_REQUEST
+ name: first-route-dest
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ trackClusterStats:
+ perEndpointStats: true
+ type: EDS
diff --git a/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.endpoints.yaml
new file mode 100644
index 00000000000..3b3f2d09076
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.endpoints.yaml
@@ -0,0 +1,12 @@
+- clusterName: first-route-dest
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: 1.2.3.4
+ portValue: 50000
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: first-route-dest/backend/0
diff --git a/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.listeners.yaml
new file mode 100644
index 00000000000..b327b344d25
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.listeners.yaml
@@ -0,0 +1,34 @@
+- address:
+ socketAddress:
+ address: 0.0.0.0
+ portValue: 10080
+ defaultFilterChain:
+ filters:
+ - name: envoy.filters.network.http_connection_manager
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
+ commonHttpProtocolOptions:
+ headersWithUnderscoresAction: REJECT_REQUEST
+ http2ProtocolOptions:
+ initialConnectionWindowSize: 1048576
+ initialStreamWindowSize: 65536
+ maxConcurrentStreams: 100
+ httpFilters:
+ - name: envoy.filters.http.router
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
+ suppressEnvoyHeaders: true
+ mergeSlashes: true
+ normalizePath: true
+ pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT
+ rds:
+ configSource:
+ ads: {}
+ resourceApiVersion: V3
+ routeConfigName: listener-enable-endpoint-stats
+ serverHeaderTransformation: PASS_THROUGH
+ statPrefix: http
+ useRemoteAddress: true
+ drainType: MODIFY_ONLY
+ name: listener-enable-endpoint-stats
+ perConnectionBufferLimitBytes: 32768
diff --git a/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.routes.yaml
new file mode 100644
index 00000000000..5f0482832e6
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/http-endpoint-stats.routes.yaml
@@ -0,0 +1,14 @@
+- ignorePortInHostMatching: true
+ name: listener-enable-endpoint-stats
+ virtualHosts:
+ - domains:
+ - '*'
+ name: listener-enable-endpoint-stats/*
+ routes:
+ - match:
+ prefix: /
+ name: first-route
+ route:
+ cluster: first-route-dest
+ upgradeConfigs:
+ - upgradeType: websocket
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.clusters.yaml
new file mode 100644
index 00000000000..21ea0681611
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.clusters.yaml
@@ -0,0 +1,104 @@
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ edsClusterConfig:
+ edsConfig:
+ ads: {}
+ resourceApiVersion: V3
+ serviceName: first-route-dest
+ lbPolicy: LEAST_REQUEST
+ name: first-route-dest
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ trackClusterStats:
+ perEndpointStats: true
+ type: EDS
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ edsClusterConfig:
+ edsConfig:
+ ads: {}
+ resourceApiVersion: V3
+ serviceName: second-route-dest
+ lbPolicy: LEAST_REQUEST
+ name: second-route-dest
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ trackClusterStats:
+ perEndpointStats: true
+ type: EDS
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ edsClusterConfig:
+ edsConfig:
+ ads: {}
+ resourceApiVersion: V3
+ serviceName: third-route-dest
+ lbPolicy: LEAST_REQUEST
+ name: third-route-dest
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ trackClusterStats:
+ perEndpointStats: true
+ type: EDS
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ dnsRefreshRate: 30s
+ lbPolicy: LEAST_REQUEST
+ loadAssignment:
+ clusterName: ratelimit_cluster
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: envoy-ratelimit.envoy-gateway-system.svc.cluster.local
+ portValue: 8081
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: ratelimit_cluster/backend/0
+ name: ratelimit_cluster
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ respectDnsTtl: true
+ trackClusterStats:
+ perEndpointStats: true
+ transportSocket:
+ name: envoy.transport_sockets.tls
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
+ commonTlsContext:
+ tlsCertificates:
+ - certificateChain:
+ filename: /certs/tls.crt
+ privateKey:
+ filename: /certs/tls.key
+ validationContext:
+ trustedCa:
+ filename: /certs/ca.crt
+ type: STRICT_DNS
+ typedExtensionProtocolOptions:
+ envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
+ '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
+ explicitHttpConfig:
+ http2ProtocolOptions: {}
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.endpoints.yaml
new file mode 100644
index 00000000000..475b89a087c
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.endpoints.yaml
@@ -0,0 +1,36 @@
+- clusterName: first-route-dest
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: 1.2.3.4
+ portValue: 50000
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: first-route-dest/backend/0
+- clusterName: second-route-dest
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: 1.2.3.4
+ portValue: 50000
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: second-route-dest/backend/0
+- clusterName: third-route-dest
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: 1.2.3.4
+ portValue: 50000
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: third-route-dest/backend/0
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.listeners.yaml
new file mode 100644
index 00000000000..d6f261b7cd5
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.listeners.yaml
@@ -0,0 +1,44 @@
+- address:
+ socketAddress:
+ address: 0.0.0.0
+ portValue: 10080
+ defaultFilterChain:
+ filters:
+ - name: envoy.filters.network.http_connection_manager
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
+ commonHttpProtocolOptions:
+ headersWithUnderscoresAction: REJECT_REQUEST
+ http2ProtocolOptions:
+ initialConnectionWindowSize: 1048576
+ initialStreamWindowSize: 65536
+ maxConcurrentStreams: 100
+ httpFilters:
+ - name: envoy.filters.http.ratelimit
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
+ domain: first-listener
+ enableXRatelimitHeaders: DRAFT_VERSION_03
+ rateLimitService:
+ grpcService:
+ envoyGrpc:
+ clusterName: ratelimit_cluster
+ transportApiVersion: V3
+ - name: envoy.filters.http.router
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
+ suppressEnvoyHeaders: true
+ mergeSlashes: true
+ normalizePath: true
+ pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT
+ rds:
+ configSource:
+ ads: {}
+ resourceApiVersion: V3
+ routeConfigName: first-listener
+ serverHeaderTransformation: PASS_THROUGH
+ statPrefix: http
+ useRemoteAddress: true
+ drainType: MODIFY_ONLY
+ name: first-listener
+ perConnectionBufferLimitBytes: 32768
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.routes.yaml
new file mode 100644
index 00000000000..479c2cd143c
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.routes.yaml
@@ -0,0 +1,57 @@
+- ignorePortInHostMatching: true
+ name: first-listener
+ virtualHosts:
+ - domains:
+ - '*'
+ name: first-listener/*
+ routes:
+ - match:
+ path: foo/bar
+ name: first-route
+ route:
+ cluster: first-route-dest
+ rateLimits:
+ - actions:
+ - genericKey:
+ descriptorKey: first-route
+ descriptorValue: first-route
+ - headerValueMatch:
+ descriptorKey: rule-0-match-0
+ descriptorValue: rule-0-match-0
+ expectMatch: true
+ headers:
+ - name: x-user-id
+ stringMatch:
+ exact: one
+ upgradeConfigs:
+ - upgradeType: websocket
+ - match:
+ path: example
+ name: second-route
+ route:
+ cluster: second-route-dest
+ rateLimits:
+ - actions:
+ - genericKey:
+ descriptorKey: second-route
+ descriptorValue: second-route
+ - requestHeaders:
+ descriptorKey: rule-0-match-0
+ headerName: x-user-id
+ upgradeConfigs:
+ - upgradeType: websocket
+ - match:
+ path: test
+ name: third-route
+ route:
+ cluster: third-route-dest
+ rateLimits:
+ - actions:
+ - genericKey:
+ descriptorKey: third-route
+ descriptorValue: third-route
+ - genericKey:
+ descriptorKey: rule-0-match--1
+ descriptorValue: rule-0-match--1
+ upgradeConfigs:
+ - upgradeType: websocket
diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.clusters.yaml
new file mode 100644
index 00000000000..4387d9b31e0
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.clusters.yaml
@@ -0,0 +1,19 @@
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ edsClusterConfig:
+ edsConfig:
+ ads: {}
+ resourceApiVersion: V3
+ serviceName: tcp-route-simple-dest
+ lbPolicy: LEAST_REQUEST
+ name: tcp-route-simple-dest
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ trackClusterStats:
+ perEndpointStats: true
+ type: EDS
diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.endpoints.yaml
new file mode 100644
index 00000000000..7eb06a08f40
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.endpoints.yaml
@@ -0,0 +1,18 @@
+- clusterName: tcp-route-simple-dest
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: 1.2.3.4
+ portValue: 50000
+ loadBalancingWeight: 1
+ - endpoint:
+ address:
+ socketAddress:
+ address: 5.6.7.8
+ portValue: 50001
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: tcp-route-simple-dest/backend/0
diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.listeners.yaml
new file mode 100644
index 00000000000..7cf2660fa72
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.listeners.yaml
@@ -0,0 +1,14 @@
+- address:
+ socketAddress:
+ address: 0.0.0.0
+ portValue: 10080
+ drainType: MODIFY_ONLY
+ filterChains:
+ - filters:
+ - name: envoy.filters.network.tcp_proxy
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
+ cluster: tcp-route-simple-dest
+ statPrefix: tcp
+ name: tcp-route-enable-endpoint-stats
+ perConnectionBufferLimitBytes: 32768
diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.routes.yaml
new file mode 100644
index 00000000000..fe51488c706
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/tcp-endpoint-stats.routes.yaml
@@ -0,0 +1 @@
+[]
diff --git a/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.clusters.yaml
new file mode 100644
index 00000000000..24a732d8e70
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.clusters.yaml
@@ -0,0 +1,53 @@
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ edsClusterConfig:
+ edsConfig:
+ ads: {}
+ resourceApiVersion: V3
+ serviceName: direct-route-dest
+ lbPolicy: LEAST_REQUEST
+ name: direct-route-dest
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ trackClusterStats:
+ perEndpointStats: true
+ type: EDS
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ dnsRefreshRate: 30s
+ lbPolicy: LEAST_REQUEST
+ loadAssignment:
+ clusterName: tracing|otel-collector.monitoring.svc.cluster.local|4317
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: otel-collector.monitoring.svc.cluster.local
+ portValue: 4317
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: tracing|otel-collector.monitoring.svc.cluster.local|4317/backend/0
+ name: tracing|otel-collector.monitoring.svc.cluster.local|4317
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ respectDnsTtl: true
+ trackClusterStats:
+ perEndpointStats: true
+ type: STRICT_DNS
+ typedExtensionProtocolOptions:
+ envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
+ '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
+ explicitHttpConfig:
+ http2ProtocolOptions: {}
diff --git a/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.endpoints.yaml
new file mode 100644
index 00000000000..20c80b3aaaa
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.endpoints.yaml
@@ -0,0 +1,12 @@
+- clusterName: direct-route-dest
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: 1.2.3.4
+ portValue: 50000
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: direct-route-dest/backend/0
diff --git a/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.listeners.yaml
new file mode 100644
index 00000000000..c8277f1e190
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.listeners.yaml
@@ -0,0 +1,63 @@
+- address:
+ socketAddress:
+ address: 0.0.0.0
+ portValue: 10080
+ defaultFilterChain:
+ filters:
+ - name: envoy.filters.network.http_connection_manager
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
+ commonHttpProtocolOptions:
+ headersWithUnderscoresAction: REJECT_REQUEST
+ http2ProtocolOptions:
+ initialConnectionWindowSize: 1048576
+ initialStreamWindowSize: 65536
+ maxConcurrentStreams: 100
+ httpFilters:
+ - name: envoy.filters.http.router
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
+ suppressEnvoyHeaders: true
+ mergeSlashes: true
+ normalizePath: true
+ pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT
+ rds:
+ configSource:
+ ads: {}
+ resourceApiVersion: V3
+ routeConfigName: first-listener
+ serverHeaderTransformation: PASS_THROUGH
+ statPrefix: http
+ tracing:
+ clientSampling:
+ value: 100
+ customTags:
+ - environment:
+ defaultValue: '-'
+ name: env1
+ tag: env1
+ - literal:
+ value: value1
+ tag: literal1
+ - requestHeader:
+ defaultValue: '-'
+ name: X-Request-Id
+ tag: req1
+ overallSampling:
+ value: 100
+ provider:
+ name: envoy.tracers.opentelemetry
+ typedConfig:
+ '@type': type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig
+ grpcService:
+ envoyGrpc:
+ authority: otel-collector.monitoring.svc.cluster.local
+ clusterName: tracing|otel-collector.monitoring.svc.cluster.local|4317
+ serviceName: fake-name.fake-ns
+ randomSampling:
+ value: 90
+ spawnUpstreamSpan: true
+ useRemoteAddress: true
+ drainType: MODIFY_ONLY
+ name: first-listener
+ perConnectionBufferLimitBytes: 32768
diff --git a/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.routes.yaml
new file mode 100644
index 00000000000..d4a7fa5ae20
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/tracing-endpoint-stats.routes.yaml
@@ -0,0 +1,14 @@
+- ignorePortInHostMatching: true
+ name: first-listener
+ virtualHosts:
+ - domains:
+ - '*'
+ name: first-listener/*
+ routes:
+ - directResponse:
+ body:
+ inlineString: 'Unknown custom filter type: UnsupportedType'
+ status: 500
+ match:
+ prefix: /
+ name: direct-route
diff --git a/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.clusters.yaml
new file mode 100644
index 00000000000..e26cb444c5c
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.clusters.yaml
@@ -0,0 +1,19 @@
+- circuitBreakers:
+ thresholds:
+ - maxRetries: 1024
+ commonLbConfig:
+ localityWeightedLbConfig: {}
+ connectTimeout: 10s
+ dnsLookupFamily: V4_ONLY
+ edsClusterConfig:
+ edsConfig:
+ ads: {}
+ resourceApiVersion: V3
+ serviceName: udp-route-dest
+ lbPolicy: LEAST_REQUEST
+ name: udp-route-dest
+ outlierDetection: {}
+ perConnectionBufferLimitBytes: 32768
+ trackClusterStats:
+ perEndpointStats: true
+ type: EDS
diff --git a/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.endpoints.yaml
new file mode 100644
index 00000000000..2e3c84e672c
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.endpoints.yaml
@@ -0,0 +1,18 @@
+- clusterName: udp-route-dest
+ endpoints:
+ - lbEndpoints:
+ - endpoint:
+ address:
+ socketAddress:
+ address: 1.2.3.4
+ portValue: 50000
+ loadBalancingWeight: 1
+ - endpoint:
+ address:
+ socketAddress:
+ address: 5.6.7.8
+ portValue: 50001
+ loadBalancingWeight: 1
+ loadBalancingWeight: 1
+ locality:
+ region: udp-route-dest/backend/0
diff --git a/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.listeners.yaml
new file mode 100644
index 00000000000..8d9eaea1141
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.listeners.yaml
@@ -0,0 +1,18 @@
+- address:
+ socketAddress:
+ address: 0.0.0.0
+ portValue: 10080
+ protocol: UDP
+ listenerFilters:
+ - name: envoy.filters.udp_listener.udp_proxy
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.udp.udp_proxy.v3.UdpProxyConfig
+ matcher:
+ onNoMatch:
+ action:
+ name: route
+ typedConfig:
+ '@type': type.googleapis.com/envoy.extensions.filters.udp.udp_proxy.v3.Route
+ cluster: udp-route-dest
+ statPrefix: service
+ name: udp-route-enable-endpoint-stats
diff --git a/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.routes.yaml
new file mode 100644
index 00000000000..fe51488c706
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/udp-endpoint-stats.routes.yaml
@@ -0,0 +1 @@
+[]
diff --git a/internal/xds/translator/tracing.go b/internal/xds/translator/tracing.go
index 8e948fe710e..44e80681c59 100644
--- a/internal/xds/translator/tracing.go
+++ b/internal/xds/translator/tracing.go
@@ -119,7 +119,7 @@ func buildHCMTracing(tracing *ir.Tracing) (*hcm.HttpConnectionManager_Tracing, e
}, nil
}
-func processClusterForTracing(tCtx *types.ResourceVersionTable, tracing *ir.Tracing) error {
+func processClusterForTracing(tCtx *types.ResourceVersionTable, tracing *ir.Tracing, metrics *ir.Metrics) error {
if tracing == nil {
return nil
}
@@ -136,6 +136,7 @@ func processClusterForTracing(tCtx *types.ResourceVersionTable, tracing *ir.Trac
settings: []*ir.DestinationSetting{ds},
tSocket: nil,
endpointType: EndpointTypeDNS,
+ metrics: metrics,
}); err != nil && !errors.Is(err, ErrXdsClusterExists) {
return err
}
diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go
index d0b6289b472..2d5945d2e96 100644
--- a/internal/xds/translator/translator.go
+++ b/internal/xds/translator/translator.go
@@ -86,11 +86,11 @@ func (t *Translator) Translate(ir *ir.Xds) (*types.ResourceVersionTable, error)
errs = errors.Join(errs, err)
}
- if err := processTCPListenerXdsTranslation(tCtx, ir.TCP, ir.AccessLog); err != nil {
+ if err := processTCPListenerXdsTranslation(tCtx, ir.TCP, ir.AccessLog, ir.Metrics); err != nil {
errs = errors.Join(errs, err)
}
- if err := processUDPListenerXdsTranslation(tCtx, ir.UDP, ir.AccessLog); err != nil {
+ if err := processUDPListenerXdsTranslation(tCtx, ir.UDP, ir.AccessLog, ir.Metrics); err != nil {
errs = errors.Join(errs, err)
}
@@ -98,11 +98,11 @@ func (t *Translator) Translate(ir *ir.Xds) (*types.ResourceVersionTable, error)
errs = errors.Join(errs, err)
}
- if err := processClusterForAccessLog(tCtx, ir.AccessLog); err != nil {
+ if err := processClusterForAccessLog(tCtx, ir.AccessLog, ir.Metrics); err != nil {
errs = errors.Join(errs, err)
}
- if err := processClusterForTracing(tCtx, ir.Tracing); err != nil {
+ if err := processClusterForTracing(tCtx, ir.Tracing, ir.Metrics); err != nil {
errs = errors.Join(errs, err)
}
@@ -278,7 +278,7 @@ func (t *Translator) processHTTPListenerXdsTranslation(
// RateLimit filter is handled separately because it relies on the global
// rate limit server configuration.
// Check if a ratelimit cluster exists, if not, add it, if it's needed.
- if err = t.createRateLimitServiceCluster(tCtx, httpListener); err != nil {
+ if err = t.createRateLimitServiceCluster(tCtx, httpListener, metrics); err != nil {
errs = errors.Join(errs, err)
}
@@ -369,7 +369,12 @@ func (t *Translator) addRouteToRouteConfig(
vHost.Routes = append(vHost.Routes, xdsRoute)
if httpRoute.Destination != nil {
- if err = processXdsCluster(tCtx, httpRoute, httpListener.HTTP1); err != nil {
+ if err = processXdsCluster(
+ tCtx,
+ httpRoute,
+ httpListener.HTTP1,
+ metrics,
+ ); err != nil {
errs = errors.Join(errs, err)
}
}
@@ -381,6 +386,7 @@ func (t *Translator) addRouteToRouteConfig(
settings: mirrorDest.Settings,
tSocket: nil,
endpointType: EndpointTypeStatic,
+ metrics: metrics,
}); err != nil && !errors.Is(err, ErrXdsClusterExists) {
errs = errors.Join(errs, err)
}
@@ -456,7 +462,7 @@ func buildHTTP3AltSvcHeader(port int) *corev3.HeaderValueOption {
}
}
-func processTCPListenerXdsTranslation(tCtx *types.ResourceVersionTable, tcpListeners []*ir.TCPListener, accesslog *ir.AccessLog) error {
+func processTCPListenerXdsTranslation(tCtx *types.ResourceVersionTable, tcpListeners []*ir.TCPListener, accesslog *ir.AccessLog, metrics *ir.Metrics) error {
// The XDS translation is done in a best-effort manner, so we collect all
// errors and return them at the end.
var errs error
@@ -487,6 +493,7 @@ func processTCPListenerXdsTranslation(tCtx *types.ResourceVersionTable, tcpListe
healthCheck: tcpListener.HealthCheck,
timeout: tcpListener.Timeout,
endpointType: buildEndpointType(tcpListener.Destination.Settings),
+ metrics: metrics,
}); err != nil && !errors.Is(err, ErrXdsClusterExists) {
errs = errors.Join(errs, err)
}
@@ -509,7 +516,7 @@ func processTCPListenerXdsTranslation(tCtx *types.ResourceVersionTable, tcpListe
return errs
}
-func processUDPListenerXdsTranslation(tCtx *types.ResourceVersionTable, udpListeners []*ir.UDPListener, accesslog *ir.AccessLog) error {
+func processUDPListenerXdsTranslation(tCtx *types.ResourceVersionTable, udpListeners []*ir.UDPListener, accesslog *ir.AccessLog, metrics *ir.Metrics) error {
// The XDS translation is done in a best-effort manner, so we collect all
// errors and return them at the end.
var errs error
@@ -537,6 +544,7 @@ func processUDPListenerXdsTranslation(tCtx *types.ResourceVersionTable, udpListe
timeout: udpListener.Timeout,
tSocket: nil,
endpointType: buildEndpointType(udpListener.Destination.Settings),
+ metrics: metrics,
}); err != nil && !errors.Is(err, ErrXdsClusterExists) {
errs = errors.Join(errs, err)
}
@@ -628,7 +636,7 @@ func findXdsEndpoint(tCtx *types.ResourceVersionTable, name string) *endpointv3.
}
// processXdsCluster processes a xds cluster by its endpoint address type.
-func processXdsCluster(tCtx *types.ResourceVersionTable, httpRoute *ir.HTTPRoute, http1Settings *ir.HTTP1Settings) error {
+func processXdsCluster(tCtx *types.ResourceVersionTable, httpRoute *ir.HTTPRoute, http1Settings *ir.HTTP1Settings, metrics *ir.Metrics) error {
if err := addXdsCluster(tCtx, &xdsClusterArgs{
name: httpRoute.Destination.Name,
settings: httpRoute.Destination.Settings,
@@ -641,6 +649,7 @@ func processXdsCluster(tCtx *types.ResourceVersionTable, httpRoute *ir.HTTPRoute
http1Settings: http1Settings,
timeout: httpRoute.Timeout,
tcpkeepalive: httpRoute.TCPKeepalive,
+ metrics: metrics,
}); err != nil && !errors.Is(err, ErrXdsClusterExists) {
return err
}
diff --git a/internal/xds/translator/translator_test.go b/internal/xds/translator/translator_test.go
index 30dfc66cb99..f60d23a8bb1 100644
--- a/internal/xds/translator/translator_test.go
+++ b/internal/xds/translator/translator_test.go
@@ -314,6 +314,24 @@ func TestTranslateXds(t *testing.T) {
{
name: "ext-proc",
},
+ {
+ name: "http-endpoint-stats",
+ },
+ {
+ name: "tcp-endpoint-stats",
+ },
+ {
+ name: "udp-endpoint-stats",
+ },
+ {
+ name: "tracing-endpoint-stats",
+ },
+ {
+ name: "accesslog-endpoint-stats",
+ },
+ {
+ name: "ratelimit-endpoint-stats",
+ },
{
name: "wasm",
},
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 7ffbd623dc8..869f7f47e40 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -2402,6 +2402,7 @@ _Appears in:_
| `sinks` | _[ProxyMetricSink](#proxymetricsink) array_ | true | Sinks defines the metric sinks where metrics are sent to. |
| `matches` | _[StringMatch](#stringmatch) array_ | true | Matches defines configuration for selecting specific metrics instead of generating all metrics stats
that are enabled by default. This helps reduce CPU and memory overhead in Envoy, but eliminating some stats
may after critical functionality. Here are the stats that we strongly recommend not disabling:
`cluster_manager.warming_clusters`, `cluster..membership_total`,`cluster..membership_healthy`,
`cluster..membership_degraded`,reference https://github.com/envoyproxy/envoy/issues/9856,
https://github.com/envoyproxy/envoy/issues/14610 |
| `enableVirtualHostStats` | _boolean_ | true | EnableVirtualHostStats enables envoy stat metrics for virtual hosts. |
+| `enablePerEndpointStats` | _boolean_ | true | EnablePerEndpointStats enables per endpoint envoy stats metrics.
Please use with caution. |
#### ProxyOpenTelemetrySink