104 lines
2.4 KiB
Go
104 lines
2.4 KiB
Go
package journal
|
|
|
|
import (
|
|
"net"
|
|
"slices"
|
|
"sync"
|
|
)
|
|
|
|
const (
|
|
// WellKnownSocketPath is where we generally expect to find the systemd
|
|
// journal daemon's socket.
|
|
WellKnownSocketPath = "/run/systemd/journal/socket"
|
|
)
|
|
|
|
// Conn represents an active, open connection to the systemd journal that is
|
|
// ready to write log entries.
|
|
type Conn struct {
|
|
// Common attributes which are emitted for all messages.
|
|
Common []Attr
|
|
|
|
// ErrHandler is called if there is an error writing to the log. If nil,
|
|
// the error is silently discarded.
|
|
ErrHandler func(error)
|
|
|
|
s *net.UnixConn
|
|
bufs sync.Pool
|
|
atts sync.Pool
|
|
}
|
|
|
|
// Connect to the systemd journal. If the path string is empty, then it uses the
|
|
// well-known socket path.
|
|
func Connect(path string) (*Conn, error) {
|
|
if path == "" {
|
|
path = WellKnownSocketPath
|
|
}
|
|
|
|
s, err := net.DialUnix("unixgram", nil, &net.UnixAddr{
|
|
Name: path,
|
|
Net: "unixgram",
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c := &Conn{
|
|
s: s,
|
|
bufs: sync.Pool{
|
|
New: func() any {
|
|
return &net.Buffers{}
|
|
},
|
|
},
|
|
}
|
|
c.atts = sync.Pool{
|
|
New: func() any {
|
|
return make([]Attr, 0, 2+len(c.Common))
|
|
},
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
var messageAttrKey = AttrKey{key: "MESSAGE"}
|
|
|
|
// Entry emits a log entry. It will add PRIORITY and MESSAGE key/value pairs
|
|
// as well as any Common attributes.
|
|
func (c *Conn) Entry(pri Priority, msg string, attrs []Attr) {
|
|
err := c.EntryErr(pri, msg, attrs)
|
|
switch {
|
|
case err == nil:
|
|
return
|
|
case c.ErrHandler == nil:
|
|
return
|
|
default:
|
|
c.ErrHandler(err)
|
|
}
|
|
}
|
|
|
|
// EntryErr is like Entry, but will propagate errors to the caller, rather than
|
|
// using the built-in error handler.
|
|
func (c *Conn) EntryErr(pri Priority, msg string, attrs []Attr) error {
|
|
a := c.atts.Get().([]Attr)
|
|
a = slices.Grow(a[:0], 2+len(c.Common)+len(attrs))
|
|
a = append(a, pri.Attr(), Attr{
|
|
Key: messageAttrKey,
|
|
Value: []byte(msg),
|
|
})
|
|
a = append(a, c.Common...)
|
|
a = append(a, attrs...)
|
|
err := c.WriteAttrs(a)
|
|
slices.Delete(a, 0, len(a)) // ensure GC doesn't see refs to old data
|
|
c.atts.Put(a)
|
|
return err
|
|
}
|
|
|
|
// WriteAttrs is a low-level method which writes a journal entry comprised of
|
|
// only the given set of attributes.
|
|
func (c *Conn) WriteAttrs(attrs []Attr) error {
|
|
buf := c.bufs.Get().(*net.Buffers)
|
|
*buf = (*buf)[:0]
|
|
err := WireWrite(buf, c.s, attrs)
|
|
slices.Delete(*buf, 0, len(*buf)) // ensure GC doesn't see refs to old data
|
|
c.bufs.Put(buf)
|
|
return err
|
|
}
|