logs.go 3.3 KB

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