journal/global.go

128 lines
2.9 KiB
Go

package journal
import (
"errors"
"fmt"
"os"
"sync"
"time"
)
var (
global *Conn
globalLock sync.Mutex
globalCommon []Attr
globalErrHandler func(error)
globalRateLimit time.Time
errGlobalBackoff = errors.New("journal unavailable; retrying after 30s")
)
const (
globalConnectRetry = 30 * time.Second
)
// CheckConnection returns nil if the connection to the journal is OK, or an
// error otherwise. It will attempt to establish a connection to the journal
// if there is not already one in progress.
func CheckConnection() error {
_, err := getGlobal()
return err
}
// SetGlobalConn can be used to override the default connection to the journal
// that is used by the global logging functions (the ones which do not directly
// operate on a Conn).
func SetGlobalConn(c *Conn) {
globalLock.Lock()
defer globalLock.Unlock()
global = c
}
func getGlobal() (*Conn, error) {
globalLock.Lock()
defer globalLock.Unlock()
// if already connected, return
if global != nil {
return global, nil
}
// rate limit new connections
if time.Now().Before(globalRateLimit) {
return nil, errGlobalBackoff
}
// attempt a new connection
var err error
global, err = Connect(WellKnownSocketPath)
if err != nil {
fmt.Fprintln(os.Stderr, "[journal] failed to connect:", err)
globalRateLimit = time.Now().Add(globalConnectRetry)
return nil, err
}
global.Common = globalCommon
if globalErrHandler != nil {
global.ErrHandler = globalErrHandler
} else {
global.ErrHandler = newDefaultGlobalErrHandler()
}
return global, nil
}
func newDefaultGlobalErrHandler() func(error) {
var errHandlerOnce sync.Once
return func(err error) {
errHandlerOnce.Do(func() {
fmt.Fprintln(os.Stderr, "[journal] failed to write entry:", err)
globalLock.Lock()
defer globalLock.Unlock()
if global != nil {
global.s.Close()
global = nil
globalRateLimit = time.Now().Add(globalConnectRetry)
}
})
}
}
// SetGlobalCommonAttr sets common attributes which will be added to every entry
// sent through the global connection.
func SetGlobalCommonAttr(attr []Attr) {
globalLock.Lock()
defer globalLock.Unlock()
globalCommon = attr
if global != nil {
global.Common = attr
}
}
// SetGlobalErrHandler allows overriding the default error handler that is
// called when the connection fails. The default will attempt to reconnect
// to the journal socket after a short delay.
func SetGlobalErrHandler(errHandler func(err error)) {
globalLock.Lock()
defer globalLock.Unlock()
globalErrHandler = errHandler
if global != nil {
global.ErrHandler = errHandler
}
}
// Entry writes a journal entry via the global connection. It will establish
// a connection as necessary.
//
// Note: to avoid allocation / garbage, ensure attrs has capacity for an extra
// 2+len(GlobalCommonAttr) values.
func Entry(pri Priority, msg string, attrs []Attr) {
c, _ := getGlobal()
if c == nil {
return
}
c.Entry(pri, msg, attrs)
}