docker_cli_logs_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. package main
  2. import (
  3. "fmt"
  4. "os/exec"
  5. "regexp"
  6. "strconv"
  7. "strings"
  8. "time"
  9. "github.com/docker/docker/pkg/timeutils"
  10. "github.com/go-check/check"
  11. )
  12. // This used to work, it test a log of PageSize-1 (gh#4851)
  13. func (s *DockerSuite) TestLogsContainerSmallerThanPage(c *check.C) {
  14. testLen := 32767
  15. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
  16. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  17. if err != nil {
  18. c.Fatalf("run failed with errors: %s, %v", out, err)
  19. }
  20. cleanedContainerID := strings.TrimSpace(out)
  21. exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
  22. logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
  23. out, _, _, err = runCommandWithStdoutStderr(logsCmd)
  24. if err != nil {
  25. c.Fatalf("failed to log container: %s, %v", out, err)
  26. }
  27. if len(out) != testLen+1 {
  28. c.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
  29. }
  30. deleteContainer(cleanedContainerID)
  31. }
  32. // Regression test: When going over the PageSize, it used to panic (gh#4851)
  33. func (s *DockerSuite) TestLogsContainerBiggerThanPage(c *check.C) {
  34. testLen := 32768
  35. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
  36. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  37. if err != nil {
  38. c.Fatalf("run failed with errors: %s, %v", out, err)
  39. }
  40. cleanedContainerID := strings.TrimSpace(out)
  41. exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
  42. logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
  43. out, _, _, err = runCommandWithStdoutStderr(logsCmd)
  44. if err != nil {
  45. c.Fatalf("failed to log container: %s, %v", out, err)
  46. }
  47. if len(out) != testLen+1 {
  48. c.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
  49. }
  50. deleteContainer(cleanedContainerID)
  51. }
  52. // Regression test: When going much over the PageSize, it used to block (gh#4851)
  53. func (s *DockerSuite) TestLogsContainerMuchBiggerThanPage(c *check.C) {
  54. testLen := 33000
  55. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
  56. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  57. if err != nil {
  58. c.Fatalf("run failed with errors: %s, %v", out, err)
  59. }
  60. cleanedContainerID := strings.TrimSpace(out)
  61. exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
  62. logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
  63. out, _, _, err = runCommandWithStdoutStderr(logsCmd)
  64. if err != nil {
  65. c.Fatalf("failed to log container: %s, %v", out, err)
  66. }
  67. if len(out) != testLen+1 {
  68. c.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
  69. }
  70. deleteContainer(cleanedContainerID)
  71. }
  72. func (s *DockerSuite) TestLogsTimestamps(c *check.C) {
  73. testLen := 100
  74. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen))
  75. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  76. if err != nil {
  77. c.Fatalf("run failed with errors: %s, %v", out, err)
  78. }
  79. cleanedContainerID := strings.TrimSpace(out)
  80. exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
  81. logsCmd := exec.Command(dockerBinary, "logs", "-t", cleanedContainerID)
  82. out, _, _, err = runCommandWithStdoutStderr(logsCmd)
  83. if err != nil {
  84. c.Fatalf("failed to log container: %s, %v", out, err)
  85. }
  86. lines := strings.Split(out, "\n")
  87. if len(lines) != testLen+1 {
  88. c.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
  89. }
  90. ts := regexp.MustCompile(`^.* `)
  91. for _, l := range lines {
  92. if l != "" {
  93. _, err := time.Parse(timeutils.RFC3339NanoFixed+" ", ts.FindString(l))
  94. if err != nil {
  95. c.Fatalf("Failed to parse timestamp from %v: %v", l, err)
  96. }
  97. if l[29] != 'Z' { // ensure we have padded 0's
  98. c.Fatalf("Timestamp isn't padded properly: %s", l)
  99. }
  100. }
  101. }
  102. deleteContainer(cleanedContainerID)
  103. }
  104. func (s *DockerSuite) TestLogsSeparateStderr(c *check.C) {
  105. msg := "stderr_log"
  106. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg))
  107. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  108. if err != nil {
  109. c.Fatalf("run failed with errors: %s, %v", out, err)
  110. }
  111. cleanedContainerID := strings.TrimSpace(out)
  112. exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
  113. logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
  114. stdout, stderr, _, err := runCommandWithStdoutStderr(logsCmd)
  115. if err != nil {
  116. c.Fatalf("failed to log container: %s, %v", out, err)
  117. }
  118. if stdout != "" {
  119. c.Fatalf("Expected empty stdout stream, got %v", stdout)
  120. }
  121. stderr = strings.TrimSpace(stderr)
  122. if stderr != msg {
  123. c.Fatalf("Expected %v in stderr stream, got %v", msg, stderr)
  124. }
  125. deleteContainer(cleanedContainerID)
  126. }
  127. func (s *DockerSuite) TestLogsStderrInStdout(c *check.C) {
  128. msg := "stderr_log"
  129. runCmd := exec.Command(dockerBinary, "run", "-d", "-t", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg))
  130. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  131. if err != nil {
  132. c.Fatalf("run failed with errors: %s, %v", out, err)
  133. }
  134. cleanedContainerID := strings.TrimSpace(out)
  135. exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
  136. logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
  137. stdout, stderr, _, err := runCommandWithStdoutStderr(logsCmd)
  138. if err != nil {
  139. c.Fatalf("failed to log container: %s, %v", out, err)
  140. }
  141. if stderr != "" {
  142. c.Fatalf("Expected empty stderr stream, got %v", stdout)
  143. }
  144. stdout = strings.TrimSpace(stdout)
  145. if stdout != msg {
  146. c.Fatalf("Expected %v in stdout stream, got %v", msg, stdout)
  147. }
  148. deleteContainer(cleanedContainerID)
  149. }
  150. func (s *DockerSuite) TestLogsTail(c *check.C) {
  151. testLen := 100
  152. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen))
  153. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  154. if err != nil {
  155. c.Fatalf("run failed with errors: %s, %v", out, err)
  156. }
  157. cleanedContainerID := strings.TrimSpace(out)
  158. exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
  159. logsCmd := exec.Command(dockerBinary, "logs", "--tail", "5", cleanedContainerID)
  160. out, _, _, err = runCommandWithStdoutStderr(logsCmd)
  161. if err != nil {
  162. c.Fatalf("failed to log container: %s, %v", out, err)
  163. }
  164. lines := strings.Split(out, "\n")
  165. if len(lines) != 6 {
  166. c.Fatalf("Expected log %d lines, received %d\n", 6, len(lines))
  167. }
  168. logsCmd = exec.Command(dockerBinary, "logs", "--tail", "all", cleanedContainerID)
  169. out, _, _, err = runCommandWithStdoutStderr(logsCmd)
  170. if err != nil {
  171. c.Fatalf("failed to log container: %s, %v", out, err)
  172. }
  173. lines = strings.Split(out, "\n")
  174. if len(lines) != testLen+1 {
  175. c.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
  176. }
  177. logsCmd = exec.Command(dockerBinary, "logs", "--tail", "random", cleanedContainerID)
  178. out, _, _, err = runCommandWithStdoutStderr(logsCmd)
  179. if err != nil {
  180. c.Fatalf("failed to log container: %s, %v", out, err)
  181. }
  182. lines = strings.Split(out, "\n")
  183. if len(lines) != testLen+1 {
  184. c.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
  185. }
  186. deleteContainer(cleanedContainerID)
  187. }
  188. func (s *DockerSuite) TestLogsFollowStopped(c *check.C) {
  189. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "echo", "hello")
  190. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  191. if err != nil {
  192. c.Fatalf("run failed with errors: %s, %v", out, err)
  193. }
  194. cleanedContainerID := strings.TrimSpace(out)
  195. exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
  196. logsCmd := exec.Command(dockerBinary, "logs", "-f", cleanedContainerID)
  197. if err := logsCmd.Start(); err != nil {
  198. c.Fatal(err)
  199. }
  200. errChan := make(chan error)
  201. go func() {
  202. errChan <- logsCmd.Wait()
  203. close(errChan)
  204. }()
  205. select {
  206. case err := <-errChan:
  207. c.Assert(err, check.IsNil)
  208. case <-time.After(1 * time.Second):
  209. c.Fatal("Following logs is hanged")
  210. }
  211. deleteContainer(cleanedContainerID)
  212. }
  213. func (s *DockerSuite) TestLogsSince(c *check.C) {
  214. name := "testlogssince"
  215. runCmd := exec.Command(dockerBinary, "run", "--name="+name, "busybox", "/bin/sh", "-c", `date +%s; for i in $(seq 1 5); do sleep 1; echo log$i; done`)
  216. out, _, err := runCommandWithOutput(runCmd)
  217. if err != nil {
  218. c.Fatalf("run failed with errors: %s, %v", out, err)
  219. }
  220. outLines := strings.Split(out, "\n")
  221. startUnix, _ := strconv.ParseInt(outLines[0], 10, 64)
  222. since := startUnix + 3
  223. logsCmd := exec.Command(dockerBinary, "logs", "-t", fmt.Sprintf("--since=%v", since), name)
  224. out, _, err = runCommandWithOutput(logsCmd)
  225. if err != nil {
  226. c.Fatalf("failed to log container: %s, %v", out, err)
  227. }
  228. // Skip 2 seconds
  229. unexpected := []string{"log1", "log2"}
  230. for _, v := range unexpected {
  231. if strings.Contains(out, v) {
  232. c.Fatalf("unexpected log message returned=%v, since=%v\nout=%v", v, since, out)
  233. }
  234. }
  235. // Test with default value specified and parameter omitted
  236. expected := []string{"log1", "log2", "log3", "log4", "log5"}
  237. for _, cmd := range []*exec.Cmd{
  238. exec.Command(dockerBinary, "logs", "-t", name),
  239. exec.Command(dockerBinary, "logs", "-t", "--since=0", name),
  240. } {
  241. out, _, err = runCommandWithOutput(cmd)
  242. if err != nil {
  243. c.Fatalf("failed to log container: %s, %v", out, err)
  244. }
  245. for _, v := range expected {
  246. if !strings.Contains(out, v) {
  247. c.Fatalf("'%v' does not contain=%v\nout=%s", cmd.Args, v, out)
  248. }
  249. }
  250. }
  251. }
  252. func (s *DockerSuite) TestLogsSinceFutureFollow(c *check.C) {
  253. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "/bin/sh", "-c", `for i in $(seq 1 5); do date +%s; sleep 1; done`)
  254. out, _, err := runCommandWithOutput(runCmd)
  255. if err != nil {
  256. c.Fatalf("run failed with errors: %s, %v", out, err)
  257. }
  258. cleanedContainerID := strings.TrimSpace(out)
  259. now := daemonTime(c).Unix()
  260. since := now + 2
  261. logCmd := exec.Command(dockerBinary, "logs", "-f", fmt.Sprintf("--since=%v", since), cleanedContainerID)
  262. out, _, err = runCommandWithOutput(logCmd)
  263. if err != nil {
  264. c.Fatalf("failed to log container: %s, %v", out, err)
  265. }
  266. lines := strings.Split(strings.TrimSpace(out), "\n")
  267. if len(lines) == 0 {
  268. c.Fatal("got no log lines")
  269. }
  270. for _, v := range lines {
  271. ts, err := strconv.ParseInt(v, 10, 64)
  272. if err != nil {
  273. c.Fatalf("cannot parse timestamp output from log: '%v'\nout=%s", v, out)
  274. }
  275. if ts < since {
  276. c.Fatalf("earlier log found. since=%v logdate=%v", since, ts)
  277. }
  278. }
  279. }
  280. // Regression test for #8832
  281. func (s *DockerSuite) TestLogsFollowSlowStdoutConsumer(c *check.C) {
  282. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "/bin/sh", "-c", `usleep 200000;yes X | head -c 200000`)
  283. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  284. if err != nil {
  285. c.Fatalf("run failed with errors: %s, %v", out, err)
  286. }
  287. cleanedContainerID := strings.TrimSpace(out)
  288. stopSlowRead := make(chan bool)
  289. go func() {
  290. exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
  291. stopSlowRead <- true
  292. }()
  293. logCmd := exec.Command(dockerBinary, "logs", "-f", cleanedContainerID)
  294. stdout, err := logCmd.StdoutPipe()
  295. c.Assert(err, check.IsNil)
  296. if err := logCmd.Start(); err != nil {
  297. c.Fatal(err)
  298. }
  299. // First read slowly
  300. bytes1, err := consumeWithSpeed(stdout, 10, 50*time.Millisecond, stopSlowRead)
  301. c.Assert(err, check.IsNil)
  302. // After the container has finished we can continue reading fast
  303. bytes2, err := consumeWithSpeed(stdout, 32*1024, 0, nil)
  304. c.Assert(err, check.IsNil)
  305. actual := bytes1 + bytes2
  306. expected := 200000
  307. if actual != expected {
  308. c.Fatalf("Invalid bytes read: %d, expected %d", actual, expected)
  309. }
  310. }