120 lines
2.5 KiB
Go
120 lines
2.5 KiB
Go
// +build !nosystemd,linux
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/alecthomas/kingpin"
|
|
"github.com/coreos/go-systemd/v22/sdjournal"
|
|
)
|
|
|
|
// Journal represents a lockable systemd journal.
|
|
type Journal struct {
|
|
*sdjournal.Journal
|
|
sync.Mutex
|
|
Path string
|
|
}
|
|
|
|
// NewJournal returns a Journal for reading journal entries.
|
|
func NewJournal(unit, slice, path string) (j *Journal, err error) {
|
|
j = new(Journal)
|
|
if path != "" {
|
|
j.Journal, err = sdjournal.NewJournalFromDir(path)
|
|
j.Path = path
|
|
} else {
|
|
j.Journal, err = sdjournal.NewJournal()
|
|
j.Path = "journald"
|
|
}
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if slice != "" {
|
|
err = j.AddMatch("_SYSTEMD_SLICE=" + slice)
|
|
if err != nil {
|
|
return
|
|
}
|
|
} else if unit != "" {
|
|
err = j.AddMatch("_SYSTEMD_UNIT=" + unit)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
// Start at end of journal
|
|
err = j.SeekRealtimeUsec(uint64(time.Now().UnixNano() / 1000))
|
|
if err != nil {
|
|
log.Printf("%v", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// NextMessage reads the next message from the journal.
|
|
func (j *Journal) NextMessage() (s string, c uint64, err error) {
|
|
var e *sdjournal.JournalEntry
|
|
|
|
// Read to next
|
|
c, err = j.Next()
|
|
if err != nil {
|
|
return
|
|
}
|
|
// Return when on the end of journal
|
|
if c == 0 {
|
|
return
|
|
}
|
|
|
|
// Get entry
|
|
e, err = j.GetEntry()
|
|
if err != nil {
|
|
return
|
|
}
|
|
ts := time.Unix(0, int64(e.RealtimeTimestamp)*int64(time.Microsecond))
|
|
|
|
// Format entry
|
|
s = fmt.Sprintf(
|
|
"%s %s %s[%s]: %s",
|
|
ts.Format(time.Stamp),
|
|
e.Fields["_HOSTNAME"],
|
|
e.Fields["SYSLOG_IDENTIFIER"],
|
|
e.Fields["_PID"],
|
|
e.Fields["MESSAGE"],
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
// systemdFlags sets the flags for use with systemd
|
|
func systemdFlags(enable *bool, unit, slice, path *string, app *kingpin.Application) {
|
|
app.Flag("systemd.enable", "Read from the systemd journal instead of log").Default("false").BoolVar(enable)
|
|
app.Flag("systemd.unit", "Name of the Postfix systemd unit.").Default("postfix.service").StringVar(unit)
|
|
app.Flag("systemd.slice", "Name of the Postfix systemd slice. Overrides the systemd unit.").Default("").StringVar(slice)
|
|
app.Flag("systemd.journal_path", "Path to the systemd journal").Default("").StringVar(path)
|
|
}
|
|
|
|
// CollectLogfileFromJournal Collects entries from the systemd journal.
|
|
func (e *PostfixExporter) CollectLogfileFromJournal() error {
|
|
e.journal.Lock()
|
|
defer e.journal.Unlock()
|
|
|
|
r := e.journal.Wait(time.Duration(1) * time.Second)
|
|
if r < 0 {
|
|
log.Print("error while waiting for journal!")
|
|
}
|
|
for {
|
|
m, c, err := e.journal.NextMessage()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if c == 0 {
|
|
break
|
|
}
|
|
e.CollectFromLogline(m)
|
|
}
|
|
|
|
return nil
|
|
}
|