diff --git a/packages/cli-lib/api/functions.js b/packages/cli-lib/api/functions.js index 0752b9b1f..ddd769fd1 100644 --- a/packages/cli-lib/api/functions.js +++ b/packages/cli-lib/api/functions.js @@ -41,7 +41,9 @@ async function getProjectAppFunctionLogs( const { limit = 5 } = query; return http.get(accountId, { - uri: `${FUNCTION_API_PATH}/app-function/logs/project/${projectName}/function/${functionName}`, + uri: `${FUNCTION_API_PATH}/app-function/logs/project/${encodeURIComponent( + projectName + )}/function/${encodeURIComponent(functionName)}`, query: { ...query, limit, appPath }, }); } @@ -53,7 +55,9 @@ async function getLatestProjectAppFunctionLog( appPath ) { return http.get(accountId, { - uri: `${FUNCTION_API_PATH}/app-function/logs/project/${projectName}/function/${functionName}/latest`, + uri: `${FUNCTION_API_PATH}/app-function/logs/project/${encodeURIComponent( + projectName + )}/function/${encodeURIComponent(functionName)}/latest`, query: { appPath }, }); } diff --git a/packages/cli-lib/api/results.js b/packages/cli-lib/api/results.js index 54391a717..e0a2afa04 100644 --- a/packages/cli-lib/api/results.js +++ b/packages/cli-lib/api/results.js @@ -6,14 +6,14 @@ async function getFunctionLogs(accountId, route, query = {}) { const { limit = 5 } = query; return http.get(accountId, { - uri: `${RESULTS_API_PATH}/by-route/${route}`, + uri: `${RESULTS_API_PATH}/by-route/${encodeURIComponent(route)}`, query: { ...query, limit }, }); } async function getLatestFunctionLog(accountId, route) { return http.get(accountId, { - uri: `${RESULTS_API_PATH}/by-route/${route}/latest`, + uri: `${RESULTS_API_PATH}/by-route/${encodeURIComponent(route)}/latest`, }); } diff --git a/packages/cli-lib/lang/en.lyaml b/packages/cli-lib/lang/en.lyaml index 74906a3af..766f3c4f8 100644 --- a/packages/cli-lib/lang/en.lyaml +++ b/packages/cli-lib/lang/en.lyaml @@ -441,9 +441,9 @@ en: logs: describe: "Get logs for a function within a project" errors: - appPathRequired: "You must specify an app path using the --appPath argument." functionNameRequired: "You must pass a function name to retrieve logs for." - logs: "No logs were found for the function name \"{{ functionName }}\" in the app path \"{{ appPath }}\" within the project \"{{ projectName }}\" in account {{ accountId }}." + noAppFunctionLogs: "No logs were found for the function name \"{{ functionName }}\" in the app path \"{{ appPath }}\" within the project \"{{ projectName }}\" in account {{ accountId }}." + noEndpointLogs: "No logs were found for the function name \"{{ functionName }}\" within the project \"{{ projectName }}\" in account {{ accountId }}." projectNameRequired: "You must specify a project name using the --projectName argument." examples: default: "Get 5 most recent logs for function named \"my-function\" within the app named \"app\" within the project named \"my-project\"" diff --git a/packages/cli/commands/project/logs.js b/packages/cli/commands/project/logs.js index 57bfd4272..d77a39efd 100644 --- a/packages/cli/commands/project/logs.js +++ b/packages/cli/commands/project/logs.js @@ -13,6 +13,10 @@ const { getProjectAppFunctionLogs, getLatestProjectAppFunctionLog, } = require('@hubspot/cli-lib/api/functions'); +const { + getFunctionLogs, + getLatestFunctionLog, +} = require('@hubspot/cli-lib/api/results'); const { getProjectConfig } = require('../../lib/projects'); const { loadAndValidateOptions } = require('../../lib/validation'); const { tailLogs } = require('../../lib/serverlessLogs'); @@ -24,17 +28,23 @@ const { EXIT_CODES } = require('../../lib/enums/exitCodes'); const handleLogsError = (e, accountId, projectName, appPath, functionName) => { if (e.statusCode === 404) { logger.error( - i18n(`${i18nKey}.errors.logs`, { - accountId, - appPath, - functionName, - projectName, - }) + appPath + ? i18n(`${i18nKey}.errors.noAppFunctionLogs`, { + accountId, + appPath, + functionName, + projectName, + }) + : i18n(`${i18nKey}.errors.noEndpointLogs`, { + accountId, + functionName, + projectName, + }) ); } }; -const appFunctionLog = async (accountId, options) => { +const functionLog = async (accountId, options) => { const { latest, follow, @@ -46,28 +56,40 @@ const appFunctionLog = async (accountId, options) => { let logsResp; + const tailCall = async after => { + try { + return appPath + ? getProjectAppFunctionLogs( + accountId, + functionName, + projectName, + appPath, + { + after, + } + ) + : getFunctionLogs(accountId, functionName, { after }); + } catch (e) { + handleLogsError(e, accountId, projectName, appPath, functionName); + } + }; + const fetchLatest = async () => { + return appPath + ? getLatestProjectAppFunctionLog( + accountId, + functionName, + projectName, + appPath + ) + : getLatestFunctionLog(accountId, functionName); + }; + if (follow) { const spinnies = new Spinnies(); spinnies.add('tailLogs', { text: i18n(`${i18nKey}.loading`), }); - const tailCall = after => - getProjectAppFunctionLogs(accountId, functionName, projectName, appPath, { - after, - }); - const fetchLatest = () => { - try { - return getLatestProjectAppFunctionLog( - accountId, - functionName, - projectName, - appPath - ); - } catch (e) { - handleLogsError(e, accountId, projectName, appPath, functionName); - } - }; await tailLogs({ accountId, @@ -78,24 +100,13 @@ const appFunctionLog = async (accountId, options) => { }); } else if (latest) { try { - logsResp = await getLatestProjectAppFunctionLog( - accountId, - functionName, - projectName, - appPath - ); + logsResp = await fetchLatest(); } catch (e) { handleLogsError(e, accountId, projectName, appPath, functionName); } } else { try { - logsResp = await getProjectAppFunctionLogs( - accountId, - functionName, - projectName, - appPath, - {} - ); + logsResp = await tailCall(); } catch (e) { handleLogsError(e, accountId, projectName, appPath, functionName); } @@ -106,50 +117,47 @@ const appFunctionLog = async (accountId, options) => { } }; -exports.command = 'logs [functionName]'; +exports.command = 'logs'; exports.describe = i18n(`${i18nKey}.describe`); exports.handler = async options => { await loadAndValidateOptions(options); - const { latest, functionName, appPath } = options; + const { latest, functionName } = options; let projectName = options.projectName; if (!functionName) { logger.error(i18n(`${i18nKey}.errors.functionNameRequired`)); process.exit(EXIT_CODES.ERROR); } else if (!projectName) { - const projectConfig = await getProjectConfig(getCwd()); + const { projectConfig } = await getProjectConfig(getCwd()); if (projectConfig && projectConfig.name) { projectName = projectConfig.name; } else { logger.error(i18n(`${i18nKey}.errors.projectNameRequired`)); process.exit(EXIT_CODES.ERROR); } - } else if (!appPath) { - logger.error(i18n(`${i18nKey}.errors.appPathRequired`)); - process.exit(EXIT_CODES.ERROR); } const accountId = getAccountId(options); trackCommandUsage('project-logs', { latest }, accountId); - appFunctionLog(accountId, { ...options, projectName }); + functionLog(accountId, { ...options, projectName }); }; exports.builder = yargs => { - yargs.positional('functionName', { - describe: i18n(`${i18nKey}.positionals.functionName.describe`), - type: 'string', - demandOption: true, - }); yargs .options({ + functionName: { + alias: 'function', + describe: i18n(`${i18nKey}.positionals.functionName.describe`), + type: 'string', + demandOption: true, + }, appPath: { describe: i18n(`${i18nKey}.options.appPath.describe`), type: 'string', - demandOption: true, }, projectName: { describe: i18n(`${i18nKey}.options.projectName.describe`), @@ -179,7 +187,7 @@ exports.builder = yargs => { yargs.example([ [ - '$0 project logs my-function --appName="app" --projectName="my-project"', + '$0 project logs --function=my-function --appPath="app" --projectName="my-project"', i18n(`${i18nKey}.examples.default`), ], ]);