From b391c96e641ae5fe79d71336fa0201e6f91a73a8 Mon Sep 17 00:00:00 2001 From: Cameron Diver Date: Tue, 28 May 2019 16:56:39 +0100 Subject: [PATCH] Allow multiple services to be tailed with balena logs and push Also correctly type the input. Change-type: patch Signed-off-by: Cameron Diver --- doc/cli.markdown | 7 +++++-- lib/actions/logs.ts | 26 ++++++++++++++++++-------- lib/actions/push.ts | 36 ++++++++++++++++++++++-------------- lib/utils/device/deploy.ts | 11 ++++++++--- lib/utils/device/logs.ts | 16 ++++++++-------- 5 files changed, 61 insertions(+), 35 deletions(-) diff --git a/doc/cli.markdown b/doc/cli.markdown index 949476ce..eb81e222 100644 --- a/doc/cli.markdown +++ b/doc/cli.markdown @@ -865,6 +865,7 @@ Examples: $ balena logs 192.168.0.31 $ balena logs 192.168.0.31 --service my-service + $ balena logs 192.168.0.31 --service my-service-1 --service my-service-2 $ balena logs 23c73a1.local --system $ balena logs 23c73a1.local --system --service my-service @@ -877,7 +878,8 @@ continuously stream output #### --service, -s <service> -Only show logs for a single service. This can be used in combination with --system +Reject logs not originating from this service. +This can be used in combination with --system or other --service flags. #### --system, -S @@ -1444,7 +1446,8 @@ Don't tail application logs when pushing to a local mode device #### --service <service> -Only show logs from a single service. This can be used in combination with --system. +Reject logs not originating from this service. +This can be used in combination with --system and other --service flags. Only valid when pushing to a local mode device. #### --system diff --git a/lib/actions/logs.ts b/lib/actions/logs.ts index 28d21a3a..907a9728 100644 --- a/lib/actions/logs.ts +++ b/lib/actions/logs.ts @@ -38,9 +38,9 @@ export const logs: CommandDefinition< uuidOrDevice: string; }, { - tail: boolean; - service: string; - system: boolean; + tail?: boolean; + service?: [string] | string; + system?: boolean; } > = { signature: 'logs ', @@ -66,6 +66,7 @@ export const logs: CommandDefinition< $ balena logs 192.168.0.31 $ balena logs 192.168.0.31 --service my-service + $ balena logs 192.168.0.31 --service my-service-1 --service my-service-2 $ balena logs 23c73a1.local --system $ balena logs 23c73a1.local --system --service my-service`, @@ -78,8 +79,9 @@ export const logs: CommandDefinition< }, { signature: 'service', - description: - 'Only show logs for a single service. This can be used in combination with --system', + description: stripIndent` + Reject logs not originating from this service. + This can be used in combination with --system or other --service flags.`, parameter: 'service', alias: 's', }, @@ -95,6 +97,7 @@ export const logs: CommandDefinition< async action(params, options, done) { normalizeUuidProp(params); const balena = (await import('balena-sdk')).fromSharedOptions(); + const isArray = await import('lodash/isArray'); const { serviceIdToName } = await import('../utils/cloud'); const { displayDeviceLogs, displayLogObject } = await import( '../utils/device/logs' @@ -107,6 +110,13 @@ export const logs: CommandDefinition< const logger = new Logger(); + const servicesToDisplay = + options.service != null + ? isArray(options.service) + ? options.service + : [options.service] + : undefined; + const displayCloudLog = async (line: CloudLog) => { if (!line.isSystem) { let serviceName = await serviceIdToName(balena, line.serviceId); @@ -117,14 +127,14 @@ export const logs: CommandDefinition< { serviceName, ...line }, logger, options.system || false, - options.service, + servicesToDisplay, ); } else { displayLogObject( line, logger, options.system || false, - options.service, + servicesToDisplay, ); } }; @@ -151,7 +161,7 @@ export const logs: CommandDefinition< logStream, logger, options.system || false, - options.service, + servicesToDisplay, ); } else { exitIfNotLoggedIn(); diff --git a/lib/actions/push.ts b/lib/actions/push.ts index 593148be..fc32a076 100644 --- a/lib/actions/push.ts +++ b/lib/actions/push.ts @@ -105,16 +105,16 @@ export const push: CommandDefinition< applicationOrDevice_raw: string; }, { - source: string; - emulated: boolean; - dockerfile: string; // DeviceDeployOptions.dockerfilePath (alternative Dockerfile) - nocache: boolean; - 'registry-secrets': string; - live: boolean; - detached: boolean; - service: string; - system: boolean; - env: string | string[]; + source?: string; + emulated?: boolean; + dockerfile?: string; // DeviceDeployOptions.dockerfilePath (alternative Dockerfile) + nocache?: boolean; + 'registry-secrets'?: string; + live?: boolean; + detached?: boolean; + service?: string | string[]; + system?: boolean; + env?: string | string[]; } > = { signature: 'push ', @@ -215,7 +215,8 @@ export const push: CommandDefinition< { signature: 'service', description: stripIndent` - Only show logs from a single service. This can be used in combination with --system. + Reject logs not originating from this service. + This can be used in combination with --system and other --service flags. Only valid when pushing to a local mode device.`, parameter: 'service', }, @@ -243,6 +244,7 @@ export const push: CommandDefinition< async action(params, options, done) { const sdk = (await import('balena-sdk')).fromSharedOptions(); const Bluebird = await import('bluebird'); + const isArray = await import('lodash/isArray'); const remote = await import('../utils/remote-build'); const deviceDeploy = await import('../utils/device/deploy'); const { exitIfNotLoggedIn, exitWithExpectedError } = await import( @@ -312,8 +314,8 @@ export const push: CommandDefinition< async (token, baseUrl, owner) => { const opts = { dockerfilePath, - emulated: options.emulated, - nocache: options.nocache, + emulated: options.emulated || false, + nocache: options.nocache || false, registrySecrets, }; const args = { @@ -332,6 +334,12 @@ export const push: CommandDefinition< break; case BuildTarget.Device: const device = appOrDevice; + const servicesToDisplay = + options.service != null + ? isArray(options.service) + ? options.service + : [options.service] + : undefined; // TODO: Support passing a different port await Bluebird.resolve( deviceDeploy.deployToDevice({ @@ -342,7 +350,7 @@ export const push: CommandDefinition< nocache: options.nocache || false, live: options.live || false, detached: options.detached || false, - service: options.service, + services: servicesToDisplay, system: options.system || false, env: typeof options.env === 'string' diff --git a/lib/utils/device/deploy.ts b/lib/utils/device/deploy.ts index c5059c88..f4c586d5 100644 --- a/lib/utils/device/deploy.ts +++ b/lib/utils/device/deploy.ts @@ -48,7 +48,7 @@ export interface DeviceDeployOptions { nocache: boolean; live: boolean; detached: boolean; - service?: string; + services?: string[]; system: boolean; env: string[]; } @@ -236,7 +236,7 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise { const logStream = await api.getLogStream(); globalLogger.logInfo('Streaming device logs...'); promises.push( - displayDeviceLogs(logStream, globalLogger, opts.system, opts.service), + displayDeviceLogs(logStream, globalLogger, opts.system, opts.services), ); } else { globalLogger.logLivepush( @@ -255,7 +255,12 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise { // Now all we need to do is stream back the logs const logStream = await api.getLogStream(); globalLogger.logInfo('Streaming device logs...'); - await displayDeviceLogs(logStream, globalLogger, opts.system, opts.service); + await displayDeviceLogs( + logStream, + globalLogger, + opts.system, + opts.services, + ); } } diff --git a/lib/utils/device/logs.ts b/lib/utils/device/logs.ts index 165cd915..0a88e2f5 100644 --- a/lib/utils/device/logs.ts +++ b/lib/utils/device/logs.ts @@ -37,11 +37,11 @@ export function displayDeviceLogs( logs: Readable, logger: Logger, system: boolean, - filterService?: string, + filterServices?: string[], ): Bluebird { return new Bluebird((resolve, reject) => { logs.on('data', log => { - displayLogLine(log, logger, system, filterService); + displayLogLine(log, logger, system, filterServices); }); logs.on('error', reject); @@ -64,11 +64,11 @@ function displayLogLine( log: string | Buffer, logger: Logger, system: boolean, - filterService?: string, + filterServices?: string[], ): void { try { const obj: Log = JSON.parse(log.toString()); - displayLogObject(obj, logger, system, filterService); + displayLogObject(obj, logger, system, filterServices); } catch (e) { logger.logDebug(`Dropping device log due to failed parsing: ${e}`); } @@ -78,7 +78,7 @@ export function displayLogObject( obj: T, logger: Logger, system: boolean, - filterService?: string, + filterServices?: string[], ): void { let toPrint: string; if (obj.timestamp != null) { @@ -88,8 +88,8 @@ export function displayLogObject( } if (obj.serviceName != null) { - if (filterService) { - if (obj.serviceName !== filterService) { + if (filterServices) { + if (!_.includes(filterServices, obj.serviceName)) { return; } } else if (system) { @@ -99,7 +99,7 @@ export function displayLogObject( const colourFn = getServiceColourFn(obj.serviceName); toPrint += ` ${colourFn(`[${obj.serviceName}]`)}`; - } else if (filterService != null && !system) { + } else if (filterServices != null && !system) { // We have a system log here but we are filtering based // on a service, so drop this too return;