Skip to content

Commit 54564b6

Browse files
committed
feat: envoyproxy health check event logging
Adds support for configuring Envoy health check event logging via the EnvoyProxy API. Health check events (probe outcomes) can be written as JSON to a file sink (defaults to /dev/stdout). The new `healthCheckLog` field under `spec.telemetry` of EnvoyProxy controls which probe outcomes are logged (Failure, FailureTransition, Success, SuccessTransition) and where the events are written. Internally, the event log config is carried on ir.ActiveHealthCheck.EventLog so it flows naturally through TrafficFeatures into every cluster that has active health checks configured, including filter-created clusters (ext-proc, extauth, etc.) without any extra threading. Closes #8753 Signed-off-by: Guy Daich <guy.daich@sap.com>
1 parent 6916245 commit 54564b6

36 files changed

Lines changed: 2227 additions & 24 deletions
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright Envoy Gateway Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
// The full text of the Apache license is available in the LICENSE file at
4+
// the root of the repo.
5+
6+
package v1alpha1
7+
8+
// ProxyHealthCheckLog configures Envoy health check event logging.
9+
// Health check events (state transitions, failures, successes) are emitted
10+
// to each configured sink.
11+
//
12+
// See the Envoy health check API reference for details on the underlying fields:
13+
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/health_check.proto
14+
type ProxyHealthCheckLog struct {
15+
// Sinks defines where health check events are written.
16+
// When omitted, events are written to /dev/stdout.
17+
//
18+
// +kubebuilder:validation:MaxItems=1
19+
// +optional
20+
Sinks []ProxyHealthCheckLogSink `json:"sinks,omitempty"`
21+
22+
// Matches defines which health check probe outcomes produce a log entry.
23+
// When omitted or empty, all events are logged.
24+
//
25+
// Each value must be unique. Multiple values are ORed. If any failure type is
26+
// specified then a success type must also be specified, and vice versa.
27+
//
28+
// +kubebuilder:validation:MaxItems=4
29+
// +kubebuilder:validation:XValidation:rule="self.exists(e, e == 'Failure' || e == 'FailureTransition') == self.exists(e, e == 'Success' || e == 'SuccessTransition')",message="a failure type and a success type must both be specified together"
30+
// +listType=set
31+
// +optional
32+
Matches []ProxyHealthCheckLogEventType `json:"matches,omitempty"`
33+
}
34+
35+
// ProxyHealthCheckLogEventType specifies which health check probe outcomes produce a log entry.
36+
//
37+
// +kubebuilder:validation:Enum=Failure;FailureTransition;Success;SuccessTransition
38+
type ProxyHealthCheckLogEventType string
39+
40+
const (
41+
// ProxyHealthCheckLogEventTypeFailure logs every failed probe regardless of
42+
// the host's current health state.
43+
ProxyHealthCheckLogEventTypeFailure ProxyHealthCheckLogEventType = "Failure"
44+
45+
// ProxyHealthCheckLogEventTypeFailureTransition logs only when a host
46+
// transitions from healthy to unhealthy.
47+
ProxyHealthCheckLogEventTypeFailureTransition ProxyHealthCheckLogEventType = "FailureTransition"
48+
49+
// ProxyHealthCheckLogEventTypeSuccess logs every successful probe regardless
50+
// of the host's current health state.
51+
ProxyHealthCheckLogEventTypeSuccess ProxyHealthCheckLogEventType = "Success"
52+
53+
// ProxyHealthCheckLogEventTypeSuccessTransition logs only when a host
54+
// transitions from unhealthy to healthy.
55+
ProxyHealthCheckLogEventTypeSuccessTransition ProxyHealthCheckLogEventType = "SuccessTransition"
56+
)
57+
58+
// ProxyHealthCheckLogSinkType is the type of a ProxyHealthCheckLog sink.
59+
type ProxyHealthCheckLogSinkType string
60+
61+
const (
62+
// ProxyHealthCheckLogSinkTypeFile writes health check events as JSON to a local file.
63+
ProxyHealthCheckLogSinkTypeFile ProxyHealthCheckLogSinkType = "File"
64+
)
65+
66+
// ProxyHealthCheckLogSink defines a destination for health check event logs.
67+
// +union
68+
//
69+
// +kubebuilder:validation:XValidation:rule="self.type == 'File' ? has(self.file) : !has(self.file)",message="If ProxyHealthCheckLogSink type is File, file field needs to be set."
70+
type ProxyHealthCheckLogSink struct {
71+
// Type defines the type of sink.
72+
//
73+
// +kubebuilder:validation:Enum=File
74+
// +unionDiscriminator
75+
Type ProxyHealthCheckLogSinkType `json:"type"`
76+
77+
// File defines the file sink configuration.
78+
// Required when type is File.
79+
//
80+
// +optional
81+
File *FileEnvoyProxyHealthCheckLog `json:"file,omitempty"`
82+
}
83+
84+
// FileEnvoyProxyHealthCheckLog writes health check events as JSON to a local file path.
85+
//
86+
// See: https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/health_check/event_sinks/file/v3/file.proto
87+
type FileEnvoyProxyHealthCheckLog struct {
88+
// Path specifies the file path for health check event output.
89+
// Use /dev/stdout to write to standard output.
90+
//
91+
// +kubebuilder:validation:MinLength=1
92+
Path string `json:"path"`
93+
}

