Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit d653a15

Browse files
committed
implement 'ganache instances logs <name>' with support for --since, --until, and --follow
1 parent 0a066b8 commit d653a15

File tree

8 files changed

+480
-88
lines changed

8 files changed

+480
-88
lines changed

src/packages/cli/package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/packages/cli/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"@types/node": "17.0.0",
7373
"chalk": "4.1.0",
7474
"cli-table": "0.3.11",
75-
"marked-terminal": "4.1.0"
75+
"marked-terminal": "4.1.0",
76+
"parse-duration": "1.0.2"
7677
}
7778
}

src/packages/cli/src/args.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { EOL } from "os";
1717
import marked from "marked";
1818
import TerminalRenderer from "marked-terminal";
1919
import { _DefaultServerOptions } from "@ganache/core";
20+
import parseDuration from "parse-duration";
2021

2122
marked.setOptions({
2223
renderer: new TerminalRenderer({
@@ -272,6 +273,30 @@ export default function (
272273
stopArgs.action = "stop";
273274
}
274275
)
276+
.command(
277+
"logs <name>",
278+
"fetch logs for the instance specified by <name>",
279+
logsArgs => {
280+
logsArgs.positional("name", { type: "string" });
281+
logsArgs
282+
.options("follow", {
283+
type: "boolean",
284+
alias: ["f"],
285+
description: "continue streaming the instances logs"
286+
})
287+
.options("since", {
288+
type: "string",
289+
alias: ["s"]
290+
})
291+
.options("until", {
292+
type: "string",
293+
alias: ["u"]
294+
});
295+
},
296+
logsArgs => {
297+
logsArgs.action = "logs";
298+
}
299+
)
275300
.version(false);
276301
}
277302
)
@@ -307,13 +332,39 @@ export default function (
307332
"flavor" | "action"
308333
>)
309334
};
335+
} else if (parsedArgs.action === "logs") {
336+
finalArgs = {
337+
action: "logs",
338+
name: parsedArgs.name as string,
339+
follow: parsedArgs.follow as boolean,
340+
since: getTimestampFromInput(parsedArgs.since as string),
341+
until: getTimestampFromInput(parsedArgs.until as string)
342+
};
310343
} else {
311344
throw new Error(`Unknown action: ${parsedArgs.action}`);
312345
}
313346

314347
return finalArgs;
315348
}
316349

350+
function getTimestampFromInput(input: string): number | null {
351+
if (input == null) {
352+
return null;
353+
}
354+
355+
const parsedDate = Date.parse(input);
356+
if (!Number.isNaN(parsedDate)) {
357+
return parsedDate;
358+
}
359+
360+
const duration = parseDuration(input, "ms");
361+
if (duration == null) {
362+
throw new Error(`Invalid duration ${input}`);
363+
}
364+
365+
return Date.now() - duration;
366+
}
367+
317368
/**
318369
* Expands the arguments into an object including only namespaced keys from the
319370
* `args` argument.

src/packages/cli/src/cli.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ import {
1313
stopDetachedInstance,
1414
startDetachedInstance,
1515
getDetachedInstances,
16-
formatUptime
16+
formatUptime,
17+
getInstanceLogsPath,
18+
getDetachedInstanceByName
1719
} from "./detach";
1820
import { TruffleColors } from "@ganache/colors";
1921
import Table from "cli-table";
2022
import chalk from "chalk";
21-
23+
import { getLogsStream } from "./logs-stream";
2224
const porscheColor = chalk.hex(TruffleColors.porsche);
2325

2426
const logAndForceExit = (messages: any[], exitCode = 0) => {
@@ -171,6 +173,36 @@ if (argv.action === "start") {
171173
console.error("Instance not found");
172174
}
173175
});
176+
} else if (argv.action === "logs") {
177+
const instanceName = argv.name;
178+
179+
getDetachedInstanceByName(instanceName)
180+
.then(_ => {
181+
const path = getInstanceLogsPath(instanceName);
182+
183+
const stream = getLogsStream(path, {
184+
follow: argv.follow,
185+
since: argv.since,
186+
until: argv.until
187+
});
188+
189+
stream.on("error", err => {
190+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
191+
console.log(
192+
`No logs are available for ${instanceName}.\nTry calling some RPC methods.`
193+
);
194+
}
195+
});
196+
stream.pipe(process.stdout);
197+
//todo: we need to be able to quit from this if `--follow` is provided
198+
})
199+
.catch(err => {
200+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
201+
console.error("Instance not found");
202+
} else {
203+
console.error(err);
204+
}
205+
});
174206
} else if (argv.action === "start-detached") {
175207
startDetachedInstance(process.argv, argv, version)
176208
.then(instance => {

0 commit comments

Comments
 (0)