github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/logger/log_writer.go (about)

     1  package logger
     2  
     3  import (
     4  	"sync"
     5  )
     6  
     7  // LogHandler interface is used for clients that want to subscribe
     8  // to logs, for example to stream them over an IPC mechanism
     9  type LogHandler interface {
    10  	HandleLog(string)
    11  }
    12  
    13  // LogWriter implements io.Writer so it can be used as a log sink.
    14  // It maintains a circular buffer of logs, and a set of handlers to
    15  // which it can stream the logs to.
    16  type LogWriter struct {
    17  	sync.Mutex
    18  	logs     []string
    19  	index    int
    20  	handlers map[LogHandler]struct{}
    21  }
    22  
    23  // NewLogWriter creates a LogWriter with the given buffer capacity
    24  func NewLogWriter(buf int) *LogWriter {
    25  	return &LogWriter{
    26  		logs:     make([]string, buf),
    27  		index:    0,
    28  		handlers: make(map[LogHandler]struct{}),
    29  	}
    30  }
    31  
    32  // RegisterHandler adds a log handler to receive logs, and sends
    33  // the last buffered logs to the handler
    34  func (l *LogWriter) RegisterHandler(lh LogHandler) {
    35  	l.Lock()
    36  	defer l.Unlock()
    37  
    38  	// Do nothing if already registered
    39  	if _, ok := l.handlers[lh]; ok {
    40  		return
    41  	}
    42  
    43  	// Register
    44  	l.handlers[lh] = struct{}{}
    45  
    46  	// Send the old logs
    47  	if l.logs[l.index] != "" {
    48  		for i := l.index; i < len(l.logs); i++ {
    49  			lh.HandleLog(l.logs[i])
    50  		}
    51  	}
    52  	for i := 0; i < l.index; i++ {
    53  		lh.HandleLog(l.logs[i])
    54  	}
    55  }
    56  
    57  // DeregisterHandler removes a LogHandler and prevents more invocations
    58  func (l *LogWriter) DeregisterHandler(lh LogHandler) {
    59  	l.Lock()
    60  	defer l.Unlock()
    61  	delete(l.handlers, lh)
    62  }
    63  
    64  // Write is used to accumulate new logs
    65  func (l *LogWriter) Write(p []byte) (n int, err error) {
    66  	l.Lock()
    67  	defer l.Unlock()
    68  
    69  	// Strip off newlines at the end if there are any since we store
    70  	// individual log lines in the agent.
    71  	n = len(p)
    72  	if p[n-1] == '\n' {
    73  		p = p[:n-1]
    74  	}
    75  
    76  	l.logs[l.index] = string(p)
    77  	l.index = (l.index + 1) % len(l.logs)
    78  
    79  	for lh := range l.handlers {
    80  		lh.HandleLog(string(p))
    81  	}
    82  	return
    83  }