github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/runner/logger.go (about) 1 // Copyright 2012-2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package runner 5 6 import ( 7 "bufio" 8 "io" 9 "sync" 10 "time" 11 12 "github.com/juju/loggo" 13 ) 14 15 type hookLogger struct { 16 r io.ReadCloser 17 done chan struct{} 18 mu sync.Mutex 19 stopped bool 20 logger loggo.Logger 21 } 22 23 func (l *hookLogger) run() { 24 defer close(l.done) 25 defer l.r.Close() 26 br := bufio.NewReaderSize(l.r, 4096) 27 for { 28 line, _, err := br.ReadLine() 29 if err != nil { 30 if err != io.EOF { 31 logger.Errorf("cannot read hook output: %v", err) 32 } 33 break 34 } 35 l.mu.Lock() 36 if l.stopped { 37 l.mu.Unlock() 38 return 39 } 40 l.logger.Infof("%s", line) 41 l.mu.Unlock() 42 } 43 } 44 45 func (l *hookLogger) stop() { 46 // We can see the process exit before the logger has processed 47 // all its output, so allow a moment for the data buffered 48 // in the pipe to be processed. We don't wait indefinitely though, 49 // because the hook may have started a background process 50 // that keeps the pipe open. 51 select { 52 case <-l.done: 53 case <-time.After(100 * time.Millisecond): 54 } 55 // We can't close the pipe asynchronously, so just 56 // stifle output instead. 57 l.mu.Lock() 58 l.stopped = true 59 l.mu.Unlock() 60 }