github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/command/agent/log_writer.go (about) 1 package agent 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 }