diff --git a/pkg/resources/collector/logging.go b/pkg/resources/collector/logging.go index 724023c1c1..51f9356d4e 100644 --- a/pkg/resources/collector/logging.go +++ b/pkg/resources/collector/logging.go @@ -2,6 +2,9 @@ package collector import ( "bytes" + "fmt" + "path/filepath" + "strings" opniloggingv1beta1 "github.com/rancher/opni/apis/logging/v1beta1" corev1 "k8s.io/api/core/v1" @@ -43,19 +46,22 @@ func (r *Reconciler) generateDistributionReceiver(config *opniloggingv1beta1.Col } func (r *Reconciler) generateKubeAuditLogsReceiver(config *opniloggingv1beta1.CollectorConfig) (string, []byte, error) { + var receiver bytes.Buffer + if config.Spec.KubeAuditLogs != nil && config.Spec.KubeAuditLogs.Enabled { - auditLogPath := "/var/log/kube-audit" + filelogDir := "/var/log/kube-audit" + if config.Spec.KubeAuditLogs.LogPath != "" { - auditLogPath = config.Spec.KubeAuditLogs.LogPath + filelogDir = config.Spec.KubeAuditLogs.LogPath } - var receiver bytes.Buffer - err := templateKubeAuditLogs.Execute(&receiver, auditLogPath) + fileGlobPatterns := generateFileGlobPatterns(filelogDir, kubeAuditLogsFileTypes) + err := templateKubeAuditLogs.Execute(&receiver, fileGlobPatterns) if err != nil { return "", nil, err } - return logReceiverKubeAudit, receiver.Bytes(), nil + return logReceiverKubeAuditLogs, receiver.Bytes(), nil } return "", nil, nil @@ -216,3 +222,24 @@ func (r *Reconciler) hostLoggingVolumes() ( } return } + +// generateFileGlobPattern generates a file glob pattern based on the provided path and file type. +// If the path doesn't end with a slash, it appends one before constructing the pattern. +// +// path is the base path for the file glob pattern. fileType is the desired file types to match, +// e.g., [".log", ".json"]. +// +// It returns a single string of the format "[ /foo/*.log, /bar/*.json ]". +func generateFileGlobPatterns(path string, fileTypes []string) string { + if len(path) > 0 && path[len(path)-1] != '/' { + path += "/" + } + + var patterns []string + for _, fileType := range fileTypes { + pattern := filepath.Join(path, fmt.Sprintf("*%s", fileType)) + patterns = append(patterns, pattern) + } + + return fmt.Sprintf("[%s]", strings.Join(patterns, ",")) +} diff --git a/pkg/resources/collector/templates.go b/pkg/resources/collector/templates.go index a55f02248f..41a65b3234 100644 --- a/pkg/resources/collector/templates.go +++ b/pkg/resources/collector/templates.go @@ -5,12 +5,12 @@ import ( ) const ( - logReceiverK8s = "filelog/k8s" - logReceiverKubeAudit = "filelog/kubeauditlogs" - logReceiverRKE = "filelog/rke" - logReceiverK3s = "journald/k3s" - logReceiverRKE2 = "journald/rke2" - fileLogReceiverRKE2 = "filelog/rke2" + logReceiverK8s = "filelog/k8s" + logReceiverKubeAuditLogs = "filelog/kubeauditlogs" + logReceiverRKE = "filelog/rke" + logReceiverK3s = "journald/k3s" + logReceiverRKE2 = "journald/rke2" + fileLogReceiverRKE2 = "filelog/rke2" ) var ( @@ -105,20 +105,50 @@ journald/k3s: templateKubeAuditLogs = template.Must(template.New("kubeauditlogsreceiver").Parse(` filelog/kubeauditlogs: - include: [ /var/log/kube-audit/*.log ] + include: {{ . }} start_at: beginning include_file_path: false include_file_name: false operators: - type: json_parser id: parse-body + timestamp: + parse_from: attributes.stageTimestamp + layout: '%Y-%m-%dT%H:%M:%S.%LZ' - type: add field: attributes.log_type value: controlplane - type: add field: attributes.kubernetes_component - value: apiserver + value: kubeauditlogs + - type: move + from: attributes.stage + to: resource["k8s.auditlog.stage"] + - type: move + from: attributes.stageTimestamp + to: resource["k8s.auditlog.stage_timestamp"] + - type: move + from: attributes.level + to: resource["k8s.auditlog.level"] + - type: move + from: attributes.auditID + to: resource["k8s.auditlog.audit_id"] + - type: move + from: attributes.objectRef.resource + to: resource["k8s.auditlog.resource"] + - type: retain + fields: + - attributes.stage + - attributes.stageTimestamp + - attributes.level + - attributes.auditID + - attributes.objectRef.resource + - attributes.cluster_id + - attributes.time + - attributes.log + - attributes.log_type `)) + templateLogAgentRKE2 = template.Must(template.New("rke2receiver").Parse(` journald/rke2: units: @@ -181,6 +211,16 @@ processors: name: k8s.pod.name - from: resource_attribute name: k8s.namespace.name + - from: resource_attribute + name: k8s.auditlog.stage + - from: resource_attribute + name: k8s.auditlog.stage_timestamp + - from: resource_attribute + name: k8s.auditlog.level + - from: resource_attribute + name: k8s.auditlog.audit_id + - from: resource_attribute + name: k8s.auditlog.resource - sources: - from: connection extract: diff --git a/pkg/resources/collector/workloads.go b/pkg/resources/collector/workloads.go index 8b805531d2..827df5cf55 100644 --- a/pkg/resources/collector/workloads.go +++ b/pkg/resources/collector/workloads.go @@ -40,6 +40,8 @@ const ( var ( directoryOrCreate = corev1.HostPathDirectoryOrCreate + + kubeAuditLogsFileTypes = []string{".log", ".json"} ) func (r *Reconciler) agentConfigMapName() string { @@ -80,7 +82,7 @@ func (r *Reconciler) receiverConfig() (retData []byte, retReceivers []string, re retData = append(retData, []byte(templateLogAgentK8sReceiver)...) retReceivers = append(retReceivers, logReceiverK8s) - config, err := r.fetchCollectorConfig() + config, err := r.fetchLoggingCollectorConfig() if err != nil { retErr = err return @@ -579,7 +581,7 @@ func (r *Reconciler) configReloaderImageSpec() opnimeta.ImageSpec { }.Resolve() } -func (r *Reconciler) fetchCollectorConfig() (*opniloggingv1beta1.CollectorConfig, error) { +func (r *Reconciler) fetchLoggingCollectorConfig() (*opniloggingv1beta1.CollectorConfig, error) { config := &opniloggingv1beta1.CollectorConfig{} err := r.client.Get(r.ctx, types.NamespacedName{ Name: r.collector.Spec.LoggingConfig.Name,