diff --git a/api/gateway/v1alpha1/gateway_types.go b/api/gateway/v1alpha1/gateway_types.go
index 188e4c3f..fbf7dd4e 100644
--- a/api/gateway/v1alpha1/gateway_types.go
+++ b/api/gateway/v1alpha1/gateway_types.go
@@ -78,6 +78,19 @@ type GatewayBGPNeighbor struct {
type GatewayLogs struct {
Default GatewayLogLevel `json:"default,omitempty"`
Tags map[string]GatewayLogLevel `json:"tags,omitempty"`
+ // RateLimit optionally throttles repeated log messages using a token
+ // bucket. When unset, log output is not rate limited.
+ RateLimit *GatewayLogRateLimit `json:"rateLimit,omitempty"`
+}
+
+// GatewayLogRateLimit configures the token-bucket rate limiter applied to log
+// output. Both fields must be greater than zero when the limiter is set.
+type GatewayLogRateLimit struct {
+ // Burst is the maximum number of log messages allowed in a burst, i.e. the
+ // token bucket capacity
+ Burst uint32 `json:"burst,omitempty"`
+ // ReplenishPerSecond is the number of tokens (messages) replenished per second
+ ReplenishPerSecond uint32 `json:"replenishPerSecond,omitempty"`
}
type GatewayLogLevel string
@@ -185,6 +198,15 @@ func (gw *Gateway) Validate(ctx context.Context, kube kclient.Reader, fabricCfg
return fmt.Errorf("workers should be between 1 and 64: %w", ErrInvalidGW)
}
+ if rl := gw.Spec.Logs.RateLimit; rl != nil {
+ if rl.Burst == 0 {
+ return fmt.Errorf("log rate limit burst must be greater than 0: %w", ErrInvalidGW)
+ }
+ if rl.ReplenishPerSecond == 0 {
+ return fmt.Errorf("log rate limit replenishPerSecond must be greater than 0: %w", ErrInvalidGW)
+ }
+ }
+
protoIP, err := netip.ParsePrefix(gw.Spec.ProtocolIP)
if err != nil {
return fmt.Errorf("invalid ProtocolIP %s: %w", gw.Spec.ProtocolIP, errors.Join(err, ErrInvalidGW))
diff --git a/api/gateway/v1alpha1/gateway_types_test.go b/api/gateway/v1alpha1/gateway_types_test.go
index 2ed727ba..56593f74 100644
--- a/api/gateway/v1alpha1/gateway_types_test.go
+++ b/api/gateway/v1alpha1/gateway_types_test.go
@@ -277,6 +277,29 @@ func TestGatewayValidate(t *testing.T) {
objs: base,
err: v1alpha1.ErrInvalidGW,
},
+ {
+ name: "test-log-rate-limit-valid",
+ gw: *gwa("gw-1", func(gw *v1alpha1.Gateway) {
+ gw.Spec.Logs.RateLimit = &v1alpha1.GatewayLogRateLimit{Burst: 50, ReplenishPerSecond: 5}
+ }),
+ objs: base,
+ },
+ {
+ name: "test-log-rate-limit-zero-burst",
+ gw: *gwa("gw-1", func(gw *v1alpha1.Gateway) {
+ gw.Spec.Logs.RateLimit = &v1alpha1.GatewayLogRateLimit{Burst: 0, ReplenishPerSecond: 5}
+ }),
+ objs: base,
+ err: v1alpha1.ErrInvalidGW,
+ },
+ {
+ name: "test-log-rate-limit-zero-replenish",
+ gw: *gwa("gw-1", func(gw *v1alpha1.Gateway) {
+ gw.Spec.Logs.RateLimit = &v1alpha1.GatewayLogRateLimit{Burst: 50, ReplenishPerSecond: 0}
+ }),
+ objs: base,
+ err: v1alpha1.ErrInvalidGW,
+ },
}
scheme := runtime.NewScheme()
diff --git a/api/gateway/v1alpha1/zz_generated.deepcopy.go b/api/gateway/v1alpha1/zz_generated.deepcopy.go
index 9c03cc1a..42407a61 100644
--- a/api/gateway/v1alpha1/zz_generated.deepcopy.go
+++ b/api/gateway/v1alpha1/zz_generated.deepcopy.go
@@ -209,6 +209,21 @@ func (in *GatewayList) DeepCopyObject() runtime.Object {
return nil
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *GatewayLogRateLimit) DeepCopyInto(out *GatewayLogRateLimit) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayLogRateLimit.
+func (in *GatewayLogRateLimit) DeepCopy() *GatewayLogRateLimit {
+ if in == nil {
+ return nil
+ }
+ out := new(GatewayLogRateLimit)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GatewayLogs) DeepCopyInto(out *GatewayLogs) {
*out = *in
@@ -219,6 +234,11 @@ func (in *GatewayLogs) DeepCopyInto(out *GatewayLogs) {
(*out)[key] = val
}
}
+ if in.RateLimit != nil {
+ in, out := &in.RateLimit, &out.RateLimit
+ *out = new(GatewayLogRateLimit)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayLogs.
diff --git a/config/crd/bases/gateway.githedgehog.com_gateways.yaml b/config/crd/bases/gateway.githedgehog.com_gateways.yaml
index e20926e2..9190fdf9 100644
--- a/config/crd/bases/gateway.githedgehog.com_gateways.yaml
+++ b/config/crd/bases/gateway.githedgehog.com_gateways.yaml
@@ -113,6 +113,23 @@ spec:
properties:
default:
type: string
+ rateLimit:
+ description: |-
+ RateLimit optionally throttles repeated log messages using a token
+ bucket. When unset, log output is not rate limited.
+ properties:
+ burst:
+ description: |-
+ Burst is the maximum number of log messages allowed in a burst, i.e. the
+ token bucket capacity
+ format: int32
+ type: integer
+ replenishPerSecond:
+ description: ReplenishPerSecond is the number of tokens (messages)
+ replenished per second
+ format: int32
+ type: integer
+ type: object
tags:
additionalProperties:
type: string
diff --git a/config/crd/bases/gwint.githedgehog.com_gatewayagents.yaml b/config/crd/bases/gwint.githedgehog.com_gatewayagents.yaml
index 2f17fe62..67796ff2 100644
--- a/config/crd/bases/gwint.githedgehog.com_gatewayagents.yaml
+++ b/config/crd/bases/gwint.githedgehog.com_gatewayagents.yaml
@@ -141,6 +141,23 @@ spec:
properties:
default:
type: string
+ rateLimit:
+ description: |-
+ RateLimit optionally throttles repeated log messages using a token
+ bucket. When unset, log output is not rate limited.
+ properties:
+ burst:
+ description: |-
+ Burst is the maximum number of log messages allowed in a burst, i.e. the
+ token bucket capacity
+ format: int32
+ type: integer
+ replenishPerSecond:
+ description: ReplenishPerSecond is the number of tokens
+ (messages) replenished per second
+ format: int32
+ type: integer
+ type: object
tags:
additionalProperties:
type: string
diff --git a/docs/api.md b/docs/api.md
index 0cb3f149..eca38423 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -991,6 +991,24 @@ _Appears in:_
| `trace` | |
+#### GatewayLogRateLimit
+
+
+
+GatewayLogRateLimit configures the token-bucket rate limiter applied to log
+output. Both fields must be greater than zero when the limiter is set.
+
+
+
+_Appears in:_
+- [GatewayLogs](#gatewaylogs)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `burst` _integer_ | Burst is the maximum number of log messages allowed in a burst, i.e. the
token bucket capacity | | |
+| `replenishPerSecond` _integer_ | ReplenishPerSecond is the number of tokens (messages) replenished per second | | |
+
+
#### GatewayLogs
@@ -1006,6 +1024,7 @@ _Appears in:_
| --- | --- | --- | --- |
| `default` _[GatewayLogLevel](#gatewayloglevel)_ | | | |
| `tags` _object (keys:string, values:[GatewayLogLevel](#gatewayloglevel))_ | | | |
+| `rateLimit` _[GatewayLogRateLimit](#gatewaylogratelimit)_ | RateLimit optionally throttles repeated log messages using a token
bucket. When unset, log output is not rate limited. | | |
#### GatewayPeering