From 29ed50ec0221c42993379f5e86a170b332522772 Mon Sep 17 00:00:00 2001 From: NuShoSinkuPomogliTebeTvoiSankcii <150355636+NuShoSinkuPomogliTebeTvoiSankcii@users.noreply.github.com> Date: Thu, 23 Nov 2023 19:16:15 +0500 Subject: [PATCH] Add support for fetching container logs from a given time (#670) --- docs/features/containers.md | 11 ++++++++ .../abstract-started-container.ts | 4 +-- .../generic-container-logs.test.ts | 27 +++++++++++++++++++ .../started-generic-container.ts | 5 ++-- packages/testcontainers/src/test-container.ts | 2 +- 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/docs/features/containers.md b/docs/features/containers.md index be8100a9a..00589a428 100644 --- a/docs/features/containers.md +++ b/docs/features/containers.md @@ -527,3 +527,14 @@ const container = await new GenericContainer("alpine") }) .start(); ``` + +You can specify a point in time as a UNIX timestamp from which you want the logs to start: + +```javascript +const msInSec = 1000; +const tenSecondsAgoMs = new Date().getTime() - 10 * msInSec; +const since = tenSecondsAgoMs / msInSec; + +(await container.logs({ since })) + .on("data", line => console.log(line)) +``` diff --git a/packages/testcontainers/src/generic-container/abstract-started-container.ts b/packages/testcontainers/src/generic-container/abstract-started-container.ts index 020efc6e8..3802c6ed6 100644 --- a/packages/testcontainers/src/generic-container/abstract-started-container.ts +++ b/packages/testcontainers/src/generic-container/abstract-started-container.ts @@ -83,7 +83,7 @@ export class AbstractStartedContainer implements StartedTestContainer { return this.startedTestContainer.exec(command); } - public logs(): Promise { - return this.startedTestContainer.logs(); + public logs(opts?: { since?: number }): Promise { + return this.startedTestContainer.logs(opts); } } diff --git a/packages/testcontainers/src/generic-container/generic-container-logs.test.ts b/packages/testcontainers/src/generic-container/generic-container-logs.test.ts index b16b04d1b..b712fe2d4 100644 --- a/packages/testcontainers/src/generic-container/generic-container-logs.test.ts +++ b/packages/testcontainers/src/generic-container/generic-container-logs.test.ts @@ -1,5 +1,6 @@ import { GenericContainer } from "./generic-container"; import { containerLog } from "../common"; +import { Wait } from "../wait-strategies/wait"; describe("GenericContainer logs", () => { jest.setTimeout(180_000); @@ -26,6 +27,32 @@ describe("GenericContainer logs", () => { await container.stop(); }); + it("should stream logs with since option from a started container", async () => { + const pauseMs = 5 * 1000; + const logBeforeSleep = "first"; + const logAfterSleep = "second"; + const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") + .withEntrypoint([ + "/bin/sh", + "-c", + `echo ${logBeforeSleep} && sleep ${pauseMs / 1000} && echo ${logAfterSleep} && sleep infinity`, + ]) + .withWaitStrategy(Wait.forLogMessage(logBeforeSleep)) + .start(); + + await new Promise((resolve) => setTimeout(resolve, pauseMs)); + + const inSleepTimestamp = new Date().getTime() - pauseMs + 1000; + const since = Math.floor(inSleepTimestamp / 1000); + + const stream = await container.logs({ since }); + const log: string = await new Promise((resolve) => stream.on("data", (line) => resolve(line.trim()))); + + expect(log).toBe(logAfterSleep); + + await container.stop(); + }); + it("should stream logs from a running container after restart", async () => { const containerLogTraceSpy = jest.spyOn(containerLog, "trace"); const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").withExposedPorts(8080).start(); diff --git a/packages/testcontainers/src/generic-container/started-generic-container.ts b/packages/testcontainers/src/generic-container/started-generic-container.ts index 2c8bf7601..698024484 100644 --- a/packages/testcontainers/src/generic-container/started-generic-container.ts +++ b/packages/testcontainers/src/generic-container/started-generic-container.ts @@ -181,8 +181,9 @@ export class StartedGenericContainer implements StartedTestContainer { return output; } - public async logs(): Promise { + public async logs(opts?: { since?: number }): Promise { const client = await getContainerRuntimeClient(); - return client.container.logs(this.container); + + return client.container.logs(this.container, opts); } } diff --git a/packages/testcontainers/src/test-container.ts b/packages/testcontainers/src/test-container.ts index 16a6846ff..53f56dd0c 100644 --- a/packages/testcontainers/src/test-container.ts +++ b/packages/testcontainers/src/test-container.ts @@ -74,7 +74,7 @@ export interface StartedTestContainer { copyFilesToContainer(filesToCopy: FileToCopy[]): Promise; copyContentToContainer(contentsToCopy: ContentToCopy[]): Promise; exec(command: string | string[]): Promise; - logs(): Promise; + logs(opts?: { since?: number }): Promise; } export interface StoppedTestContainer {