Merge pull request #1906 from balena-io/convert-logs-oclif

Convert `logs` command to oclif
This commit is contained in:
bulldozer-balena[bot] 2020-07-06 10:45:22 +00:00 committed by GitHub
commit dec92a3d9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 202 additions and 182 deletions

View File

@ -101,7 +101,7 @@ const capitanoDoc = {
},
{
title: 'Logs',
files: ['build/actions/logs.js'],
files: ['build/actions-oclif/logs.js'],
},
{
title: 'Network',

View File

@ -208,7 +208,7 @@ Users are encouraged to regularly update the balena CLI to the latest version.
- Logs
- [logs <uuidOrDevice>](#logs-uuidordevice)
- [logs <device>](#logs-device)
- Network
@ -1307,9 +1307,9 @@ answer "yes" to all questions (non interactive use)
# Logs
## logs <uuidOrDevice>
## logs <device>
Use this command to show logs for a specific device.
Show logs for a specific device.
By default, the command prints all log messages and exits.
@ -1322,30 +1322,38 @@ when this command is provided a local mode device.
Logs from a single service can be displayed with the --service flag. Just system logs
can be shown with the --system flag. Note that these flags can be used together.
Note: --service and --system flags must come after the device parameter, as per examples.
Examples:
$ balena logs 23c73a1
$ balena logs 23c73a1 --tail
$ 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
### Arguments
#### DEVICE
device UUID, IP, or .local address
### Options
#### --tail, -t
#### -t, --tail
continuously stream output
#### --service, -s <service>
#### -s, --service SERVICE
Reject logs not originating from this service.
This can be used in combination with --system or other --service flags.
#### --system, -S
#### -S, --system
Only show system logs. This can be used in combination with --service.

183
lib/actions-oclif/logs.ts Normal file
View File

@ -0,0 +1,183 @@
/**
* @license
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { flags } from '@oclif/command';
import Command from '../command';
import * as cf from '../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../utils/lazy';
import { LogMessage } from 'balena-sdk';
import { IArg } from '@oclif/parser/lib/args';
interface FlagsDef {
tail?: boolean;
service?: string[];
system?: boolean;
help: void;
}
interface ArgsDef {
device: string;
}
export default class LogsCmd extends Command {
public static description = stripIndent`
Show device logs.
Show logs for a specific device.
By default, the command prints all log messages and exits.
To continuously stream output, and see new logs in real time, use the \`--tail\` option.
If an IP or .local address is passed to this command, logs are displayed from
a local mode device with that address. Note that --tail is implied
when this command is provided a local mode device.
Logs from a single service can be displayed with the --service flag. Just system logs
can be shown with the --system flag. Note that these flags can be used together.
Note: --service and --system flags must come after the device parameter, as per examples.
`;
public static examples = [
'$ balena logs 23c73a1',
'$ balena logs 23c73a1 --tail',
'',
'$ 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',
];
public static args: Array<IArg<any>> = [
{
name: 'device',
description: 'device UUID, IP, or .local address',
required: true,
},
];
public static usage = 'logs <device>';
public static flags: flags.Input<FlagsDef> = {
tail: flags.boolean({
description: 'continuously stream output',
char: 't',
}),
service: flags.string({
description: stripIndent`
Reject logs not originating from this service.
This can be used in combination with --system or other --service flags.`,
char: 's',
multiple: true,
}),
system: flags.boolean({
description:
'Only show system logs. This can be used in combination with --service.',
char: 'S',
}),
help: cf.help,
};
public static primary = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
LogsCmd,
);
const balena = getBalenaSdk();
const { ExpectedError } = await import('../errors');
const { serviceIdToName } = await import('../utils/cloud');
const { displayDeviceLogs, displayLogObject } = await import(
'../utils/device/logs'
);
const { validateIPAddress, validateDotLocalUrl } = await import(
'../utils/validation'
);
const Logger = await import('../utils/logger');
const logger = Logger.getLogger();
const displayCloudLog = async (line: LogMessage) => {
if (!line.isSystem) {
let serviceName = await serviceIdToName(balena, line.serviceId);
if (serviceName == null) {
serviceName = 'Unknown service';
}
displayLogObject(
{ serviceName, ...line },
logger,
options.system || false,
options.service,
);
} else {
displayLogObject(
line,
logger,
options.system || false,
options.service,
);
}
};
if (
validateIPAddress(params.device) ||
validateDotLocalUrl(params.device)
) {
// Logs from local device
const { DeviceAPI } = await import('../utils/device/api');
const deviceApi = new DeviceAPI(logger, params.device);
logger.logDebug('Checking we can access device');
try {
await deviceApi.ping();
} catch (e) {
throw new ExpectedError(
`Cannot access device at address ${params.device}. Device may not be in local mode.`,
);
}
logger.logDebug('Streaming logs');
const logStream = await deviceApi.getLogStream();
await displayDeviceLogs(
logStream,
logger,
options.system || false,
options.service,
);
} else {
// Logs from cloud
await Command.checkLoggedIn();
if (options.tail) {
const logStream = await balena.logs.subscribe(params.device, {
count: 100,
});
// Never resolve (quit with CTRL-C), but reject on a broken connection
await new Promise((_resolve, reject) => {
logStream.on('line', displayCloudLog);
logStream.on('error', reject);
});
} else {
const logMessages = await balena.logs.history(params.device);
for (const logMessage of logMessages) {
await displayCloudLog(logMessage);
}
}
}
}
}

View File

@ -17,7 +17,6 @@ limitations under the License.
export * as config from './config';
export * as help from './help';
export * as local from './local';
export * as logs from './logs';
export * as os from './os';
export * as push from './push';
export * as util from './util';

View File

@ -1,168 +0,0 @@
/*
Copyright 2016-2019 Balena
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import type { LogMessage } from 'balena-sdk';
import type { CommandDefinition } from 'capitano';
import { getBalenaSdk, stripIndent } from '../utils/lazy';
import { normalizeUuidProp } from '../utils/normalization';
import { validateDotLocalUrl } from '../utils/validation';
export const logs: CommandDefinition<
{
uuidOrDevice: string;
},
{
tail?: boolean;
service?: [string] | string;
system?: boolean;
}
> = {
signature: 'logs <uuidOrDevice>',
description: 'show device logs',
help: stripIndent`
Use this command to show logs for a specific device.
By default, the command prints all log messages and exits.
To continuously stream output, and see new logs in real time, use the \`--tail\` option.
If an IP or .local address is passed to this command, logs are displayed from
a local mode device with that address. Note that --tail is implied
when this command is provided a local mode device.
Logs from a single service can be displayed with the --service flag. Just system logs
can be shown with the --system flag. Note that these flags can be used together.
Examples:
$ balena logs 23c73a1
$ balena logs 23c73a1 --tail
$ 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`,
options: [
{
signature: 'tail',
description: 'continuously stream output',
boolean: true,
alias: 't',
},
{
signature: 'service',
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',
},
{
signature: 'system',
alias: 'S',
boolean: true,
description:
'Only show system logs. This can be used in combination with --service.',
},
],
primary: true,
async action(params, options) {
normalizeUuidProp(params);
const balena = getBalenaSdk();
const { ExpectedError } = await import('../errors');
const { serviceIdToName } = await import('../utils/cloud');
const { displayDeviceLogs, displayLogObject } = await import(
'../utils/device/logs'
);
const { validateIPAddress } = await import('../utils/validation');
const { checkLoggedIn } = await import('../utils/patterns');
const Logger = await import('../utils/logger');
const logger = Logger.getLogger();
const servicesToDisplay =
options.service != null
? Array.isArray(options.service)
? options.service
: [options.service]
: undefined;
const displayCloudLog = async (line: LogMessage) => {
if (!line.isSystem) {
let serviceName = await serviceIdToName(balena, line.serviceId);
if (serviceName == null) {
serviceName = 'Unknown service';
}
displayLogObject(
{ serviceName, ...line },
logger,
options.system || false,
servicesToDisplay,
);
} else {
displayLogObject(
line,
logger,
options.system || false,
servicesToDisplay,
);
}
};
if (
validateIPAddress(params.uuidOrDevice) ||
validateDotLocalUrl(params.uuidOrDevice)
) {
const { DeviceAPI } = await import('../utils/device/api');
const deviceApi = new DeviceAPI(logger, params.uuidOrDevice);
logger.logDebug('Checking we can access device');
try {
await deviceApi.ping();
} catch (e) {
throw new ExpectedError(
`Cannot access local mode device at address ${params.uuidOrDevice}`,
);
}
const logStream = await deviceApi.getLogStream();
await displayDeviceLogs(
logStream,
logger,
options.system || false,
servicesToDisplay,
);
} else {
await checkLoggedIn();
if (options.tail) {
const logStream = await balena.logs.subscribe(params.uuidOrDevice, {
count: 100,
});
// Never resolve (quit with CTRL-C), but reject on a broken connection
await new Promise((_resolve, reject) => {
logStream.on('line', displayCloudLog);
logStream.on('error', reject);
});
} else {
const logMessages = await balena.logs.history(params.uuidOrDevice);
for (const logMessage of logMessages) {
await displayCloudLog(logMessage);
}
}
}
},
};

View File

@ -59,9 +59,6 @@ capitano.command(actions.config.inject);
capitano.command(actions.config.reconfigure);
capitano.command(actions.config.generate);
// ---------- Logs Module ----------
capitano.command(actions.logs.logs);
// ---------- Preload Module ----------
capitano.command(actions.preload);

View File

@ -175,6 +175,7 @@ export const convertedCommands = [
'leave',
'login',
'logout',
'logs',
'note',
'os:configure',
'scan',

View File

@ -9,7 +9,7 @@ Primary commands:
help [command...] show help
login login to balena
push <applicationOrDevice> Start a remote build on the balena cloud build servers or a local mode device
logs <uuidOrDevice> show device logs
logs <device> show device logs
ssh <applicationordevice> [servicename] SSH into the host or application container of a device
apps list all applications
app <name> display information about a single application