128 lines
2.9 KiB
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)
|
|
}
|