api/v1alpha1/envoyproxy_types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,12 @@ type ProxyTelemetry struct {
409409
// RequestID configures Envoy request ID behavior.
410410
// +optional
411411
RequestID *RequestIDSettings `json:"requestID,omitempty"`
412+
413+
// HealthCheckLog configures health check event logging for all clusters
414+
// that have active health checks configured.
415+
// Health check events are written as JSON to the specified file path.
416+
// +optional
417+
HealthCheckLog *ProxyHealthCheckLog `json:"healthCheckLog,omitempty"`
412418
}
413419

414420
// EnvoyProxyProviderType defines the types of providers supported by Envoy Proxy.

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 67 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14603,6 +14603,73 @@ spec:
1460314603
minItems: 1
1460414604
type: array
1460514605
type: object
14606+
healthCheckLog:
14607+
description: |-
14608+
HealthCheckLog configures health check event logging for all clusters
14609+
that have active health checks configured.
14610+
Health check events are written as JSON to the specified file path.
14611+
properties:
14612+
matches:
14613+
description: |-
14614+
Matches defines which health check probe outcomes produce a log entry.
14615+
When omitted or empty, all events are logged.
14616+
14617+
Each value must be unique. Multiple values are ORed. If any failure type is
14618+
specified then a success type must also be specified, and vice versa.
14619+
items:
14620+
description: ProxyHealthCheckLogEventType specifies which
14621+
health check probe outcomes produce a log entry.
14622+
enum:
14623+
- Failure
14624+
- FailureTransition
14625+
- Success
14626+
- SuccessTransition
14627+
type: string
14628+
maxItems: 4
14629+
type: array
14630+
x-kubernetes-list-type: set
14631+
x-kubernetes-validations:
14632+
- message: a failure type and a success type must both be
14633+
specified together
14634+
rule: self.exists(e, e == 'Failure' || e == 'FailureTransition')
14635+
== self.exists(e, e == 'Success' || e == 'SuccessTransition')
14636+
sinks:
14637+
description: |-
14638+
Sinks defines where health check events are written.
14639+
When omitted, events are written to /dev/stdout.
14640+
items:
14641+
description: ProxyHealthCheckLogSink defines a destination
14642+
for health check event logs.
14643+
properties:
14644+
file:
14645+
description: |-
14646+
File defines the file sink configuration.
14647+
Required when type is File.
14648+
properties:
14649+
path:
14650+
description: |-
14651+
Path specifies the file path for health check event output.
14652+
Use /dev/stdout to write to standard output.
14653+
minLength: 1
14654+
type: string
14655+
required:
14656+
- path
14657+
type: object
14658+
type:
14659+
description: Type defines the type of sink.
14660+
enum:
14661+
- File
14662+
type: string
14663+
required:
14664+
- type
14665+
type: object
14666+
x-kubernetes-validations:
14667+
- message: If ProxyHealthCheckLogSink type is File, file
14668+
field needs to be set.
14669+
rule: 'self.type == ''File'' ? has(self.file) : !has(self.file)'
14670+
maxItems: 1
14671+
type: array
14672+
type: object
1460614673
metrics:
1460714674
description: Metrics defines metrics configuration for managed
1460814675
proxies.

charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14602,6 +14602,73 @@ spec:
1460214602
minItems: 1
1460314603
type: array
1460414604
type: object
14605+
healthCheckLog:
14606+
description: |-
14607+
HealthCheckLog configures health check event logging for all clusters
14608+
that have active health checks configured.
14609+
Health check events are written as JSON to the specified file path.
14610+
properties:
14611+
matches:
14612+
description: |-
14613+
Matches defines which health check probe outcomes produce a log entry.
14614+
When omitted or empty, all events are logged.
14615+
14616+
Each value must be unique. Multiple values are ORed. If any failure type is
14617+
specified then a success type must also be specified, and vice versa.
14618+
items:
14619+
description: ProxyHealthCheckLogEventType specifies which
14620+
health check probe outcomes produce a log entry.
14621+
enum:
14622+
- Failure
14623+
- FailureTransition
14624+
- Success
14625+
- SuccessTransition
14626+
type: string
14627+
maxItems: 4
14628+
type: array
14629+
x-kubernetes-list-type: set
14630+
x-kubernetes-validations:
14631+
- message: a failure type and a success type must both be
14632+
specified together
14633+
rule: self.exists(e, e == 'Failure' || e == 'FailureTransition')
14634+
== self.exists(e, e == 'Success' || e == 'SuccessTransition')
14635+
sinks:
14636+
description: |-
14637+
Sinks defines where health check events are written.
14638+
When omitted, events are written to /dev/stdout.
14639+
items:
14640+
description: ProxyHealthCheckLogSink defines a destination
14641+
for health check event logs.
14642+
properties:
14643+
file:
14644+
description: |-
14645+
File defines the file sink configuration.
14646+
Required when type is File.
14647+
properties:
14648+
path:
14649+
description: |-
14650+
Path specifies the file path for health check event output.
14651+
Use /dev/stdout to write to standard output.
14652+
minLength: 1
14653+
type: string
14654+
required:
14655+
- path
14656+
type: object
14657+
type:
14658+
description: Type defines the type of sink.
14659+
enum:
14660+
- File
14661+
type: string
14662+
required:
14663+
- type
14664+
type: object
14665+
x-kubernetes-validations:
14666+
- message: If ProxyHealthCheckLogSink type is File, file
14667+
field needs to be set.
14668+
rule: 'self.type == ''File'' ? has(self.file) : !has(self.file)'
14669+
maxItems: 1
14670+
type: array
14671+
type: object
1460514672
metrics:
1460614673
description: Metrics defines metrics configuration for managed
1460714674
proxies.

internal/gatewayapi/listener.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,51 @@ func (t *Translator) processProxyObservability(gwCtx *GatewayContext, xdsIR *ir.
727727
return
728728
}
729729
proxyInfra.ResolvedMetricSinks = resolvedSinks
730+
731+
xdsIR.HealthCheckLog = processHealthCheckLog(envoyProxy)
732+
}
733+
734+
func processHealthCheckLog(envoyProxy *egv1a1.EnvoyProxy) *ir.ProxyHealthCheckLog {
735+
if envoyProxy == nil ||
736+
envoyProxy.Spec.Telemetry == nil ||
737+
envoyProxy.Spec.Telemetry.HealthCheckLog == nil {
738+
return nil
739+
}
740+
hcLogging := envoyProxy.Spec.Telemetry.HealthCheckLog
741+
irHCLogging := &ir.ProxyHealthCheckLog{}
742+
743+
// Translate Matches to the two Envoy booleans.
744+
// Empty/omitted Matches means log everything (both always-log flags true).
745+
// Failure sets AlwaysLogHealthCheckFailures; FailureTransition leaves it false
746+
// (Envoy logs transitions by default). Same for Success/SuccessTransition.
747+
// Both variants may coexist: Failure OR FailureTransition resolves to Failure.
748+
if len(hcLogging.Matches) == 0 {
749+
irHCLogging.AlwaysLogHealthCheckFailures = true
750+
irHCLogging.AlwaysLogHealthCheckSuccess = true
751+
} else {
752+
for _, et := range hcLogging.Matches {
753+
switch et {
754+
case egv1a1.ProxyHealthCheckLogEventTypeFailure:
755+
irHCLogging.AlwaysLogHealthCheckFailures = true
756+
case egv1a1.ProxyHealthCheckLogEventTypeSuccess:
757+
irHCLogging.AlwaysLogHealthCheckSuccess = true
758+
}
759+
}
760+
}
761+
762+
if len(hcLogging.Sinks) == 0 {
763+
irHCLogging.FileSinks = append(irHCLogging.FileSinks, &ir.FileEnvoyProxyHealthCheckLog{
764+
Path: "/dev/stdout",
765+
})
766+
} else {
767+
sink := hcLogging.Sinks[0]
768+
if sink.Type == egv1a1.ProxyHealthCheckLogSinkTypeFile && sink.File != nil {
769+
irHCLogging.FileSinks = append(irHCLogging.FileSinks, &ir.FileEnvoyProxyHealthCheckLog{
770+
Path: sink.File.Path,
771+
})
772+
}
773+
}
774+
return irHCLogging
730775
}
731776

732777
func (t *Translator) processInfraIRListener(listener *ListenerContext, infraIR resource.InfraIRMap, irKey string, servicePort *protocolPort, containerPort int32) {

0 commit comments

Comments
 (0)