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) }