feat(go): advance validation sidecar toward production
This commit is contained in:
parent
6a06eba255
commit
f85c2e831a
92 changed files with 8881 additions and 91 deletions
87
go-agent/internal/eventlog/read.go
Normal file
87
go-agent/internal/eventlog/read.go
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package eventlog
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
const maxRecordBytes = 1 << 20
|
||||
|
||||
// ReadRecent returns at most limit records in chronological order, reading the
|
||||
// older rotated segment before the active file. Every returned row is valid
|
||||
// JSON; corruption is reported instead of passed to an operator as evidence.
|
||||
func ReadRecent(path string, limit int) ([][]byte, error) {
|
||||
if path == "" {
|
||||
return nil, fmt.Errorf("event log path is required")
|
||||
}
|
||||
if limit <= 0 {
|
||||
return nil, fmt.Errorf("event limit must be positive")
|
||||
}
|
||||
buffer := recentBuffer{limit: limit}
|
||||
if _, err := os.Stat(path + ".1"); err == nil {
|
||||
if err := scanRecords(path+".1", buffer.add); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("stat rotated event log: %w", err)
|
||||
}
|
||||
if err := scanRecords(path, buffer.add); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buffer.values(), nil
|
||||
}
|
||||
|
||||
func scanRecords(path string, consume func([]byte)) error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open event log %s: %w", path, err)
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner.Buffer(make([]byte, 64*1024), maxRecordBytes)
|
||||
line := 0
|
||||
for scanner.Scan() {
|
||||
line++
|
||||
raw := scanner.Bytes()
|
||||
if len(raw) == 0 {
|
||||
continue
|
||||
}
|
||||
if !json.Valid(raw) {
|
||||
return fmt.Errorf("invalid JSON in %s at line %d", path, line)
|
||||
}
|
||||
consume(append([]byte(nil), raw...))
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return fmt.Errorf("read event log %s: %w", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type recentBuffer struct {
|
||||
limit int
|
||||
rows [][]byte
|
||||
next int
|
||||
}
|
||||
|
||||
func (b *recentBuffer) add(raw []byte) {
|
||||
if len(b.rows) < b.limit {
|
||||
b.rows = append(b.rows, raw)
|
||||
return
|
||||
}
|
||||
b.rows[b.next] = raw
|
||||
b.next = (b.next + 1) % b.limit
|
||||
}
|
||||
|
||||
func (b *recentBuffer) values() [][]byte {
|
||||
if len(b.rows) < b.limit || b.next == 0 {
|
||||
return b.rows
|
||||
}
|
||||
result := make([][]byte, 0, len(b.rows))
|
||||
result = append(result, b.rows[b.next:]...)
|
||||
result = append(result, b.rows[:b.next]...)
|
||||
return result
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue