Skip to content

Commit

Permalink
fix: better handling of streams not from logger
Browse files Browse the repository at this point in the history
  • Loading branch information
eysi09 committed Apr 25, 2018
1 parent c795235 commit 42fa17e
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 28 deletions.
13 changes: 9 additions & 4 deletions src/logger/renderers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as logSymbols from "log-symbols"
import * as nodeEmoji from "node-emoji"
import * as yaml from "js-yaml"
import chalk from "chalk"
import { curryRight, flow, padEnd, padStart } from "lodash"
import { curryRight, flow, isArray, padEnd, padStart } from "lodash"
import hasAnsi = require("has-ansi")

import { duration } from "./util"
Expand All @@ -30,7 +30,7 @@ const truncate = (s: string) => s.length > sectionPrefixWidth
: s
const sectionStyle = (s: string) => chalk.cyan.italic(padEnd(truncate(s), sectionPrefixWidth))
const msgStyle = (s: string) => hasAnsi(s) ? s : chalk.gray(s)
const errorStyle = (s: string) => hasAnsi(s) ? s : chalk.red(s)
const errorStyle = chalk.red

/*** RENDER HELPERS ***/
function insertVal(out: string[], idx: number, toRender: Function | string, renderArgs: any[]): string[] {
Expand Down Expand Up @@ -88,9 +88,14 @@ export function renderSymbol(entry: LogEntry): string {
}

export function renderMsg(entry: LogEntry): string {
const { entryStyle, msg } = entry.opts
const { entryStyle, msg, notOriginatedFromLogger } = entry.opts

if (notOriginatedFromLogger) {
return isArray(msg) ? msg.join(" ") : msg || ""
}

const styleFn = entryStyle === EntryStyle.error ? errorStyle : msgStyle
if (msg && msg instanceof Array) {
if (isArray(msg)) {
return msg.map(styleFn).join(chalk.gray(" → "))
}
return msg ? styleFn(msg) : ""
Expand Down
14 changes: 8 additions & 6 deletions src/logger/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,14 @@ interface StreamWriteExtraParam {
noIntercept?: boolean
}

// Intercepts the write method of a WriteableStream and calls the provided callback on the
// string to write (or optionally applies the string to the write method)
// Returns a function which sets the write back to default.
//
// Used e.g. by FancyLogger so that writes from other sources can be intercepted
// and pushed to the log stack.
/**
* Intercepts the write method of a WriteableStream and calls the provided callback on the
* string to write (or optionally applies the string to the write method)
* Returns a function which sets the write back to default.
*
* Used e.g. by FancyLogger so that writes from other sources can be intercepted
* and pushed to the log stack.
*/
export function interceptStream(stream: NodeJS.WritableStream, callback: Function) {
const prevWrite = stream.write

Expand Down
53 changes: 35 additions & 18 deletions src/logger/writers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export class FancyConsoleWriter extends Writer {
private formattedEntries: string[]
private logUpdate: any
private intervalID: number | null
public persistedAtIdx: number

public level: LogLevel

Expand All @@ -173,6 +174,7 @@ export class FancyConsoleWriter extends Writer {
this.intervalID = null
this.formattedEntries = [] // Entries are cached on format
this.spinners = [] // Each entry has it's own spinner
this.persistedAtIdx = 0
}

private initLogUpdate(rootLogNode: RootLogNode): any {
Expand All @@ -182,18 +184,17 @@ export class FancyConsoleWriter extends Writer {
write: (str, enc, cb) => (<any>process.stdout.write)(str, enc, cb, { noIntercept: true }),
}
const makeOpts = msg => ({
// Remove trailing new line from console writes since Logger already handles it
msg: typeof msg === "string" ? msg.replace(/\n$/, "") : msg,
msg,
notOriginatedFromLogger: true,
})
/*
NOTE: On every write, log-update library calls the cli-cursor library to hide the cursor
which the cli-cursor library does via stderr write. This causes an infinite loop as
the stderr writes are intercepted and funneled back to the Logger.
Therefore we manually toggle the cursor using the custom stream from above.
log-update types are missing the `opts?: {showCursor?: boolean}` parameter
*/
/**
* NOTE: On every write, log-update library calls the cli-cursor library to hide the cursor
* which the cli-cursor library does via stderr write. This causes an infinite loop as
* the stderr writes are intercepted and funneled back to the Logger.
* Therefore we manually toggle the cursor using the custom stream from above.
*
* log-update types are missing the `opts?: {showCursor?: boolean}` parameter
*/
const customLogUpdate = (<any>logUpdate.create)(<any>stream, { showCursor: true })
cliCursor.hide(stream)

Expand Down Expand Up @@ -241,7 +242,7 @@ export class FancyConsoleWriter extends Writer {
private updateStream(rootLogNode: RootLogNode): void {
const out = this.render(rootLogNode)
if (out) {
this.logUpdate(out.join("\n"))
this.logUpdate(out.join(""))
}
}

Expand All @@ -254,13 +255,19 @@ export class FancyConsoleWriter extends Writer {
const level = this.level || rootLogNode.level
const entries = <any>getChildNodes(rootLogNode)

/*
This is a bit ugly for performance sake.
Rather than just creating a new string with an updated spinner frame in each render cycle
we instead cache the formatted string and splice the updated frame into it.
*/
const out = entries.reduce((acc: string[], entry: LogEntry, idx: number): string[] => {
/**
* This is a bit ugly for performance sake.
* Rather than just creating a new string with an updated spinner frame in each render cycle
* we instead cache the formatted string and splice the updated frame into it.
*/
const out = entries.slice(this.persistedAtIdx).reduce((acc: string[], entry: LogEntry, idx: number): string[] => {
let spinnerFrame = ""

if (entry.notOriginatedFromLogger()) {
acc.push(renderMsg(entry))
return acc
}

if (entry.status === EntryStatus.ACTIVE) {
hasActiveEntries = true
spinnerFrame = this.readOrSetSpinner(idx)
Expand All @@ -271,7 +278,7 @@ export class FancyConsoleWriter extends Writer {
const withSpinner = spinnerFrame
? `${formatted.slice(0, startPos)}${spinnerStyle(spinnerFrame)} ${formatted.slice(startPos)}`
: formatted
acc.push(withSpinner)
acc.push(withSpinner + "\n")
}
return acc
}, [])
Expand Down Expand Up @@ -300,6 +307,16 @@ export class FancyConsoleWriter extends Writer {
public stop(): void {
this.stopLoop()
this.logUpdate && this.logUpdate.cleanUp()
this.logUpdate = null
}

/**
* Escape hatch for reclaiming the stream, e.g. when reading stdin.
* Logger will then continue afterwards but won't be able to update the previous content
*/
public stopAndPersist(rootLogNode: RootLogNode): void {
this.stop()
this.persistedAtIdx = rootLogNode.children.length
}

}

0 comments on commit 42fa17e

Please sign in to comment.