diff --git a/garden-service/src/commands/logs.ts b/garden-service/src/commands/logs.ts index bcef3a763c..f25e23be0e 100644 --- a/garden-service/src/commands/logs.ts +++ b/garden-service/src/commands/logs.ts @@ -95,7 +95,7 @@ export class LogsCommand extends Command { }) await Bluebird.map(services, async (service: Service) => { - const voidLog = log.placeholder(LogLevel.silly) + const voidLog = log.placeholder(LogLevel.silly, { preserveLevel: true }) const status = await garden.actions.getServiceStatus({ log: voidLog, service, hotReload: false }) if (status.state === "ready" || status.state === "outdated") { diff --git a/garden-service/src/logger/log-entry.ts b/garden-service/src/logger/log-entry.ts index 282cb170e0..34aef24d4c 100644 --- a/garden-service/src/logger/log-entry.ts +++ b/garden-service/src/logger/log-entry.ts @@ -11,7 +11,7 @@ import * as nodeEmoji from "node-emoji" import { flatten } from "lodash" import { LogNode, LogLevel } from "./log-node" -import { getChildEntries } from "./util" +import { getChildEntries, findParentEntry } from "./util" import { GardenError } from "../exceptions" import { Omit } from "../util/util" import { Logger } from "./logger" @@ -31,6 +31,7 @@ export interface UpdateOpts { error?: GardenError status?: EntryStatus indent?: number + preserveLevel?: boolean } export interface CreateOpts extends UpdateOpts { @@ -104,12 +105,16 @@ export class LogEntry extends LogNode { } protected createNode(level: LogLevel, param: CreateParam) { - // A child entry must not have a higher level than its parent - const childLevel = this.level > level ? this.level : level const opts = { indent: (this.opts.indent || 0) + 1, ...resolveParam(param), } + + // If preserveLevel is set to true, all children must have a level geq the level + // of the parent entry that set the flag. + const parentWithPreserveFlag = findParentEntry(this, entry => !!entry.opts.preserveLevel) + const childLevel = parentWithPreserveFlag ? Math.max(parentWithPreserveFlag.level, level) : level + return new LogEntry({ opts, level: childLevel, @@ -122,10 +127,10 @@ export class LogEntry extends LogNode { this.root.onGraphChange(node) } - placeholder(level: LogLevel = LogLevel.info): LogEntry { + placeholder(level: LogLevel = LogLevel.info, param? : CreateParam): LogEntry { // Ensure placeholder child entries align with parent context const indent = Math.max((this.opts.indent || 0) - 1, - 1) - return this.appendNode(level, { indent }) + return this.appendNode(level, { ...resolveParam(param), indent }) } // Preserves status diff --git a/garden-service/src/logger/log-node.ts b/garden-service/src/logger/log-node.ts index c1b561e503..e04d43d9f5 100644 --- a/garden-service/src/logger/log-node.ts +++ b/garden-service/src/logger/log-node.ts @@ -42,7 +42,7 @@ export abstract class LogNode { * A placeholder entry is an empty entry whose children should be aligned with the parent context. * Useful for setting a placeholder in the middle of the log that can later be populated. */ - abstract placeholder(level: LogLevel): LogEntry + abstract placeholder(level: LogLevel, param?: CreateParam): LogEntry protected appendNode(level: LogLevel, param: CreateParam): LogEntry { const node = this.createNode(level, param) diff --git a/garden-service/src/logger/util.ts b/garden-service/src/logger/util.ts index a13b6d65ac..646d7ff782 100644 --- a/garden-service/src/logger/util.ts +++ b/garden-service/src/logger/util.ts @@ -44,6 +44,12 @@ export function getChildEntries(node: LogNode): LogEntry[] { return getChildNodes(node) } +export function findParentEntry(entry: LogEntry, predicate: ProcessNode): LogEntry | null { + return predicate(entry) + ? entry + : entry.parent ? findParentEntry(entry.parent, predicate) : null +} + export function findLogNode(node: LogNode, predicate: ProcessNode): LogEntry | void { let found: LogEntry | undefined traverseChildren(node, entry => {