Skip to content

Commit

Permalink
feat(cli): add --show-timestamps flag to CLI commands
Browse files Browse the repository at this point in the history
Enables users to toggle timestamps on/off with log output
  • Loading branch information
eysi09 committed Sep 20, 2020
1 parent afe80dd commit f09deae
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 7 deletions.
17 changes: 14 additions & 3 deletions core/src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,20 @@ export async function makeDummyGarden(root: string, gardenOpts: GardenOpts = {})
return DummyGarden.factory(root, { ...gardenOpts, noEnterprise: true })
}

function initLogger({ level, loggerType, emoji }: { level: LogLevel; loggerType: LoggerType; emoji: boolean }) {
function initLogger({
level,
loggerType,
emoji,
showTimestamps,
}: {
level: LogLevel
loggerType: LoggerType
emoji: boolean
showTimestamps: boolean
}) {
const writer = getWriterInstance(loggerType, level)
const writers = writer ? [writer] : undefined
return Logger.initialize({ level, writers, useEmoji: emoji })
return Logger.initialize({ level, writers, showTimestamps, useEmoji: emoji })
}

export interface RunOutput {
Expand Down Expand Up @@ -164,6 +174,7 @@ ${renderCommands(commands)}
const {
"logger-type": loggerTypeOpt,
"log-level": logLevel,
"show-timestamps": showTimestamps,
emoji,
"env": environmentName,
silent,
Expand All @@ -183,7 +194,7 @@ ${renderCommands(commands)}

// Init logger
const level = parseLogLevel(logLevel)
const logger = initLogger({ level, loggerType, emoji })
const logger = initLogger({ level, loggerType, emoji, showTimestamps })

// Currently we initialise empty placeholder entries and pass those to the
// framework as opposed to the logger itself. This is to give better control over where on
Expand Down
4 changes: 4 additions & 0 deletions core/src/cli/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ export const globalOptions = {
help: "Enable emoji in output (defaults to true if the environment supports it).",
defaultValue: envSupportsEmoji(),
}),
"show-timestamps": new BooleanParameter({
help: "Show timestamps with log output.",
defaultValue: false,
}),
"yes": new BooleanParameter({
alias: "y",
help: "Automatically approve any yes/no prompts during execution.",
Expand Down
3 changes: 3 additions & 0 deletions core/src/logger/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export function getWriterInstance(loggerType: LoggerType, level: LogLevel) {

export interface LoggerConfig {
level: LogLevel
showTimestamps?: boolean
writers?: Writer[]
useEmoji?: boolean
}
Expand All @@ -81,6 +82,7 @@ export class Logger extends LogNode {
public writers: Writer[]
public events: EventBus
public useEmoji: boolean
public showTimestamps: boolean

private static instance: Logger

Expand Down Expand Up @@ -138,6 +140,7 @@ export class Logger extends LogNode {
super(config.level)
this.writers = config.writers || []
this.useEmoji = config.useEmoji === false ? false : true
this.showTimestamps = !!config.showTimestamps
this.events = new EventBus()
}

Expand Down
27 changes: 26 additions & 1 deletion core/src/logger/renderers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ export function combineRenders(entry: LogEntry, renderers: RenderFn[]): string {
return renderers.map((renderer) => renderer(entry)).join("")
}

/**
* Returns a log entries' left margin/offset. Used for determining the spinner's x coordinate.
*/
export function getLeftOffset(entry: LogEntry) {
return entry.root.showTimestamps ? leftPad(entry).length + renderTimestamp(entry).length : leftPad(entry).length
}

/**
* Returns the most recent message's `msg` field if it has `append` set to `false`.
* Otherwise returns longest chain of messages with `append: true` (starting from the most recent message).
Expand Down Expand Up @@ -114,6 +121,15 @@ export function renderSymbol(entry: LogEntry): string {
return symbol ? `${logSymbols[symbol]} ` : ""
}

export function renderTimestamp(entry: LogEntry): string {
if (!entry.root.showTimestamps) {
return ""
}

const timestamp = new Date(entry.timestamp).toISOString()
return `[${timestamp}] `
}

export function renderMsg(entry: LogEntry): string {
const { fromStdStream } = entry
const { status } = entry.getMessageState()
Expand Down Expand Up @@ -166,7 +182,16 @@ export function formatForTerminal(entry: LogEntry, type: PickFromUnion<LoggerTyp

const symbolRenderFn = type === "basic" ? renderSymbolBasic : renderSymbol

return combineRenders(entry, [leftPad, symbolRenderFn, renderSection, renderEmoji, renderMsg, renderData, () => "\n"])
return combineRenders(entry, [
renderTimestamp,
leftPad,
symbolRenderFn,
renderSection,
renderEmoji,
renderMsg,
renderData,
() => "\n",
])
}

export function cleanForJSON(input?: string | string[]): string {
Expand Down
6 changes: 3 additions & 3 deletions core/src/logger/writers/fancy-terminal-writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import elegantSpinner from "elegant-spinner"
import wrapAnsi from "wrap-ansi"
import chalk from "chalk"

import { formatForTerminal, leftPad, renderMsg, basicRender } from "../renderers"
import { formatForTerminal, renderMsg, basicRender, getLeftOffset } from "../renderers"
import { LogEntry } from "../log-entry"
import { Logger } from "../logger"
import { LogLevel } from "../log-node"
Expand Down Expand Up @@ -178,11 +178,11 @@ export class FancyTerminalWriter extends Writer {
.filter((entry) => logger.level >= entry.level)
.reduce((acc: TerminalEntry[], entry: LogEntry): TerminalEntry[] => {
let spinnerFrame = ""
let spinnerX
let spinnerX: number
let spinnerCoords: Coords | undefined

if (entry.getMessageState().status === "active") {
spinnerX = leftPad(entry).length
spinnerX = getLeftOffset(entry)
spinnerFrame = this.tickSpinner(entry.key)
spinnerCoords = [spinnerX, currentLineNumber]
} else {
Expand Down
4 changes: 4 additions & 0 deletions core/test/unit/src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ describe("cli", () => {
"json",
"--yes",
"--emoji=false",
"--show-timestamps=false",
"--force-refresh",
"--var",
"my=value,other=something",
Expand All @@ -463,6 +464,7 @@ describe("cli", () => {
"log-level": "4",
"output": "json",
"emoji": false,
"show-timestamps": false,
"yes": true,
"force-refresh": true,
"var": ["my=value", "other=something"],
Expand Down Expand Up @@ -520,6 +522,7 @@ describe("cli", () => {
"log-level": "info",
"output": undefined,
"emoji": envSupportsEmoji(),
"show-timestamps": false,
"yes": false,
"force-refresh": false,
"var": undefined,
Expand Down Expand Up @@ -588,6 +591,7 @@ describe("cli", () => {
"log-level": "info",
"output": undefined,
"emoji": envSupportsEmoji(),
"show-timestamps": false,
"yes": false,
"force-refresh": false,
"var": undefined,
Expand Down
15 changes: 15 additions & 0 deletions core/test/unit/src/logger/renderers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,21 @@ describe("renderers", () => {
expect(formatForTerminal(entry, "fancy")).to.eql("\n")
})
})
context("logger.showTimestamps is set to true", () => {
before(() => {
logger.showTimestamps = true
})
it("should include timestamp with formatted string", () => {
// Any cast so we can overwrite read only property
const entry = logger.info("hello world") as any
entry.timestamp = 1600555650583

expect(formatForTerminal(entry, "fancy")).to.equal(`[2020-09-19T22:47:30.583Z] ${msgStyle("hello world")}\n`)
})
after(() => {
logger.showTimestamps = false
})
})
})
describe("formatForJson", () => {
it("should return a JSON representation of a log entry", () => {
Expand Down
1 change: 1 addition & 0 deletions docs/reference/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ The following option flags can be used with any of the CLI commands:
| `--log-level` | `-l` | `error` `warn` `info` `verbose` `debug` `silly` `0` `1` `2` `3` `4` `5` | Set logger level. Values can be either string or numeric and are prioritized from 0 to 5 (highest to lowest) as follows: error: 0, warn: 1, info: 2, verbose: 3, debug: 4, silly: 5.
| `--output` | `-o` | `json` `yaml` | Output command result in specified format (note: disables progress logging and interactive functionality).
| `--emoji` | | boolean | Enable emoji in output (defaults to true if the environment supports it).
| `--show-timestamps` | | boolean | Show timestamps with log output.
| `--yes` | `-y` | boolean | Automatically approve any yes/no prompts during execution.
| `--force-refresh` | | boolean | Force refresh of any caches, e.g. cached provider statuses.
| `--var` | | array:string | Set a specific variable value, using the format &lt;key&gt;&#x3D;&lt;value&gt;, e.g. &#x60;--var some-key&#x3D;custom-value&#x60;. This will override any value set in your project configuration. You can specify multiple variables by separating with a comma, e.g. &#x60;--var key-a&#x3D;foo,key-b&#x3D;&quot;value with quotes&quot;&#x60;.
Expand Down

0 comments on commit f09deae

Please sign in to comment.