github.com/psychoss/docker@v1.9.0/daemon/logs.go (about)

     1  package daemon
     2  
     3  import (
     4  	"io"
     5  	"strconv"
     6  	"time"
     7  
     8  	"github.com/Sirupsen/logrus"
     9  	"github.com/docker/docker/daemon/logger"
    10  	derr "github.com/docker/docker/errors"
    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(containerName string, config *ContainerLogsConfig) error {
    34  	container, err := daemon.Get(containerName)
    35  	if err != nil {
    36  		return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
    37  	}
    38  
    39  	if !(config.UseStdout || config.UseStderr) {
    40  		return derr.ErrorCodeNeedStream
    41  	}
    42  
    43  	outStream := config.OutStream
    44  	errStream := outStream
    45  	if !container.Config.Tty {
    46  		errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
    47  		outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
    48  	}
    49  	config.OutStream = outStream
    50  
    51  	cLog, err := container.getLogger()
    52  	if err != nil {
    53  		return err
    54  	}
    55  	logReader, ok := cLog.(logger.LogReader)
    56  	if !ok {
    57  		return logger.ErrReadLogsNotSupported
    58  	}
    59  
    60  	follow := config.Follow && container.IsRunning()
    61  	tailLines, err := strconv.Atoi(config.Tail)
    62  	if err != nil {
    63  		tailLines = -1
    64  	}
    65  
    66  	logrus.Debug("logs: begin stream")
    67  	readConfig := logger.ReadConfig{
    68  		Since:  config.Since,
    69  		Tail:   tailLines,
    70  		Follow: follow,
    71  	}
    72  	logs := logReader.ReadLogs(readConfig)
    73  
    74  	for {
    75  		select {
    76  		case err := <-logs.Err:
    77  			logrus.Errorf("Error streaming logs: %v", err)
    78  			return nil
    79  		case <-config.Stop:
    80  			logs.Close()
    81  			return nil
    82  		case msg, ok := <-logs.Msg:
    83  			if !ok {
    84  				logrus.Debugf("logs: end stream")
    85  				return nil
    86  			}
    87  			logLine := msg.Line
    88  			if config.Timestamps {
    89  				logLine = append([]byte(msg.Timestamp.Format(logger.TimeFormat)+" "), logLine...)
    90  			}
    91  			if msg.Source == "stdout" && config.UseStdout {
    92  				outStream.Write(logLine)
    93  			}
    94  			if msg.Source == "stderr" && config.UseStderr {
    95  				errStream.Write(logLine)
    96  			}
    97  		}
    98  	}
    99  }