its been a while
This commit is contained in:
1 parent
ea7470231f
commit
34f13c65e1
47 files changed
+5680
-339
No files matched your search
+1010
-44
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,60 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestApplyNginxAccessParserSetsParsedTimestamp(t *testing.T) {
|
||||
event := NewEvent(time.Date(2026, time.April, 15, 18, 43, 7, 0, time.UTC))
|
||||
event.SourceKind = "file"
|
||||
event.Message = `192.168.2.40 - - [28/Jan/2026:17:43:43 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/8.0"`
|
||||
|
||||
if !applyNginxAccessParser(&event) {
|
||||
t.Fatalf("expected nginx parser to match log line")
|
||||
}
|
||||
|
||||
expected := "2026-01-28T17:43:43Z"
|
||||
if event.Timestamp != expected {
|
||||
t.Fatalf("expected parsed timestamp %s, got %s", expected, event.Timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseJSONTimestampSupportsEpochMillis(t *testing.T) {
|
||||
event := NewEvent(time.Date(2026, time.April, 15, 18, 43, 7, 0, time.UTC))
|
||||
event.SourceKind = "file"
|
||||
event.Message = `{"timestamp":1700000000000,"message":"login event"}`
|
||||
|
||||
if !applyJSONParser(&event) {
|
||||
t.Fatalf("expected json parser to parse payload")
|
||||
}
|
||||
|
||||
expected := time.Unix(1700000000, 0).UTC().Format(time.RFC3339Nano)
|
||||
if event.Timestamp != expected {
|
||||
t.Fatalf("expected parsed timestamp %s, got %s", expected, event.Timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSyslogTimestampHandlesYearRollover(t *testing.T) {
|
||||
now := time.Date(2026, time.January, 1, 0, 0, 30, 0, time.UTC)
|
||||
parsed, ok := parseSyslogTimestamp("Dec 31 23:59:59", now)
|
||||
if !ok {
|
||||
t.Fatalf("expected syslog timestamp to parse")
|
||||
}
|
||||
if parsed.Year() != 2025 {
|
||||
t.Fatalf("expected year rollover to previous year, got %d", parsed.Year())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaybeSetParsedTimestampSkipsJournalAndServiceSources(t *testing.T) {
|
||||
original := "2026-04-15T18:43:07Z"
|
||||
event := Event{
|
||||
Timestamp: original,
|
||||
SourceKind: "service",
|
||||
}
|
||||
|
||||
maybeSetParsedTimestamp(&event, time.Date(2026, time.January, 1, 0, 0, 0, 0, time.UTC))
|
||||
if event.Timestamp != original {
|
||||
t.Fatalf("expected service timestamp to remain unchanged")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ReadOffsets(path string) (map[string]int64, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return map[string]int64{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
out := map[string]int64{}
|
||||
if len(data) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func WriteOffsets(path string, offsets map[string]int64) error {
|
||||
if offsets == nil {
|
||||
offsets = map[string]int64{}
|
||||
}
|
||||
data, err := json.Marshal(offsets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, data, 0o600)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ReadState(path string) (map[string]SourceState, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return map[string]SourceState{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
out := map[string]SourceState{}
|
||||
if len(data) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func WriteState(path string, state map[string]SourceState) error {
|
||||
if state == nil {
|
||||
state = map[string]SourceState{}
|
||||
}
|
||||
data, err := json.Marshal(state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, data, 0o600)
|
||||
}
|
||||
@@ -3,21 +3,42 @@ package logs
|
||||
import "time"
|
||||
|
||||
type Event struct {
|
||||
Timestamp string `json:"timestamp"`
|
||||
Category string `json:"category"`
|
||||
EventType string `json:"event_type"`
|
||||
Unit string `json:"unit,omitempty"`
|
||||
Priority string `json:"priority,omitempty"`
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Principal string `json:"principal,omitempty"`
|
||||
SourceIP string `json:"source_ip,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Raw string `json:"raw,omitempty"`
|
||||
Fields map[string]string `json:"fields,omitempty"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Category string `json:"category"`
|
||||
EventType string `json:"event_type"`
|
||||
SourceKind string `json:"source_kind,omitempty"`
|
||||
SourceName string `json:"source_name,omitempty"`
|
||||
Unit string `json:"unit,omitempty"`
|
||||
Priority string `json:"priority,omitempty"`
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Principal string `json:"principal,omitempty"`
|
||||
SourceIP string `json:"source_ip,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Raw string `json:"raw,omitempty"`
|
||||
Fields map[string]string `json:"fields,omitempty"`
|
||||
}
|
||||
|
||||
func NewEvent(ts time.Time) Event {
|
||||
return Event{Timestamp: ts.UTC().Format(time.RFC3339Nano)}
|
||||
}
|
||||
|
||||
type SourceConfig struct {
|
||||
SourceID string
|
||||
Kind string
|
||||
Name string
|
||||
ServiceUnit string
|
||||
FilePath string
|
||||
Parser string
|
||||
IncludeMatches map[string][]string
|
||||
ExcludeMatches map[string][]string
|
||||
Category string
|
||||
EventType string
|
||||
}
|
||||
|
||||
type SourceState struct {
|
||||
Cursor string `json:"cursor,omitempty"`
|
||||
Offset int64 `json:"offset,omitempty"`
|
||||
Inode uint64 `json:"inode,omitempty"`
|
||||
}
|
||||
Reference in new issue
Block a user