github.com/erriapo/docker@v1.6.0-rc2/daemon/logs.go (about)

     1  package daemon
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"strconv"
    10  	"sync"
    11  
    12  	log "github.com/Sirupsen/logrus"
    13  	"github.com/docker/docker/engine"
    14  	"github.com/docker/docker/pkg/jsonlog"
    15  	"github.com/docker/docker/pkg/tailfile"
    16  	"github.com/docker/docker/pkg/timeutils"
    17  )
    18  
    19  func (daemon *Daemon) ContainerLogs(job *engine.Job) engine.Status {
    20  	if len(job.Args) != 1 {
    21  		return job.Errorf("Usage: %s CONTAINER\n", job.Name)
    22  	}
    23  
    24  	var (
    25  		name   = job.Args[0]
    26  		stdout = job.GetenvBool("stdout")
    27  		stderr = job.GetenvBool("stderr")
    28  		tail   = job.Getenv("tail")
    29  		follow = job.GetenvBool("follow")
    30  		times  = job.GetenvBool("timestamps")
    31  		lines  = -1
    32  		format string
    33  	)
    34  	if !(stdout || stderr) {
    35  		return job.Errorf("You must choose at least one stream")
    36  	}
    37  	if times {
    38  		format = timeutils.RFC3339NanoFixed
    39  	}
    40  	if tail == "" {
    41  		tail = "all"
    42  	}
    43  	container, err := daemon.Get(name)
    44  	if err != nil {
    45  		return job.Error(err)
    46  	}
    47  	if container.LogDriverType() != "json-file" {
    48  		return job.Errorf("\"logs\" endpoint is supported only for \"json-file\" logging driver")
    49  	}
    50  	cLog, err := container.ReadLog("json")
    51  	if err != nil && os.IsNotExist(err) {
    52  		// Legacy logs
    53  		log.Debugf("Old logs format")
    54  		if stdout {
    55  			cLog, err := container.ReadLog("stdout")
    56  			if err != nil {
    57  				log.Errorf("Error reading logs (stdout): %s", err)
    58  			} else if _, err := io.Copy(job.Stdout, cLog); err != nil {
    59  				log.Errorf("Error streaming logs (stdout): %s", err)
    60  			}
    61  		}
    62  		if stderr {
    63  			cLog, err := container.ReadLog("stderr")
    64  			if err != nil {
    65  				log.Errorf("Error reading logs (stderr): %s", err)
    66  			} else if _, err := io.Copy(job.Stderr, cLog); err != nil {
    67  				log.Errorf("Error streaming logs (stderr): %s", err)
    68  			}
    69  		}
    70  	} else if err != nil {
    71  		log.Errorf("Error reading logs (json): %s", err)
    72  	} else {
    73  		if tail != "all" {
    74  			var err error
    75  			lines, err = strconv.Atoi(tail)
    76  			if err != nil {
    77  				log.Errorf("Failed to parse tail %s, error: %v, show all logs", tail, err)
    78  				lines = -1
    79  			}
    80  		}
    81  		if lines != 0 {
    82  			if lines > 0 {
    83  				f := cLog.(*os.File)
    84  				ls, err := tailfile.TailFile(f, lines)
    85  				if err != nil {
    86  					return job.Error(err)
    87  				}
    88  				tmp := bytes.NewBuffer([]byte{})
    89  				for _, l := range ls {
    90  					fmt.Fprintf(tmp, "%s\n", l)
    91  				}
    92  				cLog = tmp
    93  			}
    94  			dec := json.NewDecoder(cLog)
    95  			l := &jsonlog.JSONLog{}
    96  			for {
    97  				if err := dec.Decode(l); err == io.EOF {
    98  					break
    99  				} else if err != nil {
   100  					log.Errorf("Error streaming logs: %s", err)
   101  					break
   102  				}
   103  				logLine := l.Log
   104  				if times {
   105  					// format can be "" or time format, so here can't be error
   106  					logLine, _ = l.Format(format)
   107  				}
   108  				if l.Stream == "stdout" && stdout {
   109  					io.WriteString(job.Stdout, logLine)
   110  				}
   111  				if l.Stream == "stderr" && stderr {
   112  					io.WriteString(job.Stderr, logLine)
   113  				}
   114  				l.Reset()
   115  			}
   116  		}
   117  	}
   118  	if follow && container.IsRunning() {
   119  		errors := make(chan error, 2)
   120  		wg := sync.WaitGroup{}
   121  
   122  		if stdout {
   123  			wg.Add(1)
   124  			stdoutPipe := container.StdoutLogPipe()
   125  			defer stdoutPipe.Close()
   126  			go func() {
   127  				errors <- jsonlog.WriteLog(stdoutPipe, job.Stdout, format)
   128  				wg.Done()
   129  			}()
   130  		}
   131  		if stderr {
   132  			wg.Add(1)
   133  			stderrPipe := container.StderrLogPipe()
   134  			defer stderrPipe.Close()
   135  			go func() {
   136  				errors <- jsonlog.WriteLog(stderrPipe, job.Stderr, format)
   137  				wg.Done()
   138  			}()
   139  		}
   140  
   141  		wg.Wait()
   142  		close(errors)
   143  
   144  		for err := range errors {
   145  			if err != nil {
   146  				log.Errorf("%s", err)
   147  			}
   148  		}
   149  
   150  	}
   151  	return engine.StatusOK
   152  }