github.com/projectatomic/docker@v1.8.2/daemon/logger/copier.go (about)

     1  package logger
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"io"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/Sirupsen/logrus"
    11  )
    12  
    13  // Copier can copy logs from specified sources to Logger and attach
    14  // ContainerID and Timestamp.
    15  // Writes are concurrent, so you need implement some sync in your logger
    16  type Copier struct {
    17  	// cid is container id for which we copying logs
    18  	cid string
    19  	// srcs is map of name -> reader pairs, for example "stdout", "stderr"
    20  	srcs     map[string]io.Reader
    21  	dst      Logger
    22  	copyJobs sync.WaitGroup
    23  }
    24  
    25  // NewCopier creates new Copier
    26  func NewCopier(cid string, srcs map[string]io.Reader, dst Logger) (*Copier, error) {
    27  	return &Copier{
    28  		cid:  cid,
    29  		srcs: srcs,
    30  		dst:  dst,
    31  	}, nil
    32  }
    33  
    34  // Run starts logs copying
    35  func (c *Copier) Run() {
    36  	for src, w := range c.srcs {
    37  		c.copyJobs.Add(1)
    38  		go c.copySrc(src, w)
    39  	}
    40  }
    41  
    42  func (c *Copier) copySrc(name string, src io.Reader) {
    43  	defer c.copyJobs.Done()
    44  	reader := bufio.NewReader(src)
    45  
    46  	for {
    47  		line, err := reader.ReadBytes('\n')
    48  		line = bytes.TrimSuffix(line, []byte{'\n'})
    49  
    50  		// ReadBytes can return full or partial output even when it failed.
    51  		// e.g. it can return a full entry and EOF.
    52  		if err == nil || len(line) > 0 {
    53  			if logErr := c.dst.Log(&Message{ContainerID: c.cid, Line: line, Source: name, Timestamp: time.Now().UTC()}); logErr != nil {
    54  				logrus.Errorf("Failed to log msg %q for logger %s: %s", line, c.dst.Name(), logErr)
    55  			}
    56  		}
    57  
    58  		if err != nil {
    59  			if err != io.EOF {
    60  				logrus.Errorf("Error scanning log stream: %s", err)
    61  			}
    62  			return
    63  		}
    64  
    65  	}
    66  }
    67  
    68  // Wait waits until all copying is done
    69  func (c *Copier) Wait() {
    70  	c.copyJobs.Wait()
    71  }