github.com/containers/podman/v4@v4.9.4/test/e2e/logs_test.go (about) 1 package integration 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "time" 8 9 . "github.com/containers/podman/v4/test/utils" 10 "github.com/containers/storage/pkg/stringid" 11 . "github.com/onsi/ginkgo/v2" 12 . "github.com/onsi/gomega" 13 "github.com/onsi/gomega/format" 14 . "github.com/onsi/gomega/gexec" 15 ) 16 17 func isEventBackendJournald(podmanTest *PodmanTestIntegration) bool { 18 if !podmanTest.RemoteTest { 19 // If not remote test, '--events-backend' is set to 'file' or 'none' 20 return false 21 } 22 info := podmanTest.Podman([]string{"info", "--format", "{{.Host.EventLogger}}"}) 23 info.WaitWithDefaultTimeout() 24 return info.OutputToString() == "journald" 25 } 26 27 var _ = Describe("Podman logs", func() { 28 29 It("podman logs on not existent container", func() { 30 results := podmanTest.Podman([]string{"logs", "notexist"}) 31 results.WaitWithDefaultTimeout() 32 Expect(results).To(Exit(125)) 33 Expect(results.ErrorToString()).To(Equal(`Error: no container with name or ID "notexist" found: no such container`)) 34 }) 35 36 for _, log := range []string{"k8s-file", "journald", "json-file"} { 37 // This is important to move the 'log' var to the correct scope under Ginkgo flow. 38 log := log 39 40 // Flake prevention: journalctl makes no timeliness guarantees 41 logTimeout := time.Millisecond 42 if log == "journald" { 43 logTimeout = time.Second 44 } 45 46 skipIfJournaldInContainer := func() { 47 if log == "journald" { 48 SkipIfJournaldUnavailable() 49 } 50 } 51 52 It("all lines: "+log, func() { 53 skipIfJournaldInContainer() 54 55 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 56 logc.WaitWithDefaultTimeout() 57 Expect(logc).To(ExitCleanly()) 58 cid := logc.OutputToString() 59 60 results := podmanTest.Podman([]string{"wait", cid}) 61 results.WaitWithDefaultTimeout() 62 Expect(results).To(ExitCleanly()) 63 64 Eventually(func(g Gomega) { 65 results = podmanTest.Podman([]string{"logs", cid}) 66 results.WaitWithDefaultTimeout() 67 g.Expect(results).To(ExitCleanly()) 68 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 69 g.Expect(results.OutputToString()).To(Equal("podman podman podman")) 70 }).WithTimeout(logTimeout).Should(Succeed()) 71 }) 72 73 It("tail two lines: "+log, func() { 74 skipIfJournaldInContainer() 75 76 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 77 logc.WaitWithDefaultTimeout() 78 Expect(logc).To(ExitCleanly()) 79 cid := logc.OutputToString() 80 81 wait := podmanTest.Podman([]string{"wait", cid}) 82 wait.WaitWithDefaultTimeout() 83 Expect(wait).To(ExitCleanly()) 84 85 Eventually(func(g Gomega) { 86 results := podmanTest.Podman([]string{"logs", "--tail", "2", cid}) 87 results.WaitWithDefaultTimeout() 88 g.Expect(results).To(ExitCleanly()) 89 g.Expect(results.OutputToStringArray()).To(HaveLen(2)) 90 g.Expect(results.OutputToString()).To(Equal("podman podman")) 91 }).WithTimeout(logTimeout).Should(Succeed()) 92 }) 93 94 It("tail zero lines: "+log, func() { 95 skipIfJournaldInContainer() 96 97 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 98 logc.WaitWithDefaultTimeout() 99 Expect(logc).To(ExitCleanly()) 100 cid := logc.OutputToString() 101 102 wait := podmanTest.Podman([]string{"wait", cid}) 103 wait.WaitWithDefaultTimeout() 104 Expect(wait).To(ExitCleanly()) 105 106 time.Sleep(logTimeout) 107 results := podmanTest.Podman([]string{"logs", "--tail", "0", cid}) 108 results.WaitWithDefaultTimeout() 109 Expect(results).To(ExitCleanly()) 110 Expect(results.OutputToStringArray()).To(BeEmpty()) 111 }) 112 113 It("tail 99 lines: "+log, func() { 114 skipIfJournaldInContainer() 115 116 name := "test1" 117 logc := podmanTest.Podman([]string{"run", "--name", name, "--log-driver", log, ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 118 logc.WaitWithDefaultTimeout() 119 Expect(logc).To(ExitCleanly()) 120 121 wait := podmanTest.Podman([]string{"wait", name}) 122 wait.WaitWithDefaultTimeout() 123 Expect(wait).To(ExitCleanly()) 124 125 Eventually(func(g Gomega) { 126 results := podmanTest.Podman([]string{"logs", "--tail", "99", name}) 127 results.WaitWithDefaultTimeout() 128 g.Expect(results).To(ExitCleanly()) 129 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 130 }).WithTimeout(logTimeout).Should(Succeed()) 131 }) 132 133 It("tail 800 lines: "+log, func() { 134 skipIfJournaldInContainer() 135 136 // we match 800 line array here, make sure to print all lines when assertion fails. 137 // There is something weird going on (https://github.com/containers/podman/issues/18501) 138 // and only the normal output log does not seem to be enough to figure out why it flakes. 139 oldLength := format.MaxLength 140 // unlimited matcher output 141 format.MaxLength = 0 142 defer func() { 143 format.MaxLength = oldLength 144 }() 145 146 // this uses -d so that we do not have 1000 unnecessary lines printed in every test log 147 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-d", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"}) 148 logc.WaitWithDefaultTimeout() 149 Expect(logc).To(ExitCleanly()) 150 cid := logc.OutputToString() 151 152 // make sure we wait for the container to finish writing its output 153 wait := podmanTest.Podman([]string{"wait", cid}) 154 wait.WaitWithDefaultTimeout() 155 Expect(wait).To(ExitCleanly()) 156 157 Eventually(func(g Gomega) { 158 results := podmanTest.Podman([]string{"logs", "--tail", "800", cid}) 159 results.WaitWithDefaultTimeout() 160 g.Expect(results).To(ExitCleanly()) 161 g.Expect(results.OutputToStringArray()).To(HaveLen(800)) 162 }).WithTimeout(logTimeout).Should(Succeed()) 163 }) 164 165 It("tail 2 lines with timestamps: "+log, func() { 166 skipIfJournaldInContainer() 167 168 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 169 logc.WaitWithDefaultTimeout() 170 Expect(logc).To(ExitCleanly()) 171 cid := logc.OutputToString() 172 173 wait := podmanTest.Podman([]string{"wait", cid}) 174 wait.WaitWithDefaultTimeout() 175 Expect(wait).To(ExitCleanly()) 176 177 Eventually(func(g Gomega) { 178 results := podmanTest.Podman([]string{"logs", "--tail", "2", "-t", cid}) 179 results.WaitWithDefaultTimeout() 180 g.Expect(results).To(ExitCleanly()) 181 g.Expect(results.OutputToStringArray()).To(HaveLen(2)) 182 }).WithTimeout(logTimeout).Should(Succeed()) 183 }) 184 185 It("since time 2017-08-07: "+log, func() { 186 skipIfJournaldInContainer() 187 188 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 189 logc.WaitWithDefaultTimeout() 190 Expect(logc).To(ExitCleanly()) 191 cid := logc.OutputToString() 192 193 wait := podmanTest.Podman([]string{"wait", cid}) 194 wait.WaitWithDefaultTimeout() 195 Expect(wait).To(ExitCleanly()) 196 197 Eventually(func(g Gomega) { 198 results := podmanTest.Podman([]string{"logs", "--since", "2017-08-07T10:10:09.056611202-04:00", cid}) 199 results.WaitWithDefaultTimeout() 200 g.Expect(results).To(ExitCleanly()) 201 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 202 }).WithTimeout(logTimeout).Should(Succeed()) 203 }) 204 205 It("since duration 10m: "+log, func() { 206 skipIfJournaldInContainer() 207 208 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 209 logc.WaitWithDefaultTimeout() 210 Expect(logc).To(ExitCleanly()) 211 cid := logc.OutputToString() 212 213 wait := podmanTest.Podman([]string{"wait", cid}) 214 wait.WaitWithDefaultTimeout() 215 Expect(wait).To(ExitCleanly()) 216 217 Eventually(func(g Gomega) { 218 results := podmanTest.Podman([]string{"logs", "--since", "10m", cid}) 219 results.WaitWithDefaultTimeout() 220 g.Expect(results).To(ExitCleanly()) 221 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 222 }).WithTimeout(logTimeout).Should(Succeed()) 223 }) 224 225 It("until duration 10m: "+log, func() { 226 skipIfJournaldInContainer() 227 228 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 229 logc.WaitWithDefaultTimeout() 230 Expect(logc).To(ExitCleanly()) 231 cid := logc.OutputToString() 232 233 wait := podmanTest.Podman([]string{"wait", cid}) 234 wait.WaitWithDefaultTimeout() 235 Expect(wait).To(ExitCleanly()) 236 237 Eventually(func(g Gomega) { 238 results := podmanTest.Podman([]string{"logs", "--until", "10m", cid}) 239 results.WaitWithDefaultTimeout() 240 g.Expect(results).To(ExitCleanly()) 241 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 242 }).WithTimeout(logTimeout).Should(Succeed()) 243 }) 244 245 It("until time NOW: "+log, func() { 246 skipIfJournaldInContainer() 247 248 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 249 logc.WaitWithDefaultTimeout() 250 Expect(logc).To(ExitCleanly()) 251 cid := logc.OutputToString() 252 253 wait := podmanTest.Podman([]string{"wait", cid}) 254 wait.WaitWithDefaultTimeout() 255 Expect(wait).To(ExitCleanly()) 256 257 Eventually(func(g Gomega) { 258 now := time.Now() 259 now = now.Add(time.Minute * 1) 260 nowS := now.Format(time.RFC3339) 261 results := podmanTest.Podman([]string{"logs", "--until", nowS, cid}) 262 results.WaitWithDefaultTimeout() 263 g.Expect(results).To(ExitCleanly()) 264 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 265 }).WithTimeout(logTimeout).Should(Succeed()) 266 }) 267 268 It("latest and container name should fail: "+log, func() { 269 skipIfJournaldInContainer() 270 271 results := podmanTest.Podman([]string{"logs", "-l", "foobar"}) 272 results.WaitWithDefaultTimeout() 273 Expect(results).To(ExitWithError()) 274 }) 275 276 It("two containers showing short container IDs: "+log, func() { 277 skipIfJournaldInContainer() 278 SkipIfRemote("podman-remote logs does not support showing two containers at the same time") 279 280 log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 281 log1.WaitWithDefaultTimeout() 282 Expect(log1).Should(ExitCleanly()) 283 cid1 := log1.OutputToString() 284 285 log2 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 286 log2.WaitWithDefaultTimeout() 287 Expect(log2).Should(ExitCleanly()) 288 cid2 := log2.OutputToString() 289 290 wait := podmanTest.Podman([]string{"wait", cid1, cid2}) 291 wait.WaitWithDefaultTimeout() 292 Expect(wait).To(ExitCleanly()) 293 294 results := podmanTest.Podman([]string{"logs", cid1, cid2}) 295 results.WaitWithDefaultTimeout() 296 Expect(results).Should(ExitCleanly()) 297 298 output := results.OutputToStringArray() 299 Expect(output).To(HaveLen(6)) 300 Expect(output[0]).To(Or(ContainSubstring(cid1[:12]), ContainSubstring(cid2[:12]))) 301 }) 302 303 It("podman logs on a created container should result in 0 exit code: "+log, func() { 304 skipIfJournaldInContainer() 305 306 session := podmanTest.Podman([]string{"create", "--log-driver", log, "--name", "log", ALPINE}) 307 session.WaitWithDefaultTimeout() 308 Expect(session).To(ExitCleanly()) 309 310 results := podmanTest.Podman([]string{"logs", "log"}) 311 results.WaitWithDefaultTimeout() 312 Expect(results).To(ExitCleanly()) 313 }) 314 315 It("streaming output: "+log, func() { 316 skipIfJournaldInContainer() 317 318 containerName := "logs-f" 319 320 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-dt", ALPINE, "sh", "-c", "echo podman-1; sleep 1; echo podman-2"}) 321 logc.WaitWithDefaultTimeout() 322 Expect(logc).To(ExitCleanly()) 323 324 results := podmanTest.Podman([]string{"logs", "-f", containerName}) 325 results.WaitWithDefaultTimeout() 326 327 if log == "journald" && !isEventBackendJournald(podmanTest) { 328 // --follow + journald log-driver is only supported with journald events-backend(PR #10431) 329 Expect(results).To(Exit(125)) 330 Expect(results.ErrorToString()).To(ContainSubstring("using --follow with the journald --log-driver but without the journald --events-backend")) 331 return 332 } 333 334 Expect(results).To(ExitCleanly()) 335 336 Expect(results.OutputToString()).To(ContainSubstring("podman-1")) 337 Expect(results.OutputToString()).To(ContainSubstring("podman-2")) 338 339 // Container should now be terminatING or terminatED, but we 340 // have no guarantee of which: 'logs -f' does not necessarily 341 // wait for cleanup. Run 'inspect' and accept either state. 342 inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Status}}", containerName}) 343 inspect.WaitWithDefaultTimeout() 344 if inspect.ExitCode() == 0 { 345 Expect(inspect.OutputToString()).To(Equal("exited")) 346 // TODO: add 2-second wait loop to confirm cleanup 347 } else { 348 Expect(inspect.ErrorToString()).To(ContainSubstring("no such container")) 349 } 350 351 results = podmanTest.Podman([]string{"rm", "--time", "0", "-f", containerName}) 352 results.WaitWithDefaultTimeout() 353 Expect(results).To(ExitCleanly()) 354 }) 355 356 It("follow output stopped container: "+log, func() { 357 skipIfJournaldInContainer() 358 359 containerName := "logs-f" 360 361 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, ALPINE, "true"}) 362 logc.WaitWithDefaultTimeout() 363 Expect(logc).To(ExitCleanly()) 364 365 results := podmanTest.Podman([]string{"logs", "-f", containerName}) 366 results.WaitWithDefaultTimeout() 367 if log == "journald" && !isEventBackendJournald(podmanTest) { 368 // --follow + journald log-driver is only supported with journald events-backend(PR #10431) 369 Expect(results).To(Exit(125)) 370 Expect(results.ErrorToString()).To(ContainSubstring("using --follow with the journald --log-driver but without the journald --events-backend")) 371 return 372 } 373 Expect(results).To(ExitCleanly()) 374 }) 375 376 It("using container with container log-size: "+log, func() { 377 skipIfJournaldInContainer() 378 379 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--log-opt=max-size=10k", "-d", ALPINE, "echo", "podman podman podman"}) 380 logc.WaitWithDefaultTimeout() 381 Expect(logc).To(ExitCleanly()) 382 cid := logc.OutputToString() 383 384 wait := podmanTest.Podman([]string{"wait", cid}) 385 wait.WaitWithDefaultTimeout() 386 Expect(wait).To(ExitCleanly()) 387 388 inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.HostConfig.LogConfig.Size}}", cid}) 389 inspect.WaitWithDefaultTimeout() 390 Expect(inspect).To(ExitCleanly()) 391 Expect(inspect.OutputToString()).To(Equal("10kB")) 392 393 Eventually(func(g Gomega) { 394 results := podmanTest.Podman([]string{"logs", cid}) 395 results.WaitWithDefaultTimeout() 396 g.Expect(results).To(ExitCleanly()) 397 g.Expect(results.OutputToString()).To(Equal("podman podman podman")) 398 }).WithTimeout(logTimeout).Should(Succeed()) 399 }) 400 401 It("Make sure logs match expected length: "+log, func() { 402 skipIfJournaldInContainer() 403 404 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", "test", ALPINE, "sh", "-c", "echo 1; echo 2"}) 405 logc.WaitWithDefaultTimeout() 406 Expect(logc).To(ExitCleanly()) 407 408 wait := podmanTest.Podman([]string{"wait", "test"}) 409 wait.WaitWithDefaultTimeout() 410 Expect(wait).To(ExitCleanly()) 411 412 Eventually(func(g Gomega) { 413 results := podmanTest.Podman([]string{"logs", "test"}) 414 results.WaitWithDefaultTimeout() 415 g.Expect(results).To(ExitCleanly()) 416 outlines := results.OutputToStringArray() 417 g.Expect(outlines).To(HaveLen(2)) 418 g.Expect(outlines[0]).To(Equal("1")) 419 g.Expect(outlines[1]).To(Equal("2")) 420 }).WithTimeout(logTimeout).Should(Succeed()) 421 }) 422 423 It("podman logs test stdout and stderr: "+log, func() { 424 skipIfJournaldInContainer() 425 426 cname := "log-test" 427 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "sh", "-c", "echo stdout; echo stderr >&2"}) 428 logc.WaitWithDefaultTimeout() 429 Expect(logc).To(Exit(0)) 430 431 wait := podmanTest.Podman([]string{"wait", cname}) 432 wait.WaitWithDefaultTimeout() 433 Expect(wait).To(ExitCleanly()) 434 435 Eventually(func(g Gomega) { 436 results := podmanTest.Podman([]string{"logs", cname}) 437 results.WaitWithDefaultTimeout() 438 g.Expect(results).To(Exit(0)) 439 g.Expect(results.OutputToString()).To(Equal("stdout")) 440 g.Expect(results.ErrorToString()).To(Equal("stderr")) 441 }).WithTimeout(logTimeout).Should(Succeed()) 442 }) 443 444 It("podman logs partial log lines: "+log, func() { 445 skipIfJournaldInContainer() 446 447 cname := "log-test" 448 content := stringid.GenerateRandomID() 449 // use printf to print no extra newline 450 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "printf", content}) 451 logc.WaitWithDefaultTimeout() 452 Expect(logc).To(ExitCleanly()) 453 // Important: do not use OutputToString(), this will remove the trailing newline from the output. 454 // However this test must make sure that there is no such extra newline. 455 Expect(string(logc.Out.Contents())).To(Equal(content)) 456 457 Eventually(func(g Gomega) { 458 logs := podmanTest.Podman([]string{"logs", cname}) 459 logs.WaitWithDefaultTimeout() 460 g.Expect(logs).To(ExitCleanly()) 461 // see comment above 462 g.Expect(string(logs.Out.Contents())).To(Equal(content)) 463 }).WithTimeout(logTimeout).Should(Succeed()) 464 }) 465 466 It("podman pod logs -l with newer container created: "+log, func() { 467 skipIfJournaldInContainer() 468 SkipIfRemote("no -l in remote") 469 470 podName := "testPod" 471 containerName1 := "container1" 472 containerName2 := "container2" 473 containerName3 := "container3" 474 475 testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)}) 476 testPod.WaitWithDefaultTimeout() 477 Expect(testPod).To(ExitCleanly()) 478 479 log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName1, "--pod", podName, BB, "echo", "log1"}) 480 log1.WaitWithDefaultTimeout() 481 Expect(log1).To(ExitCleanly()) 482 483 log2 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName2, "--pod", podName, BB, "echo", "log2"}) 484 log2.WaitWithDefaultTimeout() 485 Expect(log2).To(ExitCleanly()) 486 487 ctr := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName3, BB, "date"}) 488 ctr.WaitWithDefaultTimeout() 489 Expect(ctr).To(ExitCleanly()) 490 491 Eventually(func(g Gomega) { 492 results := podmanTest.Podman([]string{"pod", "logs", "-l"}) 493 results.WaitWithDefaultTimeout() 494 g.Expect(results).To(ExitCleanly()) 495 podOutput := results.OutputToString() 496 497 results = podmanTest.Podman([]string{"logs", "-l"}) 498 results.WaitWithDefaultTimeout() 499 g.Expect(results).To(ExitCleanly()) 500 ctrOutput := results.OutputToString() 501 502 g.Expect(podOutput).ToNot(Equal(ctrOutput)) 503 }).WithTimeout(logTimeout).Should(Succeed()) 504 }) 505 506 It("podman pod logs -l: "+log, func() { 507 skipIfJournaldInContainer() 508 SkipIfRemote("no -l in remote") 509 510 podName := "testPod" 511 containerName1 := "container1" 512 containerName2 := "container2" 513 514 testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)}) 515 testPod.WaitWithDefaultTimeout() 516 Expect(testPod).To(ExitCleanly()) 517 518 log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName1, "--pod", podName, BB, "echo", "log1"}) 519 log1.WaitWithDefaultTimeout() 520 Expect(log1).To(ExitCleanly()) 521 522 log2 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName2, "--pod", podName, BB, "echo", "log2"}) 523 log2.WaitWithDefaultTimeout() 524 Expect(log2).To(ExitCleanly()) 525 526 Eventually(func(g Gomega) { 527 results := podmanTest.Podman([]string{"pod", "logs", "-l"}) 528 results.WaitWithDefaultTimeout() 529 g.Expect(results).To(ExitCleanly()) 530 output := results.OutputToString() 531 g.Expect(output).To(ContainSubstring("log1")) 532 g.Expect(output).To(ContainSubstring("log2")) 533 }).WithTimeout(logTimeout).Should(Succeed()) 534 }) 535 } 536 537 It("using journald for container with container tag", func() { 538 SkipIfJournaldUnavailable() 539 logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "--log-opt=tag={{.ImageName}}", "-d", ALPINE, "sh", "-c", "echo podman; sleep 0.1; echo podman; sleep 0.1; echo podman"}) 540 logc.WaitWithDefaultTimeout() 541 Expect(logc).To(ExitCleanly()) 542 cid := logc.OutputToString() 543 544 wait := podmanTest.Podman([]string{"wait", cid}) 545 wait.WaitWithDefaultTimeout() 546 Expect(wait).To(ExitCleanly()) 547 548 Eventually(func(g Gomega) { 549 cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_TAG", fmt.Sprintf("CONTAINER_ID_FULL=%s", cid)) 550 out, err := cmd.CombinedOutput() 551 g.Expect(err).ToNot(HaveOccurred()) 552 g.Expect(string(out)).To(ContainSubstring("alpine")) 553 }).Should(Succeed()) 554 }) 555 556 It("using journald container name", func() { 557 SkipIfJournaldUnavailable() 558 containerName := "inside-journal" 559 logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-d", "--name", containerName, ALPINE, "sh", "-c", "echo podman; sleep 0.1; echo podman; sleep 0.1; echo podman"}) 560 logc.WaitWithDefaultTimeout() 561 Expect(logc).To(ExitCleanly()) 562 cid := logc.OutputToString() 563 564 wait := podmanTest.Podman([]string{"wait", cid}) 565 wait.WaitWithDefaultTimeout() 566 Expect(wait).To(ExitCleanly()) 567 568 Eventually(func(g Gomega) { 569 cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_NAME", fmt.Sprintf("CONTAINER_ID_FULL=%s", cid)) 570 out, err := cmd.CombinedOutput() 571 g.Expect(err).ToNot(HaveOccurred()) 572 g.Expect(string(out)).To(ContainSubstring(containerName)) 573 }).Should(Succeed()) 574 }) 575 576 It("podman logs with log-driver=none errors", func() { 577 ctrName := "logsctr" 578 logc := podmanTest.Podman([]string{"run", "--name", ctrName, "-d", "--log-driver", "none", ALPINE, "top"}) 579 logc.WaitWithDefaultTimeout() 580 Expect(logc).To(ExitCleanly()) 581 582 logs := podmanTest.Podman([]string{"logs", "-f", ctrName}) 583 logs.WaitWithDefaultTimeout() 584 Expect(logs).To(Exit(125)) 585 Expect(logs.ErrorToString()).To(ContainSubstring("this container is using the 'none' log driver, cannot read logs: this container is not logging output")) 586 }) 587 588 It("podman logs with non ASCII log tag fails without correct LANG", func() { 589 SkipIfJournaldUnavailable() 590 // need to set the LANG to something that does not support german umlaute to trigger the failure case 591 cleanup := setLangEnv("C") 592 if IsRemote() { 593 podmanTest.RestartRemoteService() 594 } 595 defer cleanup() 596 logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "--log-opt", "tag=äöüß", ALPINE, "echo", "podman"}) 597 logc.WaitWithDefaultTimeout() 598 Expect(logc).To(Exit(126)) 599 // FIXME-2023-09-26: conmon <2.1.8 logs to stdout; clean this up once >=2.1.8 is universal 600 errmsg := logc.ErrorToString() + logc.OutputToString() 601 if !IsRemote() { 602 // Error is only seen on local client 603 Expect(errmsg).To(ContainSubstring("conmon: option parsing failed: Invalid byte sequence in conversion input")) 604 } 605 Expect(errmsg).To(ContainSubstring("conmon failed: exit status 1")) 606 }) 607 608 It("podman logs with non ASCII log tag succeeds with proper env", func() { 609 SkipIfJournaldUnavailable() 610 cleanup := setLangEnv("en_US.UTF-8") 611 if IsRemote() { 612 podmanTest.RestartRemoteService() 613 } 614 defer cleanup() 615 logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "--log-opt", "tag=äöüß", ALPINE, "echo", "podman"}) 616 logc.WaitWithDefaultTimeout() 617 Expect(logc).To(ExitCleanly()) 618 Expect(logc.OutputToString()).To(Equal("podman")) 619 }) 620 621 It("podman pod logs with container names", func() { 622 SkipIfRemote("Remote can only process one container at a time") 623 podName := "testPod" 624 containerName1 := "container1" 625 containerName2 := "container2" 626 627 testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)}) 628 testPod.WaitWithDefaultTimeout() 629 Expect(testPod).To(ExitCleanly()) 630 631 log1 := podmanTest.Podman([]string{"run", "--name", containerName1, "--pod", podName, BB, "echo", "log1"}) 632 log1.WaitWithDefaultTimeout() 633 Expect(log1).To(ExitCleanly()) 634 635 log2 := podmanTest.Podman([]string{"run", "--name", containerName2, "--pod", podName, BB, "echo", "log2"}) 636 log2.WaitWithDefaultTimeout() 637 Expect(log2).To(ExitCleanly()) 638 639 Eventually(func(g Gomega) { 640 results := podmanTest.Podman([]string{"pod", "logs", "--names", podName}) 641 results.WaitWithDefaultTimeout() 642 g.Expect(results).To(ExitCleanly()) 643 644 output := results.OutputToStringArray() 645 g.Expect(output).To(HaveLen(2)) 646 g.Expect(output).To(ContainElement(ContainSubstring(containerName1))) 647 g.Expect(output).To(ContainElement(ContainSubstring(containerName2))) 648 }).Should(Succeed()) 649 }) 650 It("podman pod logs with different colors", func() { 651 SkipIfRemote("Remote can only process one container at a time") 652 podName := "testPod" 653 containerName1 := "container1" 654 containerName2 := "container2" 655 testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)}) 656 testPod.WaitWithDefaultTimeout() 657 Expect(testPod).To(ExitCleanly()) 658 log1 := podmanTest.Podman([]string{"run", "--name", containerName1, "--pod", podName, BB, "echo", "log1"}) 659 log1.WaitWithDefaultTimeout() 660 Expect(log1).To(ExitCleanly()) 661 log2 := podmanTest.Podman([]string{"run", "--name", containerName2, "--pod", podName, BB, "echo", "log2"}) 662 log2.WaitWithDefaultTimeout() 663 Expect(log2).To(ExitCleanly()) 664 665 Eventually(func(g Gomega) { 666 results := podmanTest.Podman([]string{"pod", "logs", "--color", podName}) 667 results.WaitWithDefaultTimeout() 668 g.Expect(results).To(ExitCleanly()) 669 output := results.OutputToStringArray() 670 g.Expect(output).To(HaveLen(2)) 671 g.Expect(output[0]).To(MatchRegexp(`\x1b\[3[0-9a-z ]+\x1b\[0m`)) 672 g.Expect(output[1]).To(MatchRegexp(`\x1b\[3[0-9a-z ]+\x1b\[0m`)) 673 }).Should(Succeed()) 674 }) 675 }) 676 677 func setLangEnv(lang string) func() { 678 oldLang, okLang := os.LookupEnv("LANG") 679 oldLcAll, okLc := os.LookupEnv("LC_ALL") 680 err := os.Setenv("LANG", lang) 681 Expect(err).ToNot(HaveOccurred()) 682 err = os.Setenv("LC_ALL", "") 683 Expect(err).ToNot(HaveOccurred()) 684 685 return func() { 686 if okLang { 687 os.Setenv("LANG", oldLang) 688 } else { 689 os.Unsetenv("LANG") 690 } 691 if okLc { 692 os.Setenv("LC_ALL", oldLcAll) 693 } else { 694 os.Unsetenv("LC_ALL") 695 } 696 } 697 }