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  }