diff --git a/api/v1alpha1/accesslogging_types.go b/api/v1alpha1/accesslogging_types.go index edc19e97599..31eac69f122 100644 --- a/api/v1alpha1/accesslogging_types.go +++ b/api/v1alpha1/accesslogging_types.go @@ -37,7 +37,6 @@ type ProxyAccessLogSetting struct { // If type is defined, the accesslog settings would apply to the relevant component (as-is). // +kubebuilder:validation:Enum=Listener;Route // +optional - // +notImplementedHide Type *ProxyAccessLogType `json:"type,omitempty"` } diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 0c69d7b3097..5c85e561ea1 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -241,7 +241,6 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * }, }, nil } - if envoyproxy.Spec.Telemetry.AccessLog.Disable { return nil, nil } @@ -249,6 +248,16 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * irAccessLog := &ir.AccessLog{} // translate the access log configuration to the IR for i, accessLog := range envoyproxy.Spec.Telemetry.AccessLog.Settings { + var accessLogType *ir.ProxyAccessLogType + if accessLog.Type != nil { + switch *accessLog.Type { + case egv1a1.ProxyAccessLogTypeRoute: + accessLogType = ptr.To(ir.ProxyAccessLogTypeRoute) + case egv1a1.ProxyAccessLogTypeListener: + accessLogType = ptr.To(ir.ProxyAccessLogTypeListener) + } + } + var format egv1a1.ProxyAccessLogFormat if accessLog.Format != nil { format = *accessLog.Format @@ -274,6 +283,16 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * return nil, utilerrors.NewAggregate(errs) } + if len(accessLog.Sinks) == 0 { + al := &ir.TextAccessLog{ + Format: format.Text, + CELMatches: validExprs, + LogType: accessLogType, + Path: "/dev/stdout", + } + irAccessLog.Text = append(irAccessLog.Text, al) + } + for j, sink := range accessLog.Sinks { switch sink.Type { case egv1a1.ProxyAccessLogSinkTypeFile: @@ -287,6 +306,7 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * Format: format.Text, Path: sink.File.Path, CELMatches: validExprs, + LogType: accessLogType, } irAccessLog.Text = append(irAccessLog.Text, al) case egv1a1.ProxyAccessLogFormatTypeJSON: @@ -299,6 +319,7 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * JSON: format.JSON, Path: sink.File.Path, CELMatches: validExprs, + LogType: accessLogType, } irAccessLog.JSON = append(irAccessLog.JSON, al) } @@ -329,6 +350,7 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * Traffic: traffic, Type: sink.ALS.Type, CELMatches: validExprs, + LogType: accessLogType, } if al.Type == egv1a1.ALSEnvoyProxyAccessLogTypeHTTP && sink.ALS.HTTP != nil { @@ -339,7 +361,6 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * } al.HTTP = http } - switch format.Type { case egv1a1.ProxyAccessLogFormatTypeJSON: al.Attributes = format.JSON @@ -367,6 +388,7 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * Settings: ds, }, Traffic: traffic, + LogType: accessLogType, } if len(ds) == 0 { @@ -391,7 +413,6 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * } } } - return irAccessLog, nil } diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml new file mode 100644 index 00000000000..03977e33075 --- /dev/null +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml @@ -0,0 +1,236 @@ +envoyProxyForGatewayClass: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + namespace: envoy-gateway-system + name: test + spec: + telemetry: + accessLog: + settings: + - type: Route + - type: Listener + - type: Route + format: + type: Text + text: | + this is a route log + sinks: + - type: File + file: + path: /dev/stdout + - type: ALS + als: + logName: accesslog + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + type: HTTP + - type: ALS + als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + - type: OpenTelemetry + openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: "cluster-1" + - type: Listener + format: + type: Text + text: | + this is a listener log + sinks: + - type: File + file: + path: /dev/stdout + - type: ALS + als: + logName: accesslog + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + type: HTTP + - type: ALS + als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + - type: OpenTelemetry + openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: "cluster-1" + - format: + type: Text + text: | + this is a Global log + sinks: + - type: File + file: + path: /dev/stdout + - type: ALS + als: + logName: accesslog + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + type: HTTP + - type: ALS + als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + - type: OpenTelemetry + openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: "cluster-1" + provider: + type: Kubernetes + kubernetes: + envoyService: + type: LoadBalancer + envoyDeployment: + replicas: 2 + container: + env: + - name: env_a + value: env_a_value + - name: env_b + value: env_b_name + image: "envoyproxy/envoy:distroless-dev" + resources: + requests: + cpu: 100m + memory: 512Mi + securityContext: + runAsUser: 2000 + allowPrivilegeEscalation: false + pod: + annotations: + key1: val1 + key2: val2 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: cloud.google.com/gke-nodepool + operator: In + values: + - router-node + tolerations: + - effect: NoSchedule + key: node-type + operator: Exists + value: "router" + securityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + fsGroupChangePolicy: "OnRootMismatch" + volumes: + - name: certs + secret: + secretName: envoy-cert +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: Same +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: envoy-gateway + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + rules: + - matches: + - path: + type: Exact + value: "/exact" + backendRefs: + - name: service-1 + port: 8080 +services: +- apiVersion: v1 + kind: Service + metadata: + name: envoy-als + namespace: monitoring + spec: + type: ClusterIP + ports: + - name: grpc + port: 9000 + appProtocol: grpc + protocol: TCP + targetPort: 9000 +endpointSlices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + name: endpointslice-envoy-als + namespace: monitoring + labels: + kubernetes.io/service-name: envoy-als + addressType: IPv4 + ports: + - name: grpc + protocol: TCP + appProtocol: grpc + port: 9090 + endpoints: + - addresses: + - "10.240.0.10" + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml new file mode 100644 index 00000000000..9c2c0d1cf82 --- /dev/null +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml @@ -0,0 +1,460 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: Same + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-1 + namespace: envoy-gateway + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + type: Exact + value: /exact + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Service envoy-gateway/service-1 not found + reason: BackendNotFound + status: "False" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway +infraIR: + envoy-gateway/gateway-1: + proxy: + config: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + creationTimestamp: null + name: test + namespace: envoy-gateway-system + spec: + logging: {} + provider: + kubernetes: + envoyDeployment: + container: + env: + - name: env_a + value: env_a_value + - name: env_b + value: env_b_name + image: envoyproxy/envoy:distroless-dev + resources: + requests: + cpu: 100m + memory: 512Mi + securityContext: + allowPrivilegeEscalation: false + runAsUser: 2000 + pod: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: cloud.google.com/gke-nodepool + operator: In + values: + - router-node + annotations: + key1: val1 + key2: val2 + securityContext: + fsGroup: 2000 + fsGroupChangePolicy: OnRootMismatch + runAsGroup: 3000 + runAsUser: 1000 + tolerations: + - effect: NoSchedule + key: node-type + operator: Exists + value: router + volumes: + - name: certs + secret: + secretName: envoy-cert + replicas: 2 + envoyService: + type: LoadBalancer + type: Kubernetes + telemetry: + accessLog: + settings: + - sinks: null + type: Route + - sinks: null + type: Listener + - format: + text: | + this is a route log + type: Text + sinks: + - file: + path: /dev/stdout + type: File + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logName: accesslog + type: HTTP + type: ALS + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + type: ALS + - openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: cluster-1 + type: OpenTelemetry + type: Route + - format: + text: | + this is a listener log + type: Text + sinks: + - file: + path: /dev/stdout + type: File + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logName: accesslog + type: HTTP + type: ALS + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + type: ALS + - openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: cluster-1 + type: OpenTelemetry + type: Listener + - format: + text: | + this is a Global log + type: Text + sinks: + - file: + path: /dev/stdout + type: File + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logName: accesslog + type: HTTP + type: ALS + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + type: ALS + - openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: cluster-1 + type: OpenTelemetry + status: {} + listeners: + - address: null + name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + name: envoy-gateway/gateway-1 +xdsIR: + envoy-gateway/gateway-1: + accessLog: + als: + - destination: + name: accesslog_als_2_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logType: Route + name: accesslog + text: | + this is a route log + type: HTTP + - destination: + name: accesslog_als_2_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + logType: Route + name: envoy-gateway-system/test + text: | + this is a route log + type: TCP + - destination: + name: accesslog_als_3_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logType: Listener + name: accesslog + text: | + this is a listener log + type: HTTP + - destination: + name: accesslog_als_3_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + logType: Listener + name: envoy-gateway-system/test + text: | + this is a listener log + type: TCP + - destination: + name: accesslog_als_4_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + name: accesslog + text: | + this is a Global log + type: HTTP + - destination: + name: accesslog_als_4_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + name: envoy-gateway-system/test + text: | + this is a Global log + type: TCP + openTelemetry: + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_2_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + logType: Route + resources: + k8s.cluster.name: cluster-1 + text: | + this is a route log + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_3_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + logType: Listener + resources: + k8s.cluster.name: cluster-1 + text: | + this is a listener log + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_4_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + resources: + k8s.cluster.name: cluster-1 + text: | + this is a Global log + text: + - logType: Route + path: /dev/stdout + - logType: Listener + path: /dev/stdout + - format: | + this is a route log + logType: Route + path: /dev/stdout + - format: | + this is a listener log + logType: Listener + path: /dev/stdout + - format: | + this is a Global log + path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - weight: 1 + directResponse: + statusCode: 500 + hostname: '*' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: envoy-gateway + name: httproute/envoy-gateway/httproute-1/rule/0/match/0/* + pathMatch: + distinct: false + exact: /exact + name: "" diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 40e7da917f3..53eb34fa2a6 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -1739,6 +1739,13 @@ type RateLimitValue struct { Unit RateLimitUnit `json:"unit" yaml:"unit"` } +type ProxyAccessLogType egv1a1.ProxyAccessLogType + +const ( + ProxyAccessLogTypeRoute = ProxyAccessLogType(egv1a1.ProxyAccessLogTypeRoute) + ProxyAccessLogTypeListener = ProxyAccessLogType(egv1a1.ProxyAccessLogTypeListener) +) + // AccessLog holds the access logging configuration. // +k8s:deepcopy-gen=true type AccessLog struct { @@ -1751,17 +1758,19 @@ type AccessLog struct { // TextAccessLog holds the configuration for text access logging. // +k8s:deepcopy-gen=true type TextAccessLog struct { - CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` - Format *string `json:"format,omitempty" yaml:"format,omitempty"` - Path string `json:"path" yaml:"path"` + CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` + Format *string `json:"format,omitempty" yaml:"format,omitempty"` + Path string `json:"path" yaml:"path"` + LogType *ProxyAccessLogType `json:"logType,omitempty" yaml:"logType,omitempty"` } // JSONAccessLog holds the configuration for JSON access logging. // +k8s:deepcopy-gen=true type JSONAccessLog struct { - CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` - JSON map[string]string `json:"json,omitempty" yaml:"json,omitempty"` - Path string `json:"path" yaml:"path"` + CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` + JSON map[string]string `json:"json,omitempty" yaml:"json,omitempty"` + Path string `json:"path" yaml:"path"` + LogType *ProxyAccessLogType `json:"logType,omitempty" yaml:"logType,omitempty"` } // ALSAccessLog holds the configuration for gRPC ALS access logging. @@ -1775,6 +1784,7 @@ type ALSAccessLog struct { Text *string `json:"text,omitempty" yaml:"text,omitempty"` Attributes map[string]string `json:"attributes,omitempty" yaml:"attributes,omitempty"` HTTP *ALSAccessLogHTTP `json:"http,omitempty" yaml:"http,omitempty"` + LogType *ProxyAccessLogType `json:"logType,omitempty" yaml:"logType,omitempty"` } // ALSAccessLogHTTP holds the configuration for HTTP ALS access logging. @@ -1788,13 +1798,14 @@ type ALSAccessLogHTTP struct { // OpenTelemetryAccessLog holds the configuration for OpenTelemetry access logging. // +k8s:deepcopy-gen=true type OpenTelemetryAccessLog struct { - CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` - Authority string `json:"authority,omitempty" yaml:"authority,omitempty"` - Text *string `json:"text,omitempty" yaml:"text,omitempty"` - Attributes map[string]string `json:"attributes,omitempty" yaml:"attributes,omitempty"` - Resources map[string]string `json:"resources,omitempty" yaml:"resources,omitempty"` - Destination RouteDestination `json:"destination,omitempty" yaml:"destination,omitempty"` - Traffic *TrafficFeatures `json:"traffic,omitempty" yaml:"traffic,omitempty"` + CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` + Authority string `json:"authority,omitempty" yaml:"authority,omitempty"` + Text *string `json:"text,omitempty" yaml:"text,omitempty"` + Attributes map[string]string `json:"attributes,omitempty" yaml:"attributes,omitempty"` + Resources map[string]string `json:"resources,omitempty" yaml:"resources,omitempty"` + Destination RouteDestination `json:"destination,omitempty" yaml:"destination,omitempty"` + Traffic *TrafficFeatures `json:"traffic,omitempty" yaml:"traffic,omitempty"` + LogType *ProxyAccessLogType `json:"logType,omitempty" yaml:"logType,omitempty"` } // EnvoyPatchPolicy defines the intermediate representation of the EnvoyPatchPolicy resource. diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 4400b555dd7..1a0185bbb9f 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -47,6 +47,11 @@ func (in *ALSAccessLog) DeepCopyInto(out *ALSAccessLog) { *out = new(ALSAccessLogHTTP) (*in).DeepCopyInto(*out) } + if in.LogType != nil { + in, out := &in.LogType, &out.LogType + *out = new(ProxyAccessLogType) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ALSAccessLog. @@ -1690,6 +1695,11 @@ func (in *JSONAccessLog) DeepCopyInto(out *JSONAccessLog) { (*out)[key] = val } } + if in.LogType != nil { + in, out := &in.LogType, &out.LogType + *out = new(ProxyAccessLogType) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONAccessLog. @@ -1976,6 +1986,11 @@ func (in *OpenTelemetryAccessLog) DeepCopyInto(out *OpenTelemetryAccessLog) { *out = new(TrafficFeatures) (*in).DeepCopyInto(*out) } + if in.LogType != nil { + in, out := &in.LogType, &out.LogType + *out = new(ProxyAccessLogType) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenTelemetryAccessLog. @@ -2985,6 +3000,11 @@ func (in *TextAccessLog) DeepCopyInto(out *TextAccessLog) { *out = new(string) **out = **in } + if in.LogType != nil { + in, out := &in.LogType, &out.LogType + *out = new(ProxyAccessLogType) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TextAccessLog. diff --git a/internal/xds/translator/accesslog.go b/internal/xds/translator/accesslog.go index 8acb6e4b005..6660ba8fab6 100644 --- a/internal/xds/translator/accesslog.go +++ b/internal/xds/translator/accesslog.go @@ -90,15 +90,24 @@ var ( } ) -func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLog { +func buildXdsAccessLog(al *ir.AccessLog, accessLogType ir.ProxyAccessLogType) []*accesslog.AccessLog { if al == nil { return nil } totalLen := len(al.Text) + len(al.JSON) + len(al.OpenTelemetry) accessLogs := make([]*accesslog.AccessLog, 0, totalLen) + // handle text file access logs for _, text := range al.Text { + // Filter out logs that are not Global or match the desired access log type + if !(text.LogType == nil || *text.LogType == accessLogType) { + continue + } + + // NR is only added to listener logs originating from a global log configuration + defaultLogTypeForListener := accessLogType == ir.ProxyAccessLogTypeListener && text.LogType == nil + filelog := &fileaccesslog.FileAccessLog{ Path: text.Path, } @@ -131,11 +140,19 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo ConfigType: &accesslog.AccessLog_TypedConfig{ TypedConfig: accesslogAny, }, - Filter: buildAccessLogFilter(text.CELMatches, forListener), + Filter: buildAccessLogFilter(text.CELMatches, defaultLogTypeForListener), }) } // handle json file access logs for _, json := range al.JSON { + // Filter out logs that are not Global or match the desired access log type + if !(json.LogType == nil || *json.LogType == accessLogType) { + continue + } + + // NR is only added to listener logs originating from a global log configuration + defaultLogTypeForListener := accessLogType == ir.ProxyAccessLogTypeListener && json.LogType == nil + jsonFormat := &structpb.Struct{ Fields: make(map[string]*structpb.Value, len(json.JSON)), } @@ -174,11 +191,19 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo ConfigType: &accesslog.AccessLog_TypedConfig{ TypedConfig: accesslogAny, }, - Filter: buildAccessLogFilter(json.CELMatches, forListener), + Filter: buildAccessLogFilter(json.CELMatches, defaultLogTypeForListener), }) } // handle ALS access logs for _, als := range al.ALS { + // Filter out logs that are not Global or match the desired access log type + if !(als.LogType == nil || *als.LogType == accessLogType) { + continue + } + + // NR is only added to listener logs originating from a global log configuration + defaultLogTypeForListener := accessLogType == ir.ProxyAccessLogTypeListener && als.LogType == nil + cc := &grpcaccesslog.CommonGrpcAccessLogConfig{ LogName: als.LogName, GrpcService: &cfgcore.GrpcService{ @@ -209,7 +234,7 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo ConfigType: &accesslog.AccessLog_TypedConfig{ TypedConfig: accesslogAny, }, - Filter: buildAccessLogFilter(als.CELMatches, forListener), + Filter: buildAccessLogFilter(als.CELMatches, defaultLogTypeForListener), }) case egv1a1.ALSEnvoyProxyAccessLogTypeTCP: alCfg := &grpcaccesslog.TcpGrpcAccessLogConfig{ @@ -222,12 +247,20 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo ConfigType: &accesslog.AccessLog_TypedConfig{ TypedConfig: accesslogAny, }, - Filter: buildAccessLogFilter(als.CELMatches, forListener), + Filter: buildAccessLogFilter(als.CELMatches, defaultLogTypeForListener), }) } } // handle open telemetry access logs for _, otel := range al.OpenTelemetry { + // Filter out logs that are not Global or match the desired access log type + if !(otel.LogType == nil || *otel.LogType == accessLogType) { + continue + } + + // NR is only added to listener logs originating from a global log configuration + defaultLogTypeForListener := accessLogType == ir.ProxyAccessLogTypeListener && otel.LogType == nil + al := &otelaccesslog.OpenTelemetryAccessLogConfig{ CommonConfig: &grpcaccesslog.CommonGrpcAccessLogConfig{ LogName: otelLogName, @@ -270,7 +303,7 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo ConfigType: &accesslog.AccessLog_TypedConfig{ TypedConfig: accesslogAny, }, - Filter: buildAccessLogFilter(otel.CELMatches, forListener), + Filter: buildAccessLogFilter(otel.CELMatches, defaultLogTypeForListener), }) } @@ -292,13 +325,13 @@ func celAccessLogFilter(expr string) *accesslog.AccessLogFilter { } } -func buildAccessLogFilter(exprs []string, forListener bool) *accesslog.AccessLogFilter { +func buildAccessLogFilter(exprs []string, withNoRouteMatchFilter bool) *accesslog.AccessLogFilter { // add filter for access logs var filters []*accesslog.AccessLogFilter for _, expr := range exprs { filters = append(filters, celAccessLogFilter(expr)) } - if forListener { + if withNoRouteMatchFilter { filters = append(filters, listenerAccessLogFilter) } diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go index 98f7c28e372..9cc8e61f6ed 100644 --- a/internal/xds/translator/listener.go +++ b/internal/xds/translator/listener.go @@ -151,7 +151,7 @@ func originalIPDetectionExtensions(clientIPDetection *ir.ClientIPDetectionSettin // TODO: Improve function parameters func buildXdsTCPListener(name, address string, port uint32, keepalive *ir.TCPKeepalive, connection *ir.ClientConnection, accesslog *ir.AccessLog) *listenerv3.Listener { socketOptions := buildTCPSocketOptions(keepalive) - al := buildXdsAccessLog(accesslog, true) + al := buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeListener) bufferLimitBytes := buildPerConnectionBufferLimitBytes(connection) return &listenerv3.Listener{ Name: name, @@ -183,7 +183,7 @@ func buildPerConnectionBufferLimitBytes(connection *ir.ClientConnection) *wrappe func buildXdsQuicListener(name, address string, port uint32, accesslog *ir.AccessLog) *listenerv3.Listener { xdsListener := &listenerv3.Listener{ Name: name + "-quic", - AccessLog: buildXdsAccessLog(accesslog, true), + AccessLog: buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeListener), Address: &corev3.Address{ Address: &corev3.Address_SocketAddress{ SocketAddress: &corev3.SocketAddress{ @@ -220,7 +220,7 @@ func buildXdsQuicListener(name, address string, port uint32, accesslog *ir.Acces func (t *Translator) addHCMToXDSListener(xdsListener *listenerv3.Listener, irListener *ir.HTTPListener, accesslog *ir.AccessLog, tracing *ir.Tracing, http3Listener bool, connection *ir.ClientConnection, ) error { - al := buildXdsAccessLog(accesslog, false) + al := buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeRoute) hcmTracing, err := buildHCMTracing(tracing) if err != nil { @@ -494,7 +494,7 @@ func addXdsTCPFilterChain(xdsListener *listenerv3.Listener, irRoute *ir.TCPRoute statPrefix = strings.Join([]string{statPrefix, strconv.Itoa(int(xdsListener.Address.GetSocketAddress().GetPortValue()))}, "-") mgr := &tcpv3.TcpProxy{ - AccessLog: buildXdsAccessLog(accesslog, false), + AccessLog: buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeRoute), StatPrefix: statPrefix, ClusterSpecifier: &tcpv3.TcpProxy_Cluster{ Cluster: clusterName, @@ -773,7 +773,7 @@ func buildXdsUDPListener(clusterName string, udpListener *ir.UDPListener, access udpProxy := &udpv3.UdpProxyConfig{ StatPrefix: statPrefix, - AccessLog: buildXdsAccessLog(accesslog, false), + AccessLog: buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeRoute), RouteSpecifier: &udpv3.UdpProxyConfig_Matcher{ Matcher: &matcher.Matcher{ OnNoMatch: &matcher.Matcher_OnMatch{ @@ -794,7 +794,7 @@ func buildXdsUDPListener(clusterName string, udpListener *ir.UDPListener, access xdsListener := &listenerv3.Listener{ Name: udpListener.Name, - AccessLog: buildXdsAccessLog(accesslog, true), + AccessLog: buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeListener), Address: &corev3.Address{ Address: &corev3.Address_SocketAddress{ SocketAddress: &corev3.SocketAddress{ diff --git a/internal/xds/translator/testdata/in/xds-ir/accesslog-types.yaml b/internal/xds/translator/testdata/in/xds-ir/accesslog-types.yaml new file mode 100644 index 00000000000..d2458abfce9 --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/accesslog-types.yaml @@ -0,0 +1,184 @@ +accessLog: + als: + - destination: + name: accesslog_als_0_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logType: Route + name: accesslog + text: | + this is a route log + type: HTTP + - destination: + name: accesslog_als_0_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + logType: Route + name: envoy-gateway-system/test + text: | + this is a route log + type: TCP + - destination: + name: accesslog_als_1_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logType: Listener + name: accesslog + text: | + this is a listener log + type: HTTP + - destination: + name: accesslog_als_1_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + logType: Listener + name: envoy-gateway-system/test + text: | + this is a listener log + type: TCP + - destination: + name: accesslog_als_2_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + name: accesslog + text: | + this is a Global log + type: HTTP + - destination: + name: accesslog_als_2_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + name: envoy-gateway-system/test + text: | + this is a Global log + type: TCP + openTelemetry: + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_0_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + logType: Route + resources: + k8s.cluster.name: cluster-1 + text: | + this is a route log + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_1_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + logType: Listener + resources: + k8s.cluster.name: cluster-1 + text: | + this is a listener log + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_2_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + resources: + k8s.cluster.name: cluster-1 + text: | + this is a Global log + text: + - logType: Route + path: /dev/stdout + - logType: Listener + path: /dev/stdout + - format: | + this is a route log + logType: Route + path: /dev/stdout + - format: | + this is a listener log + logType: Listener + path: /dev/stdout + - format: | + this is a Global log + path: /dev/stdout +http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + 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/out/xds-ir/accesslog-types.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.clusters.yaml new file mode 100644 index 00000000000..e0328b6e26c --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.clusters.yaml @@ -0,0 +1,263 @@ +- 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 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_0_1 + lbPolicy: LEAST_REQUEST + name: accesslog_als_0_1 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_0_2 + lbPolicy: LEAST_REQUEST + name: accesslog_als_0_2 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_1_1 + lbPolicy: LEAST_REQUEST + name: accesslog_als_1_1 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_1_2 + lbPolicy: LEAST_REQUEST + name: accesslog_als_1_2 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_2_1 + lbPolicy: LEAST_REQUEST + name: accesslog_als_2_1 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_2_2 + lbPolicy: LEAST_REQUEST + name: accesslog_als_2_2 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + dnsRefreshRate: 30s + lbPolicy: LEAST_REQUEST + loadAssignment: + clusterName: accesslog_otel_0_3 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: otel-collector.monitoring.svc.cluster.local + portValue: 4317 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_otel_0_3/backend/0 + name: accesslog_otel_0_3 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + dnsRefreshRate: 30s + lbPolicy: LEAST_REQUEST + loadAssignment: + clusterName: accesslog_otel_1_3 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: otel-collector.monitoring.svc.cluster.local + portValue: 4317 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_otel_1_3/backend/0 + name: accesslog_otel_1_3 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + dnsRefreshRate: 30s + lbPolicy: LEAST_REQUEST + loadAssignment: + clusterName: accesslog_otel_2_3 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: otel-collector.monitoring.svc.cluster.local + portValue: 4317 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_otel_2_3/backend/0 + name: accesslog_otel_2_3 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-types.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.endpoints.yaml new file mode 100644 index 00000000000..e9526ab5d90 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.endpoints.yaml @@ -0,0 +1,84 @@ +- 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 +- clusterName: accesslog_als_0_1 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_0_1/backend/0 +- clusterName: accesslog_als_0_2 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_0_2/backend/0 +- clusterName: accesslog_als_1_1 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_1_1/backend/0 +- clusterName: accesslog_als_1_2 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_1_2/backend/0 +- clusterName: accesslog_als_2_1 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_2_1/backend/0 +- clusterName: accesslog_als_2_2 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_2_2/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-types.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.listeners.yaml new file mode 100644 index 00000000000..dbb30726378 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.listeners.yaml @@ -0,0 +1,300 @@ +- accessLog: + - name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + logFormat: + textFormatSource: + inlineString: | + {"start_time":"%START_TIME%","method":"%REQ(:METHOD)%","x-envoy-origin-path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","response_code_details":"%RESPONSE_CODE_DETAILS%","connection_termination_details":"%CONNECTION_TERMINATION_DETAILS%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration":"%DURATION%","x-envoy-upstream-service-time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","x-forwarded-for":"%REQ(X-FORWARDED-FOR)%","user-agent":"%REQ(USER-AGENT)%","x-request-id":"%REQ(X-REQUEST-ID)%",":authority":"%REQ(:AUTHORITY)%","upstream_host":"%UPSTREAM_HOST%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","requested_server_name":"%REQUESTED_SERVER_NAME%","route_name":"%ROUTE_NAME%"} + path: /dev/stdout + - name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + logFormat: + textFormatSource: + inlineString: | + this is a listener log + 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: + textFormatSource: + inlineString: | + this is a Global log + path: /dev/stdout + - name: envoy.access_loggers.http_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig + additionalRequestHeadersToLog: + - x-client-ip-address + additionalResponseHeadersToLog: + - cache-control + additionalResponseTrailersToLog: + - expires + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_1_1 + logName: accesslog + transportApiVersion: V3 + - name: envoy.access_loggers.tcp_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.TcpGrpcAccessLogConfig + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_1_2 + logName: envoy-gateway-system/test + transportApiVersion: V3 + - filter: + responseFlagFilter: + flags: + - NR + name: envoy.access_loggers.http_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig + additionalRequestHeadersToLog: + - x-client-ip-address + additionalResponseHeadersToLog: + - cache-control + additionalResponseTrailersToLog: + - expires + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_2_1 + logName: accesslog + transportApiVersion: V3 + - filter: + responseFlagFilter: + flags: + - NR + name: envoy.access_loggers.tcp_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.TcpGrpcAccessLogConfig + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_2_2 + logName: envoy-gateway-system/test + transportApiVersion: V3 + - 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)%' + body: + stringValue: | + this is a listener log + commonConfig: + grpcService: + envoyGrpc: + authority: otel-collector.monitoring.svc.cluster.local + clusterName: accesslog_otel_1_3 + logName: otel_envoy_accesslog + transportApiVersion: V3 + resourceAttributes: + values: + - key: k8s.cluster.name + value: + stringValue: cluster-1 + - 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)%' + body: + stringValue: | + this is a Global log + commonConfig: + grpcService: + envoyGrpc: + authority: otel-collector.monitoring.svc.cluster.local + clusterName: accesslog_otel_2_3 + logName: otel_envoy_accesslog + transportApiVersion: V3 + resourceAttributes: + values: + - key: k8s.cluster.name + value: + stringValue: cluster-1 + 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":"%START_TIME%","method":"%REQ(:METHOD)%","x-envoy-origin-path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","response_code_details":"%RESPONSE_CODE_DETAILS%","connection_termination_details":"%CONNECTION_TERMINATION_DETAILS%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration":"%DURATION%","x-envoy-upstream-service-time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","x-forwarded-for":"%REQ(X-FORWARDED-FOR)%","user-agent":"%REQ(USER-AGENT)%","x-request-id":"%REQ(X-REQUEST-ID)%",":authority":"%REQ(:AUTHORITY)%","upstream_host":"%UPSTREAM_HOST%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","requested_server_name":"%REQUESTED_SERVER_NAME%","route_name":"%ROUTE_NAME%"} + path: /dev/stdout + - name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + logFormat: + textFormatSource: + inlineString: | + this is a route log + path: /dev/stdout + - name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + logFormat: + textFormatSource: + inlineString: | + this is a Global log + path: /dev/stdout + - name: envoy.access_loggers.http_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig + additionalRequestHeadersToLog: + - x-client-ip-address + additionalResponseHeadersToLog: + - cache-control + additionalResponseTrailersToLog: + - expires + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_0_1 + logName: accesslog + transportApiVersion: V3 + - name: envoy.access_loggers.tcp_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.TcpGrpcAccessLogConfig + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_0_2 + logName: envoy-gateway-system/test + transportApiVersion: V3 + - name: envoy.access_loggers.http_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig + additionalRequestHeadersToLog: + - x-client-ip-address + additionalResponseHeadersToLog: + - cache-control + additionalResponseTrailersToLog: + - expires + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_2_1 + logName: accesslog + transportApiVersion: V3 + - name: envoy.access_loggers.tcp_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.TcpGrpcAccessLogConfig + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_2_2 + logName: envoy-gateway-system/test + transportApiVersion: V3 + - 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)%' + body: + stringValue: | + this is a route log + commonConfig: + grpcService: + envoyGrpc: + authority: otel-collector.monitoring.svc.cluster.local + clusterName: accesslog_otel_0_3 + logName: otel_envoy_accesslog + transportApiVersion: V3 + resourceAttributes: + values: + - key: k8s.cluster.name + value: + stringValue: cluster-1 + - 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)%' + body: + stringValue: | + this is a Global log + commonConfig: + grpcService: + envoyGrpc: + authority: otel-collector.monitoring.svc.cluster.local + clusterName: accesslog_otel_2_3 + logName: otel_envoy_accesslog + transportApiVersion: V3 + resourceAttributes: + values: + - key: k8s.cluster.name + value: + stringValue: cluster-1 + 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: envoy-gateway/gateway-1/http + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10080 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http + name: envoy-gateway/gateway-1/http + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-types.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.routes.yaml new file mode 100644 index 00000000000..ff2210f8d50 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.routes.yaml @@ -0,0 +1,20 @@ +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http + virtualHosts: + - domains: + - '*' + metadata: + filterMetadata: + envoy-gateway: + resources: + - kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http/* + routes: + - directResponse: + status: 500 + match: + prefix: / + name: direct-route diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index bc01189920d..c26a8c713f8 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -2995,6 +2995,7 @@ _Appears in:_ | `format` | _[ProxyAccessLogFormat](#proxyaccesslogformat)_ | false | Format defines the format of accesslog.
This will be ignored if sink type is ALS. | | `matches` | _string array_ | true | Matches defines the match conditions for accesslog in CEL expression.
An accesslog will be emitted only when one or more match conditions are evaluated to true.
Invalid [CEL](https://www.envoyproxy.io/docs/envoy/latest/xds/type/v3/cel.proto.html#common-expression-language-cel-proto) expressions will be ignored. | | `sinks` | _[ProxyAccessLogSink](#proxyaccesslogsink) array_ | true | Sinks defines the sinks of accesslog. | +| `type` | _[ProxyAccessLogType](#proxyaccesslogtype)_ | false | Type defines the component emitting the accesslog, such as Listener and Route.
If type not defined, the setting would apply to:
(1) All Routes.
(2) Listeners if and only if Envoy does not find a matching route for a request.
If type is defined, the accesslog settings would apply to the relevant component (as-is). | #### ProxyAccessLogSink diff --git a/site/content/en/latest/tasks/observability/proxy-accesslog.md b/site/content/en/latest/tasks/observability/proxy-accesslog.md index fb0200f1739..17d444b8636 100644 --- a/site/content/en/latest/tasks/observability/proxy-accesslog.md +++ b/site/content/en/latest/tasks/observability/proxy-accesslog.md @@ -249,3 +249,62 @@ Envoy Gateway provides additional metadata about the K8s resources that were tra For example, details about the `HTTPRoute` and `GRPCRoute` (kind, group, name, namespace and annotations) are available for access log formatter using the `METADATA` operator. To enrich logs, users can add log operator such as: `%METADATA(ROUTE:envoy-gateway:resources)%` to their access log format. + +## Access Log Types + +By default, Access Log settings would apply to: +- All Routes +- If traffic is not matched by any Route known to Envoy, the Listener would emit the access log instead + +Users may wish to customize this behavior: +- Emit Access Logs by all Listeners for all traffic with specific settings +- Do not emit Route-oriented access logs when a route is not matched. + +To achieve this, users can select if Access Log settings follow the default behavior or apply specifically to +Routes or Listeners by specifying the setting's type. + +**Note**: When users define their own Access Log settings (with or without a type), the default Envoy Gateway +file access log is no longer configured. It can be re-enabled explicitly by adding empty settings for the desired components. + +In the following example: +- Route Access logs would use the default Envoy Gateway format and sink +- Listener Access logs are customized to report transport-level failures and connection attributes + +```shell +kubectl apply -f - <This will be ignored if sink type is ALS. | | `matches` | _string array_ | true | Matches defines the match conditions for accesslog in CEL expression.
An accesslog will be emitted only when one or more match conditions are evaluated to true.
Invalid [CEL](https://www.envoyproxy.io/docs/envoy/latest/xds/type/v3/cel.proto.html#common-expression-language-cel-proto) expressions will be ignored. | | `sinks` | _[ProxyAccessLogSink](#proxyaccesslogsink) array_ | true | Sinks defines the sinks of accesslog. | +| `type` | _[ProxyAccessLogType](#proxyaccesslogtype)_ | false | Type defines the component emitting the accesslog, such as Listener and Route.
If type not defined, the setting would apply to:
(1) All Routes.
(2) Listeners if and only if Envoy does not find a matching route for a request.
If type is defined, the accesslog settings would apply to the relevant component (as-is). | #### ProxyAccessLogSink diff --git a/test/config/gatewayclass.yaml b/test/config/gatewayclass.yaml index fa07a159305..6e8acf3d0f8 100644 --- a/test/config/gatewayclass.yaml +++ b/test/config/gatewayclass.yaml @@ -68,6 +68,15 @@ spec: namespace: monitoring port: 8080 type: HTTP + - type: Listener + format: + type: Text + text: | + LISTENER ACCESS LOG %UPSTREAM_PROTOCOL% %RESPONSE_CODE% + sinks: + - type: File + file: + path: /dev/stdout tracing: provider: backendRefs: diff --git a/test/e2e/tests/accesslog.go b/test/e2e/tests/accesslog.go index 2019d92568c..b2c9a28ac94 100644 --- a/test/e2e/tests/accesslog.go +++ b/test/e2e/tests/accesslog.go @@ -81,6 +81,38 @@ var FileAccessLogTest = suite.ConformanceTest{ runLogTest(t, suite, gwAddr, expectedResponse, labels, match, 0) }) + + t.Run("Listener Logs", func(t *testing.T) { + // Ensure that Listener is emitting the log: protocol and response code should be + // empty in listener logs as they are upstream L7 attributes + expectedMatch := "LISTENER ACCESS LOG - 0" + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "accesslog-file", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + + expectedResponse := httputils.ExpectedResponse{ + Request: httputils.Request{ + Path: "/file", + Headers: map[string]string{ + "connection": "close", + }, + }, + ExpectedRequest: &httputils.ExpectedRequest{ + Request: httputils.Request{ + Path: "/file", + }, + }, + Response: httputils.Response{ + StatusCode: 200, + }, + Namespace: ns, + } + // make sure listener is ready + httputils.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectedResponse) + + runLogTest(t, suite, gwAddr, expectedResponse, labels, expectedMatch, 0) + }) }, }