Initial MVP commit
This commit is contained in:
commit
7bcf16a1d4
24 changed files with 2781 additions and 0 deletions
journald
114
journald/journald.go
Normal file
114
journald/journald.go
Normal file
|
@ -0,0 +1,114 @@
|
|||
package journald
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"iter"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-systemd/v22/sdjournal"
|
||||
)
|
||||
|
||||
func syslogMatchData(syslogIdentifier string) string {
|
||||
builder := strings.Builder{}
|
||||
|
||||
builder.WriteString(sdjournal.SD_JOURNAL_FIELD_SYSLOG_IDENTIFIER)
|
||||
builder.WriteString("=")
|
||||
builder.WriteString(syslogIdentifier)
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
type Journald struct {
|
||||
journal *sdjournal.Journal
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func NewJournald(syslogName string) (*Journald, error) {
|
||||
journal, err := sdjournal.NewJournal()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize journal: %w", err)
|
||||
}
|
||||
|
||||
if syslogName != "" {
|
||||
matchData := syslogMatchData(syslogName)
|
||||
err = journal.AddMatch(matchData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add match %s to journal: %w", matchData, err)
|
||||
}
|
||||
}
|
||||
|
||||
err = journal.SeekTail()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to seek to tail: %w", err)
|
||||
}
|
||||
|
||||
_, err = journal.Previous()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to go to tail message: %w", err)
|
||||
}
|
||||
|
||||
return &Journald{
|
||||
journal: journal,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (j *Journald) Close() error {
|
||||
err := j.journal.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to close journal: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *Journald) Next() (*sdjournal.JournalEntry, error) {
|
||||
j.lock.Lock()
|
||||
defer j.lock.Unlock()
|
||||
|
||||
entryCount, err := j.journal.Next()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get next journald entry: %w", err)
|
||||
}
|
||||
|
||||
if entryCount == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
entry, err := j.journal.GetEntry()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get journald entry: %w", err)
|
||||
}
|
||||
|
||||
return entry, nil
|
||||
}
|
||||
|
||||
func (j *Journald) Iter(ctx context.Context) iter.Seq2[*sdjournal.JournalEntry, error] {
|
||||
return func(yield func(*sdjournal.JournalEntry, error) bool) {
|
||||
for {
|
||||
j.journal.Wait(time.Second)
|
||||
if ctx.Err() != nil {
|
||||
yield(nil, fmt.Errorf("failed to iterate on journald, context error: %w", ctx.Err()))
|
||||
return
|
||||
}
|
||||
|
||||
entry, err := j.Next()
|
||||
if err != nil {
|
||||
yield(nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
// no more entries at the moment
|
||||
if entry == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// we were told to stop
|
||||
if !yield(entry, nil) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue