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