Skip to content

Commit

Permalink
feat: pass parent to nested log entries
Browse files Browse the repository at this point in the history
  • Loading branch information
eysi09 committed Apr 26, 2018
1 parent 814733b commit 41cddf0
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 65 deletions.
4 changes: 1 addition & 3 deletions bin/integ
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ garden_bin=${garden_root}/build/src/bin/garden.js

chmod +x ${garden_bin}

export GARDEN_LOGGER_TYPE=basic

cd ${garden_root}/examples/hello-world

${garden_bin} build --force
${garden_bin} build --force --silent
19 changes: 13 additions & 6 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import chalk from "chalk"
import { enumToArray, shutdown } from "./util"
import { merge, intersection, reduce } from "lodash"
import {
BooleanParameter,
Command,
ChoicesParameter,
ParameterValues,
Expand Down Expand Up @@ -44,6 +45,11 @@ const GLOBAL_OPTIONS = {
help: "override project root directory (defaults to working directory)",
defaultValue: process.cwd(),
}),
silent: new BooleanParameter({
alias: "s",
help: "suppress log output",
defaultValue: false,
}),
env: new EnvironmentOption(),
loglevel: new ChoicesParameter({
alias: "log",
Expand Down Expand Up @@ -193,7 +199,6 @@ export class GardenCli {

constructor() {
const version = require("../package.json").version

this.logger = getLogger()
this.program = sywac
.help("-h, --help", {
Expand Down Expand Up @@ -261,22 +266,24 @@ export class GardenCli {
}

const action = async argv => {
const logger = this.logger

// Sywac returns positional args and options in a single object which we separate into args and opts
const argsForAction = filterByArray(argv, argKeys)
const optsForAction = filterByArray(argv, optKeys.concat(globalKeys))
const root = resolve(process.cwd(), optsForAction.root)
const env = optsForAction.env

// Update logger config
const level = LogLevel[<string>argv.loglevel]
// Update logger
const logger = this.logger
const { loglevel, silent } = optsForAction
const level = LogLevel[<string>loglevel]
logger.level = level
if (level !== LogLevel.silent) {
if (!silent) {
logger.writers.push(
new FileWriter({ level, root }),
new FileWriter({ level: LogLevel.error, filename: ERROR_LOG_FILENAME, root }),
)
} else {
logger.writers = []
}

const garden = await Garden.factory(root, { env, logger })
Expand Down
43 changes: 23 additions & 20 deletions src/logger/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import {
LogEntryOpts,
LogSymbolType,
} from "./types"
import { FancyConsoleWriter, Writer, BasicConsoleWriter } from "./writers"
import { BasicConsoleWriter, FancyConsoleWriter, Writer } from "./writers"
import { ParameterError } from "../exceptions"

const ROOT_DEPTH = -1
const DEFAULT_CONFIGS: { [key in LoggerType]: LoggerConfig } = {
const CONFIG_TYPES: { [key in LoggerType]: LoggerConfig } = {
[LoggerType.fancy]: {
level: LogLevel.info,
writers: [new FancyConsoleWriter()],
Expand All @@ -52,19 +52,25 @@ export interface LogEntryConstructor {
opts: LogEntryOpts
depth: number
root: RootLogNode
parentEntry?: LogEntry
}

let loggerInstance: RootLogNode
let defaultLoggerType: LoggerType = LoggerType.fancy
let defaultLoggerConfig: LoggerConfig = DEFAULT_CONFIGS[defaultLoggerType]

function createLogEntry(level: LogLevel, opts: LogEntryOpts, parent: LogNode) {
const { depth, root } = parent
let loggerType: LoggerType = LoggerType.fancy
let loggerConfig: LoggerConfig = CONFIG_TYPES[loggerType]

function createLogEntry(level: LogLevel, opts: LogEntryOpts, parentNode: LogNode) {
const { depth, root } = parentNode
let parentEntry
if (parentNode.depth > ROOT_DEPTH) {
parentEntry = parentNode
}
const params = {
depth: depth + 1,
root,
level,
opts,
parentEntry,
}
return new LogEntry(params)
}
Expand Down Expand Up @@ -140,11 +146,13 @@ export class LogEntry extends LogNode {
public timestamp: number
public level: LogLevel
public depth: number
public parentEntry: LogEntry | undefined
public children: LogEntry[]

constructor({ level, opts, depth, root }: LogEntryConstructor) {
constructor({ level, opts, depth, root, parentEntry }: LogEntryConstructor) {
super(level, depth)
this.root = root
this.parentEntry = parentEntry
this.opts = opts
if (opts.entryStyle === EntryStyle.activity) {
this.status = EntryStatus.ACTIVE
Expand Down Expand Up @@ -202,7 +210,6 @@ export class LogEntry extends LogNode {
return this
}

// public setSuccess: UpdateLogEntry = (entryVal: CreateLogEntryParam = {}): LogEntry => {
public setSuccess: UpdateLogEntry = (entryVal: UpdateLogEntryParam = {}): LogEntry => {
this.deepSetState({ ...makeLogOpts(entryVal), symbol: LogSymbolType.success }, EntryStatus.SUCCESS)
this.root.onGraphChange(this)
Expand Down Expand Up @@ -291,21 +298,17 @@ export class RootLogNode extends LogNode {

}

export function getLogger(config?: LoggerConfig) {
export function getLogger() {
if (!loggerInstance) {
loggerInstance = new RootLogNode(config || defaultLoggerConfig)
loggerInstance = new RootLogNode(loggerConfig)
}

return loggerInstance
}

export function setDefaultLoggerType(loggerType: LoggerType) {
defaultLoggerType = loggerType
defaultLoggerConfig = DEFAULT_CONFIGS[loggerType]
}

export function setDefaultLoggerConfig(config: LoggerConfig) {
defaultLoggerConfig = config
export function setLoggerType(type: LoggerType) {
loggerType = type
loggerConfig = CONFIG_TYPES[type]
}

// allow configuring logger type via environment variable
Expand All @@ -320,7 +323,7 @@ if (process.env.GARDEN_LOGGER_TYPE) {
})
}

defaultLoggerType = type
defaultLoggerConfig = DEFAULT_CONFIGS[type]
setLoggerType(type)

getLogger().debug(`Setting logger type to ${type} (from GARDEN_LOGGER_TYPE)`)
}
4 changes: 4 additions & 0 deletions src/logger/renderers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export function combine(renderers: Renderers): string {

/*** RENDERERS ***/
export function leftPad(entry: LogEntry): string {
const { parentEntry } = entry
if (parentEntry && parentEntry.opts.unindentChildren) {
return ""
}
return padStart("", entry.depth * 3)
}

Expand Down
9 changes: 2 additions & 7 deletions src/logger/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { GardenError } from "../exceptions"
export type EmojiName = keyof typeof nodeEmoji.emoji

export enum LogLevel {
silent = -1,
error = 0,
warn = 1,
info = 2,
Expand All @@ -28,7 +27,6 @@ export enum LoggerType {
quiet = "quiet",
}

// Defines entry style and format (only one available style at the moment)
export enum EntryStyle {
activity = "activity",
error = "error",
Expand All @@ -51,11 +49,7 @@ export enum EntryStatus {
WARN = "warn",
}

export interface HeaderOpts {
emoji?: string
command: string
}

// TODO Split up
export interface LogEntryOpts {
msg?: string | string[]
section?: string
Expand All @@ -67,4 +61,5 @@ export interface LogEntryOpts {
showDuration?: boolean
error?: GardenError | Error
id?: string
unindentChildren?: boolean
}
17 changes: 10 additions & 7 deletions src/logger/writers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ const DEFAULT_FILE_TRANSPORT_OPTIONS = {
}

const levelToStr = (lvl: LogLevel): string => LogLevel[lvl]
const isEntryValid = (level: LogLevel, entry: LogEntry): boolean => {
return level >= entry.level && entry.opts.msg !== undefined
}

export interface WriterConfig {
level?: LogLevel
Expand Down Expand Up @@ -100,7 +103,7 @@ export class FileWriter extends Writer {

render(entry: LogEntry): string | null {
const renderFn = entry.level === LogLevel.error ? renderError : renderMsg
if (entry.opts.msg && this.level >= entry.level) {
if (isEntryValid(this.level, entry)) {
return stripAnsi(renderFn(entry))
}
return null
Expand Down Expand Up @@ -144,7 +147,7 @@ export class BasicConsoleWriter extends Writer {

render(entry: LogEntry, rootLogNode: RootLogNode): string | null {
const level = this.level || rootLogNode.level
if (level >= entry.level) {
if (isEntryValid(level, entry)) {
return formatForConsole(entry)
}
return null
Expand Down Expand Up @@ -246,10 +249,10 @@ export class FancyConsoleWriter extends Writer {
}
}

/*
Has a side effect in that it starts/stops the rendering loop depending on
whether or not active entries were found while building output
*/
/**
* Has a side effect in that it starts/stops the rendering loop depending on
* whether or not active entries were found while building output
*/
public render(rootLogNode: RootLogNode): string[] | null {
let hasActiveEntries = false
const level = this.level || rootLogNode.level
Expand All @@ -272,7 +275,7 @@ export class FancyConsoleWriter extends Writer {
hasActiveEntries = true
spinnerFrame = this.readOrSetSpinner(idx)
}
if (level >= entry.level) {
if (isEntryValid(level, entry)) {
const formatted = this.readerOrSetFormattedEntry(entry, idx)
const startPos = leftPad(entry).length
const withSpinner = spinnerFrame
Expand Down
4 changes: 2 additions & 2 deletions test/setup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { LoggerType } from "../src/logger/types"
import { setDefaultLoggerType } from "../src/logger"
import { setLoggerType, getLogger } from "../src/logger"

// Global before hooks
before(() => {
setDefaultLoggerType(LoggerType.quiet)
setLoggerType(LoggerType.quiet)
})
76 changes: 56 additions & 20 deletions test/src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe("RootLogNode", () => {
})

describe("addNode", () => {
it("should add new child entries to respective node", () => {
it("should add new child entries to the respective node", () => {
const prevLength = logger.children.length
const entry = logger.children[0]
const nested = entry.info("nested")
Expand All @@ -78,32 +78,68 @@ describe("RootLogNode", () => {
})

describe("BasicConsoleWriter.render", () => {
it("should return a string if log level is geq than entry level", () => {
const writer = new BasicConsoleWriter({ level: LogLevel.silent })
const logger = new RootLogNode({ level: LogLevel.silent })
it("should return a string if level is geq than entry level and entry contains a message", () => {
const logger = new RootLogNode({ level: LogLevel.info })
const writer = new BasicConsoleWriter()
const entry = logger.info("")
const out1 = writer.render(entry, logger)
writer.level = LogLevel.verbose
const out2 = writer.render(entry, logger)

expect(out1).to.be.a("null")
expect(out2).to.be.a("string")
const out = writer.render(entry, logger)
expect(out).to.eql("")
})
it("should override root level if level is set", () => {
const logger = new RootLogNode({ level: LogLevel.info })
const writer = new BasicConsoleWriter({ level: LogLevel.verbose })
const entry = logger.verbose("")
const out = writer.render(entry, logger)
expect(out).to.eql("")
})
it("should return null if entry level is geq to writer level", () => {
const logger = new RootLogNode({ level: LogLevel.info })
const writer = new BasicConsoleWriter()
const entry = logger.verbose("")
const out = writer.render(entry, logger)
expect(out).to.eql(null)
})
it("should return null if entry has no message", () => {
const logger = new RootLogNode({ level: LogLevel.info })
const writer = new BasicConsoleWriter()
const entry = logger.info({})
const out = writer.render(entry, logger)
expect(out).to.eql(null)
})
})

describe("FancyConsoleWriter.render", () => {
it("should return an array of strings if log level is geq than respective entry level", () => {
const writer = new FancyConsoleWriter({ level: LogLevel.silent })
const logger = new RootLogNode({ level: LogLevel.silent })
it("should return an array of strings if level is geq than entry level and entry contains a message", () => {
const logger = new RootLogNode({ level: LogLevel.info })
const writer = new FancyConsoleWriter()
const entry = logger.info("")
const out1 = writer.render(logger)
writer.level = LogLevel.verbose
const out2 = writer.render(logger)

const out = writer.render(logger)
writer.stop()

expect(out1).to.be.a("null")
expect(out2).to.be.an("array").of.length(1)
expect(out).to.eql(["\n"])
})
it("should override root level if level is set", () => {
const logger = new RootLogNode({ level: LogLevel.info })
const writer = new FancyConsoleWriter({ level: LogLevel.verbose })
writer.stop()
const entry = logger.verbose("")
const out = writer.render(logger)
expect(out).to.eql(["\n"])
})
it("should return null if entry level is geq to writer level", () => {
const logger = new RootLogNode({ level: LogLevel.info })
const writer = new FancyConsoleWriter()
writer.stop()
const entry = logger.verbose("")
const out = writer.render(logger)
expect(out).to.eql(null)
})
it("should return null if entry has no message", () => {
const logger = new RootLogNode({ level: LogLevel.info })
const writer = new FancyConsoleWriter()
writer.stop()
const entry = logger.info({})
const out = writer.render(logger)
expect(out).to.eql(null)
})
})

Expand Down

0 comments on commit 41cddf0

Please sign in to comment.