github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/daemon/logs.go (about)

     1  package daemon
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/Sirupsen/logrus"
    10  	"github.com/docker/docker/daemon/logger"
    11  	"github.com/docker/docker/pkg/stdcopy"
    12  )
    13  
    14  // ContainerLogsConfig holds configs for logging operations. Exists
    15  // for users of the daemon to to pass it a logging configuration.
    16  type ContainerLogsConfig struct {
    17  	// if true stream log output
    18  	Follow bool
    19  	// if true include timestamps for each line of log output
    20  	Timestamps bool
    21  	// return that many lines of log output from the end
    22  	Tail string
    23  	// filter logs by returning on those entries after this time
    24  	Since time.Time
    25  	// whether or not to show stdout and stderr as well as log entries.
    26  	UseStdout, UseStderr bool
    27  	OutStream            io.Writer
    28  	Stop                 <-chan bool
    29  }
    30  
    31  // ContainerLogs hooks up a container's stdout and stderr streams
    32  // configured with the given struct.
    33  func (daemon *Daemon) ContainerLogs(container *Container, config *ContainerLogsConfig) error {
    34  	if !(config.UseStdout || config.UseStderr) {
    35  		return fmt.Errorf("You must choose at least one stream")
    36  	}
    37  
    38  	outStream := config.OutStream
    39  	errStream := outStream
    40  	if !container.Config.Tty {
    41  		errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
    42  		outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
    43  	}
    44  	config.OutStream = outStream
    45  
    46  	cLog, err := container.getLogger()
    47  	if err != nil {
    48  		return err
    49  	}
    50  	logReader, ok := cLog.(logger.LogReader)
    51  	if !ok {
    52  		return logger.ErrReadLogsNotSupported
    53  	}
    54  
    55  	follow := config.Follow && container.IsRunning()
    56  	tailLines, err := strconv.Atoi(config.Tail)
    57  	if err != nil {
    58  		tailLines = -1
    59  	}
    60  
    61  	logrus.Debug("logs: begin stream")
    62  	readConfig := logger.ReadConfig{
    63  		Since:  config.Since,
    64  		Tail:   tailLines,
    65  		Follow: follow,
    66  	}
    67  	logs := logReader.ReadLogs(readConfig)
    68  
    69  	for {
    70  		select {
    71  		case err := <-logs.Err:
    72  			logrus.Errorf("Error streaming logs: %v", err)
    73  			return nil
    74  		case <-config.Stop:
    75  			logs.Close()
    76  			return nil
    77  		case msg, ok := <-logs.Msg:
    78  			if !ok {
    79  				logrus.Debugf("logs: end stream")
    80  				return nil
    81  			}
    82  			logLine := msg.Line
    83  			if config.Timestamps {
    84  				logLine = append([]byte(msg.Timestamp.Format(logger.TimeFormat)+" "), logLine...)
    85  			}
    86  			if msg.Source == "stdout" && config.UseStdout {
    87  				outStream.Write(logLine)
    88  			}
    89  			if msg.Source == "stderr" && config.UseStderr {
    90  				errStream.Write(logLine)
    91  			}
    92  		}
    93  	}
    94  }