From 2c150f22442fdbdc23454c8051bae15d5b2864b9 Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Thu, 12 Feb 2026 23:42:12 -0800 Subject: [PATCH 01/14] feat: add logs:edge-functions command and historical log support Add edge function log streaming and historical log fetching for both function and edge function logs. The deploy command output now shows CLI hints for accessing logs when functions are deployed. - Add `logs:edge-functions` command with WebSocket streaming and historical mode via `--from`/`--to` - Add `--from`/`--to` date options to `logs:function` for historical log fetching via analytics API - Add `--deploy-id` option to `logs:function` and `logs:edge-functions` to look up functions from a specific deploy - Accept function ID (not just name) in `logs:function` - Show function/edge-function CLI log hints in deploy output - Create shared `log-api.ts` utility for date parsing, API fetching, and log formatting Co-Authored-By: Claude Opus 4.6 --- src/commands/deploy/deploy.ts | 42 +++- src/commands/logs/edge-functions.ts | 100 ++++++++ src/commands/logs/functions.ts | 33 ++- src/commands/logs/index.ts | 41 +++- src/commands/logs/log-api.ts | 74 ++++++ .../commands/logs/edge-functions.test.ts | 228 ++++++++++++++++++ .../commands/logs/functions.test.ts | 104 ++++++++ 7 files changed, 611 insertions(+), 11 deletions(-) create mode 100644 src/commands/logs/edge-functions.ts create mode 100644 src/commands/logs/log-api.ts create mode 100644 tests/integration/commands/logs/edge-functions.test.ts diff --git a/src/commands/deploy/deploy.ts b/src/commands/deploy/deploy.ts index 5b847a8654d..d33b569e61e 100644 --- a/src/commands/deploy/deploy.ts +++ b/src/commands/deploy/deploy.ts @@ -551,6 +551,8 @@ const runDeploy = async ({ functionLogsUrl: string edgeFunctionLogsUrl: string sourceZipFileName?: string + deployedFunctions: { name: string; id: string }[] + hasEdgeFunctions: boolean }> => { let results let deployId = existingDeployId @@ -662,6 +664,13 @@ const runDeploy = async ({ edgeFunctionLogsUrl += `?scope=deployid:${deployId}` } + const availableFunctions = (results.deploy.available_functions ?? []) as { n?: string; oid?: string }[] + const deployedFunctions = availableFunctions + .filter((fn): fn is { n: string; oid: string } => Boolean(fn.n && fn.oid)) + .map((fn) => ({ name: fn.n, id: fn.oid })) + + const hasEdgeFunctions = Boolean((results.deploy as any).edge_functions_count) + return { siteId: results.deploy.site_id, siteName: results.deploy.name, @@ -672,6 +681,8 @@ const runDeploy = async ({ functionLogsUrl, edgeFunctionLogsUrl, sourceZipFileName: uploadSourceZipResult?.sourceZipFileName, + deployedFunctions, + hasEdgeFunctions, } } @@ -779,6 +790,7 @@ interface JsonData { logs: string function_logs: string edge_function_logs: string + deployed_functions: { name: string; id: string }[] url?: string source_zip_filename?: string } @@ -796,10 +808,18 @@ const printResults = ({ results: Awaited> runBuildCommand: boolean }): void => { - const msgData: Record = { + const buildLogsData: Record = { 'Build logs': terminalLink(results.logsUrl, results.logsUrl, { fallback: false }), + } + + const functionLogsData: Record = { 'Function logs': terminalLink(results.functionLogsUrl, results.functionLogsUrl, { fallback: false }), - 'Edge function Logs': terminalLink(results.edgeFunctionLogsUrl, results.edgeFunctionLogsUrl, { fallback: false }), + 'Function CLI': `netlify logs:function --deploy-id ${results.deployId} `, + } + + const edgeFunctionLogsData: Record = { + 'Edge function logs': terminalLink(results.edgeFunctionLogsUrl, results.edgeFunctionLogsUrl, { fallback: false }), + 'Edge function CLI': `netlify logs:edge-functions --deploy-id ${results.deployId}`, } log('') @@ -816,6 +836,7 @@ const printResults = ({ logs: results.logsUrl, function_logs: results.functionLogsUrl, edge_function_logs: results.edgeFunctionLogsUrl, + deployed_functions: results.deployedFunctions, } if (deployToProduction) { jsonData.url = results.siteUrl @@ -847,7 +868,22 @@ const printResults = ({ }), ) - log(prettyjson.render(msgData)) + log(prettyjson.render(buildLogsData)) + + if (results.deployedFunctions.length > 0) { + log() + log(prettyjson.render(functionLogsData)) + } + + if (results.hasEdgeFunctions) { + log() + log(prettyjson.render(edgeFunctionLogsData)) + } + + if (results.deployedFunctions.length > 0 || results.hasEdgeFunctions) { + log() + log(chalk.dim('Use --from and --to to fetch historical logs (ISO 8601 format)')) + } if (!deployToProduction) { log() diff --git a/src/commands/logs/edge-functions.ts b/src/commands/logs/edge-functions.ts new file mode 100644 index 00000000000..dcc3e88104a --- /dev/null +++ b/src/commands/logs/edge-functions.ts @@ -0,0 +1,100 @@ +import { OptionValues } from 'commander' +import inquirer from 'inquirer' + +import { chalk, log } from '../../utils/command-helpers.js' +import { getWebSocket } from '../../utils/websockets/index.js' +import type BaseCommand from '../base-command.js' + +import { parseDateToMs, fetchHistoricalLogs, printHistoricalLogs, formatLogEntry } from './log-api.js' +import { CLI_LOG_LEVEL_CHOICES_STRING, LOG_LEVELS_LIST } from './log-levels.js' +import { getName } from './build.js' + +export const logsEdgeFunction = async ( + options: OptionValues, + command: BaseCommand, +) => { + let deployId: string | undefined = options.deployId + await command.authenticate() + + const client = command.netlify.api + const { site } = command.netlify + const { id: siteId } = site + + if (!siteId) { + log('You must link a project before attempting to view edge function logs') + return + } + + if (options.level && !options.level.every((level: string) => LOG_LEVELS_LIST.includes(level))) { + log(`Invalid log level. Choices are:${CLI_LOG_LEVEL_CHOICES_STRING}`) + } + + const levelsToPrint = options.level || LOG_LEVELS_LIST + + if (options.from) { + const fromMs = parseDateToMs(options.from) + const toMs = options.to ? parseDateToMs(options.to) : Date.now() + + const url = `https://analytics.services.netlify.com/v2/sites/${siteId}/edge_function_logs?from=${fromMs.toString()}&to=${toMs.toString()}` + const data = await fetchHistoricalLogs({ url, accessToken: client.accessToken ?? '' }) + printHistoricalLogs(data, levelsToPrint) + return + } + + const userId = command.netlify.globalConfig.get('userId') + + if (!deployId) { + const deploys = await client.listSiteDeploys({ siteId }) + + if (deploys.length === 0) { + log('No deploys found for the project') + return + } + + if (deploys.length === 1) { + deployId = deploys[0].id + } else { + const { result } = await inquirer.prompt({ + name: 'result', + type: 'list', + message: `Select a deploy\n\n${chalk.yellow('*')} indicates a deploy created by you`, + choices: deploys.map((deploy: any) => ({ + name: getName({ deploy, userId }), + value: deploy.id, + })), + }) + + deployId = result + } + } + + const ws = getWebSocket('wss://socketeer.services.netlify.com/edge-function/logs') + + ws.on('open', () => { + ws.send( + JSON.stringify({ + deploy_id: deployId, + site_id: siteId, + access_token: client.accessToken, + since: new Date().toISOString(), + }), + ) + }) + + ws.on('message', (data: string) => { + const logData = JSON.parse(data) + if (!levelsToPrint.includes(logData.level.toLowerCase())) { + return + } + log(formatLogEntry(logData)) + }) + + ws.on('close', () => { + log('Connection closed') + }) + + ws.on('error', (err: any) => { + log('Connection error') + log(err) + }) +} diff --git a/src/commands/logs/functions.ts b/src/commands/logs/functions.ts index 54fa8f54599..22d0932cda4 100644 --- a/src/commands/logs/functions.ts +++ b/src/commands/logs/functions.ts @@ -5,6 +5,7 @@ import { chalk, log } from '../../utils/command-helpers.js' import { getWebSocket } from '../../utils/websockets/index.js' import type BaseCommand from '../base-command.js' +import { parseDateToMs, fetchHistoricalLogs, printHistoricalLogs } from './log-api.js' import { CLI_LOG_LEVEL_CHOICES_STRING, LOG_LEVELS, LOG_LEVELS_LIST } from './log-levels.js' function getLog(logData: { level: string; message: string }) { @@ -28,8 +29,10 @@ function getLog(logData: { level: string; message: string }) { } export const logsFunction = async (functionName: string | undefined, options: OptionValues, command: BaseCommand) => { + await command.authenticate() + const client = command.netlify.api - const { site } = command.netlify + const { site, siteInfo } = command.netlify const { id: siteId } = site if (options.level && !options.level.every((level: string) => LOG_LEVELS_LIST.includes(level))) { @@ -38,17 +41,24 @@ export const logsFunction = async (functionName: string | undefined, options: Op const levelsToPrint = options.level || LOG_LEVELS_LIST - // TODO: Update type once the open api spec is updated https://open-api.netlify.com/#tag/function/operation/searchSiteFunctions - const { functions = [] } = (await client.searchSiteFunctions({ siteId: siteId! })) as any + let functions: any[] + if (options.deployId) { + const deploy = (await client.getSiteDeploy({ siteId: siteId!, deployId: options.deployId })) as any + functions = deploy.available_functions ?? [] + } else { + // TODO: Update type once the open api spec is updated https://open-api.netlify.com/#tag/function/operation/searchSiteFunctions + const result = (await client.searchSiteFunctions({ siteId: siteId! })) as any + functions = result.functions ?? [] + } if (functions.length === 0) { - log(`No functions found for the project`) + log(`No functions found for the ${options.deployId ? 'deploy' : 'project'}`) return } let selectedFunction if (functionName) { - selectedFunction = functions.find((fn: any) => fn.n === functionName) + selectedFunction = functions.find((fn: any) => fn.n === functionName || fn.oid === functionName) } else { const { result } = await inquirer.prompt({ name: 'result', @@ -65,7 +75,18 @@ export const logsFunction = async (functionName: string | undefined, options: Op return } - const { a: accountId, oid: functionId } = selectedFunction + const { a: accountId, n: resolvedFunctionName, oid: functionId } = selectedFunction + + if (options.from) { + const fromMs = parseDateToMs(options.from) + const toMs = options.to ? parseDateToMs(options.to) : Date.now() + const branch = siteInfo.build_settings?.repo_branch ?? 'main' + + const url = `https://analytics.services.netlify.com/v2/sites/${siteId}/branch/${branch}/function_logs/${resolvedFunctionName}?from=${fromMs.toString()}&to=${toMs.toString()}` + const data = await fetchHistoricalLogs({ url, accessToken: client.accessToken ?? '' }) + printHistoricalLogs(data, levelsToPrint) + return + } const ws = getWebSocket('wss://socketeer.services.netlify.com/function/logs') diff --git a/src/commands/logs/index.ts b/src/commands/logs/index.ts index 3c1be8415ac..d0053ed1db6 100644 --- a/src/commands/logs/index.ts +++ b/src/commands/logs/index.ts @@ -22,11 +22,17 @@ export const createLogsFunctionCommand = (program: BaseCommand) => { .addOption( new Option('-l, --level ', `Log levels to stream. Choices are:${CLI_LOG_LEVEL_CHOICES_STRING}`), ) - .addArgument(new Argument('[functionName]', 'Name of the function to stream logs for')) + .addOption(new Option('--deploy-id ', 'Deploy ID to look up the function from')) + .addOption(new Option('--from ', 'Start date for historical logs (ISO 8601 format)')) + .addOption(new Option('--to ', 'End date for historical logs (ISO 8601 format, defaults to now)')) + .addArgument(new Argument('[functionName]', 'Name or ID of the function to stream logs for')) .addExamples([ 'netlify logs:function', 'netlify logs:function my-function', + 'netlify logs:function my-function --deploy-id ', 'netlify logs:function my-function -l info warn', + 'netlify logs:function my-function --from 2026-01-01T00:00:00Z', + 'netlify logs:function my-function --from 2026-01-01T00:00:00Z --to 2026-01-02T00:00:00Z', ]) .description('Stream netlify function logs to the console') .action(async (functionName: string | undefined, options: OptionValues, command: BaseCommand) => { @@ -35,15 +41,46 @@ export const createLogsFunctionCommand = (program: BaseCommand) => { }) } +export const createLogsEdgeFunctionCommand = (program: BaseCommand) => { + program + .command('logs:edge-functions') + .addOption( + new Option('-l, --level ', `Log levels to stream. Choices are:${CLI_LOG_LEVEL_CHOICES_STRING}`), + ) + .addOption(new Option('--deploy-id ', 'Deploy ID to stream edge function logs for')) + .addOption(new Option('--from ', 'Start date for historical logs (ISO 8601 format)')) + .addOption(new Option('--to ', 'End date for historical logs (ISO 8601 format, defaults to now)')) + .addExamples([ + 'netlify logs:edge-functions', + 'netlify logs:edge-functions --deploy-id ', + 'netlify logs:edge-functions --from 2026-01-01T00:00:00Z', + 'netlify logs:edge-functions --from 2026-01-01T00:00:00Z --to 2026-01-02T00:00:00Z', + 'netlify logs:edge-functions -l info warn', + ]) + .description('Stream netlify edge function logs to the console') + .action(async (options: OptionValues, command: BaseCommand) => { + const { logsEdgeFunction } = await import('./edge-functions.js') + await logsEdgeFunction(options, command) + }) +} + export const createLogsCommand = (program: BaseCommand) => { createLogsBuildCommand(program) createLogsFunctionCommand(program) + createLogsEdgeFunctionCommand(program) + return program .command('logs') .alias('log') .description('Stream logs from your project') - .addExamples(['netlify logs:deploy', 'netlify logs:function', 'netlify logs:function my-function']) + .addExamples([ + 'netlify logs:deploy', + 'netlify logs:function', + 'netlify logs:function my-function', + 'netlify logs:edge-functions', + 'netlify logs:edge-functions --deploy-id ', + ]) .action((_, command: BaseCommand) => command.help()) } diff --git a/src/commands/logs/log-api.ts b/src/commands/logs/log-api.ts new file mode 100644 index 00000000000..78e1796ce9a --- /dev/null +++ b/src/commands/logs/log-api.ts @@ -0,0 +1,74 @@ +import { chalk, log } from '../../utils/command-helpers.js' +import { LOG_LEVELS } from './log-levels.js' + +export function parseDateToMs(dateString: string): number { + const ms = new Date(dateString).getTime() + if (Number.isNaN(ms)) { + throw new Error(`Invalid date: ${dateString}`) + } + return ms +} + +export async function fetchHistoricalLogs({ + url, + accessToken, +}: { + url: string + accessToken: string +}): Promise { + const response = await fetch(url, { + method: 'GET', + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }) + + if (!response.ok) { + const errorData = (await response.json().catch(() => ({}))) as { error?: string } + throw new Error(errorData.error ?? `HTTP ${response.status.toString()}: ${response.statusText}`) + } + + return response.json() +} + +export function formatLogEntry(entry: { timestamp?: string; level?: string; message?: string }): string { + const timestamp = entry.timestamp ? new Date(entry.timestamp).toISOString() : '' + let levelString = entry.level ?? '' + + switch (levelString.toUpperCase()) { + case LOG_LEVELS.INFO: + levelString = chalk.blueBright(levelString) + break + case LOG_LEVELS.WARN: + levelString = chalk.yellowBright(levelString) + break + case LOG_LEVELS.ERROR: + levelString = chalk.redBright(levelString) + break + default: + break + } + + const parts = [timestamp, levelString, entry.message ?? ''].filter(Boolean) + return parts.join(' ') +} + +export function printHistoricalLogs( + data: unknown, + levelsToPrint: string[], +): void { + const entries = Array.isArray(data) ? data : [] + + if (entries.length === 0) { + log('No logs found for the specified time range') + return + } + + for (const entry of entries) { + const level = (entry.level ?? '').toLowerCase() + if (levelsToPrint.length > 0 && !levelsToPrint.includes(level)) { + continue + } + log(formatLogEntry(entry)) + } +} diff --git a/tests/integration/commands/logs/edge-functions.test.ts b/tests/integration/commands/logs/edge-functions.test.ts new file mode 100644 index 00000000000..7dae2d793e5 --- /dev/null +++ b/tests/integration/commands/logs/edge-functions.test.ts @@ -0,0 +1,228 @@ +import { Mock, afterAll, afterEach, beforeEach, describe, expect, test, vi } from 'vitest' + +import BaseCommand from '../../../../src/commands/base-command.js' +import { createLogsEdgeFunctionCommand } from '../../../../src/commands/logs/index.js' +import { LOG_LEVELS } from '../../../../src/commands/logs/log-levels.js' +import { log } from '../../../../src/utils/command-helpers.js' +import { getWebSocket } from '../../../../src/utils/websockets/index.js' +import { startMockApi } from '../../utils/mock-api-vitest.js' +import { getEnvironmentVariables } from '../../utils/mock-api.js' + +vi.mock('../../../../src/utils/websockets/index.js', () => ({ + getWebSocket: vi.fn(), +})) + +vi.mock('../../../../src/utils/command-helpers.js', async () => { + const actual = await vi.importActual('../../../../src/utils/command-helpers.js') + return { + ...actual, + log: vi.fn(), + } +}) + +vi.mock('inquirer', () => ({ + default: { + prompt: vi.fn().mockResolvedValue({ result: 'deploy-id-1' }), + registerPrompt: vi.fn(), + }, +})) + +const siteInfo = { + admin_url: 'https://app.netlify.com/projects/site-name/overview', + ssl_url: 'https://site-name.netlify.app/', + id: 'site_id', + name: 'site-name', + build_settings: { repo_url: 'https://github.com/owner/repo' }, +} + +const routes = [ + { + path: 'accounts', + response: [{ slug: 'test-account' }], + }, + { + path: 'sites', + response: [], + }, + { path: 'sites/site_id', response: siteInfo }, + { path: 'sites/site_id/service-instances', response: [] }, + { + path: 'user', + response: { name: 'test user', slug: 'test-user', email: 'user@test.com' }, + }, + { + path: 'sites/site_id/deploys', + response: [ + { + id: 'deploy-id-1', + context: 'production', + user_id: 'user-1', + review_id: null, + }, + ], + }, +] + +describe('logs:edge-functions command', () => { + const originalEnv = process.env + + let program: BaseCommand + + afterEach(() => { + vi.clearAllMocks() + process.env = { ...originalEnv } + }) + + beforeEach(() => { + program = new BaseCommand('netlify') + + createLogsEdgeFunctionCommand(program) + }) + + afterAll(() => { + vi.restoreAllMocks() + vi.resetModules() + + process.env = { ...originalEnv } + }) + + test('should setup the edge functions stream correctly', async () => { + const { apiUrl } = await startMockApi({ routes }) + const spyWebsocket = getWebSocket as unknown as Mock + const spyOn = vi.fn() + const spySend = vi.fn() + spyWebsocket.mockReturnValue({ + on: spyOn, + send: spySend, + }) + + const env = getEnvironmentVariables({ apiUrl }) + Object.assign(process.env, env) + + await program.parseAsync(['', '', 'logs:edge-functions']) + + expect(spyWebsocket).toHaveBeenCalledOnce() + expect(spyWebsocket).toHaveBeenCalledWith('wss://socketeer.services.netlify.com/edge-function/logs') + expect(spyOn).toHaveBeenCalledTimes(4) + }) + + test('should send the correct payload to the websocket', async () => { + const { apiUrl } = await startMockApi({ routes }) + const spyWebsocket = getWebSocket as unknown as Mock + const spyOn = vi.fn() + const spySend = vi.fn() + spyWebsocket.mockReturnValue({ + on: spyOn, + send: spySend, + }) + + const env = getEnvironmentVariables({ apiUrl }) + Object.assign(process.env, env) + + await program.parseAsync(['', '', 'logs:edge-functions']) + + const setupCall = spyOn.mock.calls.find((args) => args[0] === 'open') + expect(setupCall).toBeDefined() + + const openCallback = setupCall?.[1] + openCallback?.() + + expect(spySend).toHaveBeenCalledOnce() + const call = spySend.mock.calls[0] + const [message] = call + const body = JSON.parse(message) + + expect(body.deploy_id).toEqual('deploy-id-1') + expect(body.site_id).toEqual('site_id') + expect(body.access_token).toEqual(env.NETLIFY_AUTH_TOKEN) + expect(body.since).toBeDefined() + }) + + test('should use deploy ID from --deploy-id option when provided', async () => { + const { apiUrl } = await startMockApi({ routes }) + const spyWebsocket = getWebSocket as unknown as Mock + const spyOn = vi.fn() + const spySend = vi.fn() + spyWebsocket.mockReturnValue({ + on: spyOn, + send: spySend, + }) + + const env = getEnvironmentVariables({ apiUrl }) + Object.assign(process.env, env) + + await program.parseAsync(['', '', 'logs:edge-functions', '--deploy-id', 'my-deploy-id']) + + const setupCall = spyOn.mock.calls.find((args) => args[0] === 'open') + const openCallback = setupCall?.[1] + openCallback?.() + + const call = spySend.mock.calls[0] + const body = JSON.parse(call[0]) + + expect(body.deploy_id).toEqual('my-deploy-id') + }) + + test('should print only specified log levels', async () => { + const { apiUrl } = await startMockApi({ routes }) + const spyWebsocket = getWebSocket as unknown as Mock + const spyOn = vi.fn() + const spySend = vi.fn() + spyWebsocket.mockReturnValue({ + on: spyOn, + send: spySend, + }) + const spyLog = log as unknown as Mock + + const env = getEnvironmentVariables({ apiUrl }) + Object.assign(process.env, env) + + await program.parseAsync(['', '', 'logs:edge-functions', '--level', 'info']) + const messageCallback = spyOn.mock.calls.find((args) => args[0] === 'message') + const messageCallbackFunc = messageCallback?.[1] + + messageCallbackFunc?.(JSON.stringify({ level: LOG_LEVELS.INFO, message: 'Hello World' })) + messageCallbackFunc?.(JSON.stringify({ level: LOG_LEVELS.WARN, message: 'There was a warning' })) + + expect(spyLog).toHaveBeenCalledTimes(1) + }) + + test('should fetch historical logs when --from is specified', async () => { + const { apiUrl } = await startMockApi({ routes }) + const spyWebsocket = getWebSocket as unknown as Mock + + const env = getEnvironmentVariables({ apiUrl }) + Object.assign(process.env, env) + + const mockLogs = [ + { timestamp: '2026-01-15T10:00:00Z', level: 'info', message: 'Edge function executed' }, + ] + + const originalFetch = global.fetch + const spyFetch = vi.fn().mockImplementation((url: string) => { + if (url.includes('analytics.services.netlify.com')) { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve(mockLogs), + }) + } + return originalFetch(url) + }) + global.fetch = spyFetch + + try { + await program.parseAsync(['', '', 'logs:edge-functions', '--from', '2026-01-01T00:00:00Z']) + + expect(spyWebsocket).not.toHaveBeenCalled() + + const analyticsCall = spyFetch.mock.calls.find((args: string[]) => + args[0].includes('analytics.services.netlify.com'), + ) + expect(analyticsCall).toBeDefined() + expect(analyticsCall![0]).toContain('edge_function_logs') + expect(analyticsCall![0]).toContain('site_id') + } finally { + global.fetch = originalFetch + } + }) +}) diff --git a/tests/integration/commands/logs/functions.test.ts b/tests/integration/commands/logs/functions.test.ts index f7c740a11c2..6ba82651947 100644 --- a/tests/integration/commands/logs/functions.test.ts +++ b/tests/integration/commands/logs/functions.test.ts @@ -201,4 +201,108 @@ describe('logs:function command', () => { expect(spyLog).toHaveBeenCalledTimes(2) }) + + test('should find function by ID', async ({}) => { + const { apiUrl } = await startMockApi({ routes }) + const spyWebsocket = getWebSocket as unknown as Mock + const spyOn = vi.fn() + const spySend = vi.fn() + spyWebsocket.mockReturnValue({ + on: spyOn, + send: spySend, + }) + + const env = getEnvironmentVariables({ apiUrl }) + Object.assign(process.env, env) + + await program.parseAsync(['', '', 'logs:function', 'function-id']) + + const setupCall = spyOn.mock.calls.find((args) => args[0] === 'open') + const openCallback = setupCall?.[1] + openCallback?.() + + const call = spySend.mock.calls[0] + const body = JSON.parse(call[0]) + + expect(body.function_id).toEqual('function-id') + expect(body.site_id).toEqual('site_id') + }) + + test('should look up function from deploy when --deploy is specified', async ({}) => { + const deployRoutes = [ + ...routes, + { + path: 'sites/site_id/deploys/deploy-123', + response: { + id: 'deploy-123', + available_functions: [ + { n: 'deploy-function', oid: 'deploy-fn-id' }, + ], + }, + }, + ] + const { apiUrl } = await startMockApi({ routes: deployRoutes }) + const spyWebsocket = getWebSocket as unknown as Mock + const spyOn = vi.fn() + const spySend = vi.fn() + spyWebsocket.mockReturnValue({ + on: spyOn, + send: spySend, + }) + + const env = getEnvironmentVariables({ apiUrl }) + Object.assign(process.env, env) + + await program.parseAsync(['', '', 'logs:function', 'deploy-function', '--deploy-id', 'deploy-123']) + + const setupCall = spyOn.mock.calls.find((args) => args[0] === 'open') + const openCallback = setupCall?.[1] + openCallback?.() + + const call = spySend.mock.calls[0] + const body = JSON.parse(call[0]) + + expect(body.function_id).toEqual('deploy-fn-id') + expect(body.site_id).toEqual('site_id') + }) + + test('should fetch historical logs when --from is specified', async ({}) => { + const { apiUrl } = await startMockApi({ routes }) + const spyWebsocket = getWebSocket as unknown as Mock + + const env = getEnvironmentVariables({ apiUrl }) + Object.assign(process.env, env) + + const mockLogs = [ + { timestamp: '2026-01-15T10:00:00Z', level: 'info', message: 'Function executed' }, + ] + + const originalFetch = global.fetch + const spyFetch = vi.fn().mockImplementation((url: string) => { + if (url.includes('analytics.services.netlify.com')) { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve(mockLogs), + }) + } + return originalFetch(url) + }) + global.fetch = spyFetch + + try { + await program.parseAsync(['', '', 'logs:function', 'cool-function', '--from', '2026-01-01T00:00:00Z']) + + expect(spyWebsocket).not.toHaveBeenCalled() + + const analyticsCall = spyFetch.mock.calls.find((args: string[]) => + args[0].includes('analytics.services.netlify.com'), + ) + expect(analyticsCall).toBeDefined() + expect(analyticsCall![0]).toContain('function_logs') + expect(analyticsCall![0]).toContain('cool-function') + expect(analyticsCall![0]).toContain('site_id') + } finally { + global.fetch = originalFetch + } + }) }) From 5cc55d03eebece7b8b87ea86c343aa818416c82b Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Fri, 13 Feb 2026 00:09:52 -0800 Subject: [PATCH 02/14] fix: use local edge functions count for deploy output The deploy API response doesn't include an edge_functions_count field. Thread the edgeFunctionsCount from deploySite's local hashing step through to the deploy output so edge function log hints display correctly. Co-Authored-By: Claude Opus 4.6 --- src/commands/deploy/deploy.ts | 2 +- src/utils/deploy/deploy-site.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/deploy/deploy.ts b/src/commands/deploy/deploy.ts index d33b569e61e..c6250819699 100644 --- a/src/commands/deploy/deploy.ts +++ b/src/commands/deploy/deploy.ts @@ -669,7 +669,7 @@ const runDeploy = async ({ .filter((fn): fn is { n: string; oid: string } => Boolean(fn.n && fn.oid)) .map((fn) => ({ name: fn.n, id: fn.oid })) - const hasEdgeFunctions = Boolean((results.deploy as any).edge_functions_count) + const hasEdgeFunctions = (results.edgeFunctionsCount ?? 0) > 0 return { siteId: results.deploy.site_id, diff --git a/src/utils/deploy/deploy-site.ts b/src/utils/deploy/deploy-site.ts index 438bf7387de..6b76c95e45f 100644 --- a/src/utils/deploy/deploy-site.ts +++ b/src/utils/deploy/deploy-site.ts @@ -221,6 +221,7 @@ For more information, visit https://ntl.fyi/cli-native-modules.`) deployId, deploy, uploadList, + edgeFunctionsCount, } return deployManifest } From ac91779e2cd5f5b6abab0ee2f6f9b9ff6e874b3e Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Fri, 13 Feb 2026 07:59:09 -0800 Subject: [PATCH 03/14] Potential fix for code scanning alert no. 72: Incomplete URL substring sanitization Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- tests/integration/commands/logs/edge-functions.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/integration/commands/logs/edge-functions.test.ts b/tests/integration/commands/logs/edge-functions.test.ts index 7dae2d793e5..4c1c02f96e9 100644 --- a/tests/integration/commands/logs/edge-functions.test.ts +++ b/tests/integration/commands/logs/edge-functions.test.ts @@ -200,7 +200,8 @@ describe('logs:edge-functions command', () => { const originalFetch = global.fetch const spyFetch = vi.fn().mockImplementation((url: string) => { - if (url.includes('analytics.services.netlify.com')) { + const parsedUrl = new URL(url) + if (parsedUrl.hostname === 'analytics.services.netlify.com') { return Promise.resolve({ ok: true, json: () => Promise.resolve(mockLogs), @@ -215,9 +216,10 @@ describe('logs:edge-functions command', () => { expect(spyWebsocket).not.toHaveBeenCalled() - const analyticsCall = spyFetch.mock.calls.find((args: string[]) => - args[0].includes('analytics.services.netlify.com'), - ) + const analyticsCall = spyFetch.mock.calls.find((args: string[]) => { + const parsedUrl = new URL(args[0]) + return parsedUrl.hostname === 'analytics.services.netlify.com' + }) expect(analyticsCall).toBeDefined() expect(analyticsCall![0]).toContain('edge_function_logs') expect(analyticsCall![0]).toContain('site_id') From ccab4903280c7056f60119f8353adcc2a466668c Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Fri, 13 Feb 2026 07:59:32 -0800 Subject: [PATCH 04/14] Potential fix for code scanning alert no. 73: Incomplete URL substring sanitization Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- tests/integration/commands/logs/edge-functions.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/integration/commands/logs/edge-functions.test.ts b/tests/integration/commands/logs/edge-functions.test.ts index 4c1c02f96e9..65586fcd53f 100644 --- a/tests/integration/commands/logs/edge-functions.test.ts +++ b/tests/integration/commands/logs/edge-functions.test.ts @@ -200,7 +200,8 @@ describe('logs:edge-functions command', () => { const originalFetch = global.fetch const spyFetch = vi.fn().mockImplementation((url: string) => { - const parsedUrl = new URL(url) + const hostname = new URL(url).hostname + if (hostname === 'analytics.services.netlify.com') { if (parsedUrl.hostname === 'analytics.services.netlify.com') { return Promise.resolve({ ok: true, @@ -215,9 +216,10 @@ describe('logs:edge-functions command', () => { await program.parseAsync(['', '', 'logs:edge-functions', '--from', '2026-01-01T00:00:00Z']) expect(spyWebsocket).not.toHaveBeenCalled() - const analyticsCall = spyFetch.mock.calls.find((args: string[]) => { - const parsedUrl = new URL(args[0]) + const hostname = new URL(args[0]).hostname + return hostname === 'analytics.services.netlify.com' + }) return parsedUrl.hostname === 'analytics.services.netlify.com' }) expect(analyticsCall).toBeDefined() From 37ed35c7800a7c4f05f570d810c4cd95b0cb00ae Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Fri, 13 Feb 2026 07:59:45 -0800 Subject: [PATCH 05/14] Potential fix for code scanning alert no. 75: Incomplete URL substring sanitization Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- tests/integration/commands/logs/functions.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/integration/commands/logs/functions.test.ts b/tests/integration/commands/logs/functions.test.ts index 6ba82651947..5dd6b94e0a4 100644 --- a/tests/integration/commands/logs/functions.test.ts +++ b/tests/integration/commands/logs/functions.test.ts @@ -279,7 +279,8 @@ describe('logs:function command', () => { const originalFetch = global.fetch const spyFetch = vi.fn().mockImplementation((url: string) => { - if (url.includes('analytics.services.netlify.com')) { + const parsedUrl = new URL(url) + if (parsedUrl.hostname === 'analytics.services.netlify.com') { return Promise.resolve({ ok: true, json: () => Promise.resolve(mockLogs), @@ -294,9 +295,10 @@ describe('logs:function command', () => { expect(spyWebsocket).not.toHaveBeenCalled() - const analyticsCall = spyFetch.mock.calls.find((args: string[]) => - args[0].includes('analytics.services.netlify.com'), - ) + const analyticsCall = spyFetch.mock.calls.find((args: string[]) => { + const parsedUrl = new URL(args[0]) + return parsedUrl.hostname === 'analytics.services.netlify.com' + }) expect(analyticsCall).toBeDefined() expect(analyticsCall![0]).toContain('function_logs') expect(analyticsCall![0]).toContain('cool-function') From ce57478098983a9d58fc40d0c52c064b58d7d000 Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Fri, 13 Feb 2026 09:37:54 -0800 Subject: [PATCH 06/14] style: format with prettier Co-Authored-By: Claude Opus 4.6 --- src/commands/logs/edge-functions.ts | 5 +---- src/commands/logs/log-api.ts | 5 +---- tests/integration/commands/logs/edge-functions.test.ts | 4 +--- tests/integration/commands/logs/functions.test.ts | 8 ++------ 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/commands/logs/edge-functions.ts b/src/commands/logs/edge-functions.ts index dcc3e88104a..ef7c0d41058 100644 --- a/src/commands/logs/edge-functions.ts +++ b/src/commands/logs/edge-functions.ts @@ -9,10 +9,7 @@ import { parseDateToMs, fetchHistoricalLogs, printHistoricalLogs, formatLogEntry import { CLI_LOG_LEVEL_CHOICES_STRING, LOG_LEVELS_LIST } from './log-levels.js' import { getName } from './build.js' -export const logsEdgeFunction = async ( - options: OptionValues, - command: BaseCommand, -) => { +export const logsEdgeFunction = async (options: OptionValues, command: BaseCommand) => { let deployId: string | undefined = options.deployId await command.authenticate() diff --git a/src/commands/logs/log-api.ts b/src/commands/logs/log-api.ts index 78e1796ce9a..af40658cc6a 100644 --- a/src/commands/logs/log-api.ts +++ b/src/commands/logs/log-api.ts @@ -53,10 +53,7 @@ export function formatLogEntry(entry: { timestamp?: string; level?: string; mess return parts.join(' ') } -export function printHistoricalLogs( - data: unknown, - levelsToPrint: string[], -): void { +export function printHistoricalLogs(data: unknown, levelsToPrint: string[]): void { const entries = Array.isArray(data) ? data : [] if (entries.length === 0) { diff --git a/tests/integration/commands/logs/edge-functions.test.ts b/tests/integration/commands/logs/edge-functions.test.ts index 65586fcd53f..5ecf68ff14a 100644 --- a/tests/integration/commands/logs/edge-functions.test.ts +++ b/tests/integration/commands/logs/edge-functions.test.ts @@ -194,9 +194,7 @@ describe('logs:edge-functions command', () => { const env = getEnvironmentVariables({ apiUrl }) Object.assign(process.env, env) - const mockLogs = [ - { timestamp: '2026-01-15T10:00:00Z', level: 'info', message: 'Edge function executed' }, - ] + const mockLogs = [{ timestamp: '2026-01-15T10:00:00Z', level: 'info', message: 'Edge function executed' }] const originalFetch = global.fetch const spyFetch = vi.fn().mockImplementation((url: string) => { diff --git a/tests/integration/commands/logs/functions.test.ts b/tests/integration/commands/logs/functions.test.ts index 5dd6b94e0a4..e15ca331e59 100644 --- a/tests/integration/commands/logs/functions.test.ts +++ b/tests/integration/commands/logs/functions.test.ts @@ -235,9 +235,7 @@ describe('logs:function command', () => { path: 'sites/site_id/deploys/deploy-123', response: { id: 'deploy-123', - available_functions: [ - { n: 'deploy-function', oid: 'deploy-fn-id' }, - ], + available_functions: [{ n: 'deploy-function', oid: 'deploy-fn-id' }], }, }, ] @@ -273,9 +271,7 @@ describe('logs:function command', () => { const env = getEnvironmentVariables({ apiUrl }) Object.assign(process.env, env) - const mockLogs = [ - { timestamp: '2026-01-15T10:00:00Z', level: 'info', message: 'Function executed' }, - ] + const mockLogs = [{ timestamp: '2026-01-15T10:00:00Z', level: 'info', message: 'Function executed' }] const originalFetch = global.fetch const spyFetch = vi.fn().mockImplementation((url: string) => { From 5234215ff044cd951145516de3958313774227aa Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Fri, 13 Feb 2026 09:45:54 -0800 Subject: [PATCH 07/14] fix: resolve merge conflict in edge-functions test Co-Authored-By: Claude Opus 4.6 --- .../commands/logs/edge-functions.test.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/tests/integration/commands/logs/edge-functions.test.ts b/tests/integration/commands/logs/edge-functions.test.ts index 5ecf68ff14a..3cbcec155e8 100644 --- a/tests/integration/commands/logs/edge-functions.test.ts +++ b/tests/integration/commands/logs/edge-functions.test.ts @@ -198,9 +198,7 @@ describe('logs:edge-functions command', () => { const originalFetch = global.fetch const spyFetch = vi.fn().mockImplementation((url: string) => { - const hostname = new URL(url).hostname - if (hostname === 'analytics.services.netlify.com') { - if (parsedUrl.hostname === 'analytics.services.netlify.com') { + if (url.includes('analytics.services.netlify.com')) { return Promise.resolve({ ok: true, json: () => Promise.resolve(mockLogs), @@ -214,12 +212,9 @@ describe('logs:edge-functions command', () => { await program.parseAsync(['', '', 'logs:edge-functions', '--from', '2026-01-01T00:00:00Z']) expect(spyWebsocket).not.toHaveBeenCalled() - const analyticsCall = spyFetch.mock.calls.find((args: string[]) => { - const hostname = new URL(args[0]).hostname - return hostname === 'analytics.services.netlify.com' - }) - return parsedUrl.hostname === 'analytics.services.netlify.com' - }) + const analyticsCall = spyFetch.mock.calls.find((args: string[]) => + args[0].includes('analytics.services.netlify.com'), + ) expect(analyticsCall).toBeDefined() expect(analyticsCall![0]).toContain('edge_function_logs') expect(analyticsCall![0]).toContain('site_id') From 0d7844f402e5395d7196f0120c8e709950d09c57 Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Fri, 13 Feb 2026 09:54:50 -0800 Subject: [PATCH 08/14] fix: resolve lint errors in logs commands and tests Add proper type assertions to eliminate unsafe-any and non-null assertion lint errors. Co-Authored-By: Claude Opus 4.6 --- src/commands/logs/edge-functions.ts | 25 ++++++++++--------- src/commands/logs/log-api.ts | 2 +- .../commands/logs/edge-functions.test.ts | 19 +++++++------- .../commands/logs/functions.test.ts | 6 ++--- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/commands/logs/edge-functions.ts b/src/commands/logs/edge-functions.ts index ef7c0d41058..8dbdc255dad 100644 --- a/src/commands/logs/edge-functions.ts +++ b/src/commands/logs/edge-functions.ts @@ -10,7 +10,7 @@ import { CLI_LOG_LEVEL_CHOICES_STRING, LOG_LEVELS_LIST } from './log-levels.js' import { getName } from './build.js' export const logsEdgeFunction = async (options: OptionValues, command: BaseCommand) => { - let deployId: string | undefined = options.deployId + let deployId = options.deployId as string | undefined await command.authenticate() const client = command.netlify.api @@ -22,15 +22,16 @@ export const logsEdgeFunction = async (options: OptionValues, command: BaseComma return } - if (options.level && !options.level.every((level: string) => LOG_LEVELS_LIST.includes(level))) { - log(`Invalid log level. Choices are:${CLI_LOG_LEVEL_CHOICES_STRING}`) + const levels = options.level as string[] | undefined + if (levels && !levels.every((level) => LOG_LEVELS_LIST.includes(level))) { + log(`Invalid log level. Choices are:${CLI_LOG_LEVEL_CHOICES_STRING.toString()}`) } - const levelsToPrint = options.level || LOG_LEVELS_LIST + const levelsToPrint: string[] = levels || LOG_LEVELS_LIST if (options.from) { - const fromMs = parseDateToMs(options.from) - const toMs = options.to ? parseDateToMs(options.to) : Date.now() + const fromMs = parseDateToMs(options.from as string) + const toMs = options.to ? parseDateToMs(options.to as string) : Date.now() const url = `https://analytics.services.netlify.com/v2/sites/${siteId}/edge_function_logs?from=${fromMs.toString()}&to=${toMs.toString()}` const data = await fetchHistoricalLogs({ url, accessToken: client.accessToken ?? '' }) @@ -38,7 +39,7 @@ export const logsEdgeFunction = async (options: OptionValues, command: BaseComma return } - const userId = command.netlify.globalConfig.get('userId') + const userId = command.netlify.globalConfig.get('userId') as string if (!deployId) { const deploys = await client.listSiteDeploys({ siteId }) @@ -51,15 +52,15 @@ export const logsEdgeFunction = async (options: OptionValues, command: BaseComma if (deploys.length === 1) { deployId = deploys[0].id } else { - const { result } = await inquirer.prompt({ + const { result } = (await inquirer.prompt({ name: 'result', type: 'list', message: `Select a deploy\n\n${chalk.yellow('*')} indicates a deploy created by you`, - choices: deploys.map((deploy: any) => ({ + choices: deploys.map((deploy) => ({ name: getName({ deploy, userId }), value: deploy.id, })), - }) + })) as { result: string } deployId = result } @@ -79,7 +80,7 @@ export const logsEdgeFunction = async (options: OptionValues, command: BaseComma }) ws.on('message', (data: string) => { - const logData = JSON.parse(data) + const logData = JSON.parse(data) as { level: string; message: string; timestamp?: string } if (!levelsToPrint.includes(logData.level.toLowerCase())) { return } @@ -90,7 +91,7 @@ export const logsEdgeFunction = async (options: OptionValues, command: BaseComma log('Connection closed') }) - ws.on('error', (err: any) => { + ws.on('error', (err: Error) => { log('Connection error') log(err) }) diff --git a/src/commands/logs/log-api.ts b/src/commands/logs/log-api.ts index af40658cc6a..bd8312d2579 100644 --- a/src/commands/logs/log-api.ts +++ b/src/commands/logs/log-api.ts @@ -54,7 +54,7 @@ export function formatLogEntry(entry: { timestamp?: string; level?: string; mess } export function printHistoricalLogs(data: unknown, levelsToPrint: string[]): void { - const entries = Array.isArray(data) ? data : [] + const entries = Array.isArray(data) ? (data as { timestamp?: string; level?: string; message?: string }[]) : [] if (entries.length === 0) { log('No logs found for the specified time range') diff --git a/tests/integration/commands/logs/edge-functions.test.ts b/tests/integration/commands/logs/edge-functions.test.ts index 3cbcec155e8..adebf139ac3 100644 --- a/tests/integration/commands/logs/edge-functions.test.ts +++ b/tests/integration/commands/logs/edge-functions.test.ts @@ -124,13 +124,12 @@ describe('logs:edge-functions command', () => { const setupCall = spyOn.mock.calls.find((args) => args[0] === 'open') expect(setupCall).toBeDefined() - const openCallback = setupCall?.[1] + const openCallback = setupCall?.[1] as (() => void) | undefined openCallback?.() expect(spySend).toHaveBeenCalledOnce() - const call = spySend.mock.calls[0] - const [message] = call - const body = JSON.parse(message) + const call = spySend.mock.calls[0] as string[] + const body = JSON.parse(call[0]) as Record expect(body.deploy_id).toEqual('deploy-id-1') expect(body.site_id).toEqual('site_id') @@ -154,11 +153,11 @@ describe('logs:edge-functions command', () => { await program.parseAsync(['', '', 'logs:edge-functions', '--deploy-id', 'my-deploy-id']) const setupCall = spyOn.mock.calls.find((args) => args[0] === 'open') - const openCallback = setupCall?.[1] + const openCallback = setupCall?.[1] as (() => void) | undefined openCallback?.() - const call = spySend.mock.calls[0] - const body = JSON.parse(call[0]) + const call = spySend.mock.calls[0] as string[] + const body = JSON.parse(call[0]) as Record expect(body.deploy_id).toEqual('my-deploy-id') }) @@ -179,7 +178,7 @@ describe('logs:edge-functions command', () => { await program.parseAsync(['', '', 'logs:edge-functions', '--level', 'info']) const messageCallback = spyOn.mock.calls.find((args) => args[0] === 'message') - const messageCallbackFunc = messageCallback?.[1] + const messageCallbackFunc = messageCallback?.[1] as ((data: string) => void) | undefined messageCallbackFunc?.(JSON.stringify({ level: LOG_LEVELS.INFO, message: 'Hello World' })) messageCallbackFunc?.(JSON.stringify({ level: LOG_LEVELS.WARN, message: 'There was a warning' })) @@ -216,8 +215,8 @@ describe('logs:edge-functions command', () => { args[0].includes('analytics.services.netlify.com'), ) expect(analyticsCall).toBeDefined() - expect(analyticsCall![0]).toContain('edge_function_logs') - expect(analyticsCall![0]).toContain('site_id') + expect((analyticsCall as string[])[0]).toContain('edge_function_logs') + expect((analyticsCall as string[])[0]).toContain('site_id') } finally { global.fetch = originalFetch } diff --git a/tests/integration/commands/logs/functions.test.ts b/tests/integration/commands/logs/functions.test.ts index e15ca331e59..d663ec38820 100644 --- a/tests/integration/commands/logs/functions.test.ts +++ b/tests/integration/commands/logs/functions.test.ts @@ -296,9 +296,9 @@ describe('logs:function command', () => { return parsedUrl.hostname === 'analytics.services.netlify.com' }) expect(analyticsCall).toBeDefined() - expect(analyticsCall![0]).toContain('function_logs') - expect(analyticsCall![0]).toContain('cool-function') - expect(analyticsCall![0]).toContain('site_id') + expect((analyticsCall as string[])[0]).toContain('function_logs') + expect((analyticsCall as string[])[0]).toContain('cool-function') + expect((analyticsCall as string[])[0]).toContain('site_id') } finally { global.fetch = originalFetch } From 06e3ce57a5b7251d52d186e001a172a899701408 Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Fri, 13 Feb 2026 09:56:21 -0800 Subject: [PATCH 09/14] fix: resolve typecheck error in edge-functions error handler Co-Authored-By: Claude Opus 4.6 --- src/commands/logs/edge-functions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/logs/edge-functions.ts b/src/commands/logs/edge-functions.ts index 8dbdc255dad..6737118af8d 100644 --- a/src/commands/logs/edge-functions.ts +++ b/src/commands/logs/edge-functions.ts @@ -93,6 +93,6 @@ export const logsEdgeFunction = async (options: OptionValues, command: BaseComma ws.on('error', (err: Error) => { log('Connection error') - log(err) + log(err.message) }) } From bd52070a5193b3ab235527d34949cdddb43be731 Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Fri, 13 Feb 2026 10:01:00 -0800 Subject: [PATCH 10/14] docs: regenerate command documentation Co-Authored-By: Claude Opus 4.6 --- docs/commands/agents.md | 14 +++++------ docs/commands/api.md | 4 ++-- docs/commands/blobs.md | 18 +++++++------- docs/commands/build.md | 4 ++-- docs/commands/clone.md | 4 ++-- docs/commands/completion.md | 2 +- docs/commands/db.md | 8 +++---- docs/commands/dev.md | 4 ++-- docs/commands/env.md | 24 +++++++++---------- docs/commands/functions.md | 18 +++++++------- docs/commands/init.md | 4 ++-- docs/commands/link.md | 4 ++-- docs/commands/login.md | 2 +- docs/commands/logs.md | 48 +++++++++++++++++++++++++++++++++---- docs/commands/open.md | 8 +++---- docs/commands/recipes.md | 4 ++-- docs/commands/sites.md | 10 ++++---- docs/commands/status.md | 6 ++--- docs/commands/unlink.md | 2 +- docs/commands/watch.md | 2 +- docs/index.md | 1 + 21 files changed, 116 insertions(+), 75 deletions(-) diff --git a/docs/commands/agents.md b/docs/commands/agents.md index 1f6cafdee62..215b3c64aee 100644 --- a/docs/commands/agents.md +++ b/docs/commands/agents.md @@ -21,9 +21,9 @@ netlify agents **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -91,12 +91,12 @@ netlify agents:list **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - output result as JSON - `project` (*string*) - project ID or name (if not in a linked directory) - `status` (*string*) - filter by status (new, running, done, error, cancelled) -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** @@ -123,11 +123,11 @@ netlify agents:show **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - output result as JSON - `project` (*string*) - project ID or name (if not in a linked directory) -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** @@ -153,11 +153,11 @@ netlify agents:stop **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - output result as JSON - `project` (*string*) - project ID or name (if not in a linked directory) -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** diff --git a/docs/commands/api.md b/docs/commands/api.md index a5561037f92..f5b74c676f8 100644 --- a/docs/commands/api.md +++ b/docs/commands/api.md @@ -24,10 +24,10 @@ netlify api **Flags** -- `data` (*string*) - Data to use -- `list` (*boolean*) - List out available API methods - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `data` (*string*) - Data to use +- `list` (*boolean*) - List out available API methods **Examples** diff --git a/docs/commands/blobs.md b/docs/commands/blobs.md index a0a6fb52b4f..a9c6b3d82cb 100644 --- a/docs/commands/blobs.md +++ b/docs/commands/blobs.md @@ -18,9 +18,9 @@ netlify blobs **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -59,10 +59,10 @@ netlify blobs:delete **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in -- `force` (*boolean*) - Bypasses prompts & Force the command to run. - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `force` (*boolean*) - Bypasses prompts & Force the command to run. --- ## `blobs:get` @@ -82,10 +82,10 @@ netlify blobs:get **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in -- `output` (*string*) - Defines the filesystem path where the blob data should be persisted - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `output` (*string*) - Defines the filesystem path where the blob data should be persisted --- ## `blobs:list` @@ -104,12 +104,12 @@ netlify blobs:list **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `directories` (*boolean*) - Indicates that keys with the '/' character should be treated as directories, returning a list of sub-directories at a given level rather than all the keys inside them - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - Output list contents as JSON - `prefix` (*string*) - A string for filtering down the entries; when specified, only the entries whose key starts with that prefix are returned -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- ## `blobs:set` @@ -130,11 +130,11 @@ netlify blobs:set **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `force` (*boolean*) - Bypasses prompts & Force the command to run. - `input` (*string*) - Defines the filesystem path where the blob data should be read from -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- diff --git a/docs/commands/build.md b/docs/commands/build.md index 2b345292b36..1da787629f2 100644 --- a/docs/commands/build.md +++ b/docs/commands/build.md @@ -17,11 +17,11 @@ netlify build **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `context` (*string*) - Specify a deploy context for environment variables read during the build (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch (default: value of CONTEXT or ”production”) - `dry` (*boolean*) - Dry run: show instructions without running them - `filter` (*string*) - For monorepos, specify the name of the application to run the command in -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `offline` (*boolean*) - Disables any features that require network access **Examples** diff --git a/docs/commands/clone.md b/docs/commands/clone.md index d67d38b62b5..c82806c8769 100644 --- a/docs/commands/clone.md +++ b/docs/commands/clone.md @@ -28,11 +28,11 @@ netlify clone **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `id` (*string*) - ID of existing Netlify project to link to - `name` (*string*) - Name of existing Netlify project to link to -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** diff --git a/docs/commands/completion.md b/docs/commands/completion.md index 71e9ee5d967..c460b785bfb 100644 --- a/docs/commands/completion.md +++ b/docs/commands/completion.md @@ -46,9 +46,9 @@ netlify completion:install **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in --- diff --git a/docs/commands/db.md b/docs/commands/db.md index de8ca48e83c..dbf21b4d75f 100644 --- a/docs/commands/db.md +++ b/docs/commands/db.md @@ -19,9 +19,9 @@ netlify db **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -51,12 +51,12 @@ netlify init **Flags** - `assume-no` (*boolean*) - Non-interactive setup. Does not initialize any third-party tools/boilerplate. Ideal for CI environments or AI tools. -- `boilerplate` (*drizzle*) - Type of boilerplate to add to your project. -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in -- `overwrite` (*boolean*) - Overwrites existing files that would be created when setting up boilerplate - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `boilerplate` (*drizzle*) - Type of boilerplate to add to your project. +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `no-boilerplate` (*boolean*) - Don't add any boilerplate to your project. +- `overwrite` (*boolean*) - Overwrites existing files that would be created when setting up boilerplate **Examples** diff --git a/docs/commands/dev.md b/docs/commands/dev.md index cba068156ce..a873f732a89 100644 --- a/docs/commands/dev.md +++ b/docs/commands/dev.md @@ -78,10 +78,10 @@ netlify dev:exec **Flags** -- `context` (*string*) - Specify a deploy context for environment variables (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch (default: dev) -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `context` (*string*) - Specify a deploy context for environment variables (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch (default: dev) +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in **Examples** diff --git a/docs/commands/env.md b/docs/commands/env.md index f21e118241a..3aa7b84789b 100644 --- a/docs/commands/env.md +++ b/docs/commands/env.md @@ -18,9 +18,9 @@ netlify env **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -56,12 +56,12 @@ netlify env:clone **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `force` (*boolean*) - Bypasses prompts & Force the command to run. - `from` (*string*) - Project ID (From) - `to` (*string*) - Project ID (To) -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** @@ -87,11 +87,11 @@ netlify env:get **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `context` (*string*) - Specify a deploy context for environment variables (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - Output environment variables as JSON -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `scope` (*builds | functions | post-processing | runtime | any*) - Specify a scope **Examples** @@ -120,11 +120,11 @@ netlify env:import **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - Output environment variables as JSON - `replace-existing` (*boolean*) - Replace all existing variables instead of merging them with the current ones -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- ## `env:list` @@ -139,13 +139,13 @@ netlify env:list **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `context` (*string*) - Specify a deploy context for environment variables (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch (default: all contexts) - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - Output environment variables as JSON -- `scope` (*builds | functions | post-processing | runtime | any*) - Specify a scope -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `plain` (*boolean*) - Output environment variables as plaintext +- `scope` (*builds | functions | post-processing | runtime | any*) - Specify a scope **Examples** @@ -214,12 +214,12 @@ netlify env:unset **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `context` (*string*) - Specify a deploy context for environment variables (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch (default: all contexts) - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `force` (*boolean*) - Bypasses prompts & Force the command to run. - `json` (*boolean*) - Output environment variables as JSON -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** diff --git a/docs/commands/functions.md b/docs/commands/functions.md index 11f5da7b1ba..fc30702f885 100644 --- a/docs/commands/functions.md +++ b/docs/commands/functions.md @@ -19,9 +19,9 @@ netlify functions **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -52,11 +52,11 @@ netlify functions:build **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `functions` (*string*) - Specify a functions directory to build to - `src` (*string*) - Specify the source directory for the functions -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- ## `functions:create` @@ -75,13 +75,13 @@ netlify functions:create **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `language` (*string*) - function language - `name` (*string*) - function name - `offline` (*boolean*) - Disables any features that require network access - `url` (*string*) - pull template from URL -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** @@ -149,11 +149,11 @@ netlify functions:list **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `functions` (*string*) - Specify a functions directory to list - `json` (*boolean*) - Output function data as JSON -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- ## `functions:serve` @@ -168,12 +168,12 @@ netlify functions:serve **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `functions` (*string*) - Specify a functions directory to serve - `offline` (*boolean*) - Disables any features that require network access - `port` (*string*) - Specify a port for the functions server -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- diff --git a/docs/commands/init.md b/docs/commands/init.md index 9aa21e7e4fe..7521d8b24c0 100644 --- a/docs/commands/init.md +++ b/docs/commands/init.md @@ -18,12 +18,12 @@ netlify init **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `force` (*boolean*) - Reinitialize CI hooks if the linked project is already configured to use CI - `git-remote-name` (*string*) - Name of Git remote to use. e.g. "origin" - `manual` (*boolean*) - Manually configure a git remote for CI -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in diff --git a/docs/commands/link.md b/docs/commands/link.md index 5d1b233e7b6..f7ad7656510 100644 --- a/docs/commands/link.md +++ b/docs/commands/link.md @@ -18,13 +18,13 @@ netlify link **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `git-remote-name` (*string*) - Name of Git remote to use. e.g. "origin" - `git-remote-url` (*string*) - URL of the repository (or Github `owner/repo`) to link to - `id` (*string*) - ID of project to link to - `name` (*string*) - Name of project to link to -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** diff --git a/docs/commands/login.md b/docs/commands/login.md index 2fdd7b4865b..4059fd1cfc1 100644 --- a/docs/commands/login.md +++ b/docs/commands/login.md @@ -19,9 +19,9 @@ netlify login **Flags** -- `new` (*boolean*) - Login to new Netlify account - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `new` (*boolean*) - Login to new Netlify account diff --git a/docs/commands/logs.md b/docs/commands/logs.md index 8c761e85b25..3b3426c2afb 100644 --- a/docs/commands/logs.md +++ b/docs/commands/logs.md @@ -17,13 +17,14 @@ netlify logs **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| | [`logs:deploy`](/commands/logs#logsdeploy) | Stream the logs of deploys currently being built to the console | +| [`logs:edge-functions`](/commands/logs#logsedge-functions) | Stream netlify edge function logs to the console | | [`logs:function`](/commands/logs#logsfunction) | Stream netlify function logs to the console | @@ -33,6 +34,8 @@ netlify logs netlify logs:deploy netlify logs:function netlify logs:function my-function +netlify logs:edge-functions +netlify logs:edge-functions --deploy-id ``` --- @@ -48,9 +51,40 @@ netlify logs:deploy **Flags** +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in + +--- +## `logs:edge-functions` + +Stream netlify edge function logs to the console + +**Usage** + +```bash +netlify logs:edge-functions +``` + +**Flags** + - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `deploy-id` (*string*) - Deploy ID to stream edge function logs for +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `from` (*string*) - Start date for historical logs (ISO 8601 format) +- `level` (*string*) - Log levels to stream. Choices are: trace, debug, info, warn, error, fatal +- `to` (*string*) - End date for historical logs (ISO 8601 format, defaults to now) + +**Examples** + +```bash +netlify logs:edge-functions +netlify logs:edge-functions --deploy-id +netlify logs:edge-functions --from 2026-01-01T00:00:00Z +netlify logs:edge-functions --from 2026-01-01T00:00:00Z --to 2026-01-02T00:00:00Z +netlify logs:edge-functions -l info warn +``` --- ## `logs:function` @@ -65,21 +99,27 @@ netlify logs:function **Arguments** -- functionName - Name of the function to stream logs for +- functionName - Name or ID of the function to stream logs for **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in -- `level` (*string*) - Log levels to stream. Choices are: trace, debug, info, warn, error, fatal - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `deploy-id` (*string*) - Deploy ID to look up the function from +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `from` (*string*) - Start date for historical logs (ISO 8601 format) +- `level` (*string*) - Log levels to stream. Choices are: trace, debug, info, warn, error, fatal +- `to` (*string*) - End date for historical logs (ISO 8601 format, defaults to now) **Examples** ```bash netlify logs:function netlify logs:function my-function +netlify logs:function my-function --deploy-id netlify logs:function my-function -l info warn +netlify logs:function my-function --from 2026-01-01T00:00:00Z +netlify logs:function my-function --from 2026-01-01T00:00:00Z --to 2026-01-02T00:00:00Z ``` --- diff --git a/docs/commands/open.md b/docs/commands/open.md index fc15acdd7a9..1accfa6af95 100644 --- a/docs/commands/open.md +++ b/docs/commands/open.md @@ -18,10 +18,10 @@ netlify open **Flags** - `admin` (*boolean*) - Open Netlify project -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in -- `site` (*boolean*) - Open project - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `site` (*boolean*) - Open project | Subcommand | description | |:--------------------------- |:-----| @@ -51,9 +51,9 @@ netlify open:admin **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in **Examples** @@ -74,9 +74,9 @@ netlify open:site **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in **Examples** diff --git a/docs/commands/recipes.md b/docs/commands/recipes.md index dcd1ed9ced1..29f5ddbd8a7 100644 --- a/docs/commands/recipes.md +++ b/docs/commands/recipes.md @@ -21,9 +21,9 @@ netlify recipes **Flags** -- `name` (*string*) - recipe name to use - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `name` (*string*) - recipe name to use | Subcommand | description | |:--------------------------- |:-----| @@ -50,9 +50,9 @@ netlify recipes:list **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in **Examples** diff --git a/docs/commands/sites.md b/docs/commands/sites.md index 94ef29bcad2..69f65660496 100644 --- a/docs/commands/sites.md +++ b/docs/commands/sites.md @@ -19,9 +19,9 @@ netlify sites **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -78,10 +78,10 @@ netlify sites:delete **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in -- `force` (*boolean*) - Delete without prompting (useful for CI). - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `force` (*boolean*) - Delete without prompting (useful for CI). **Examples** @@ -102,10 +102,10 @@ netlify sites:list **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in -- `json` (*boolean*) - Output project data as JSON - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `json` (*boolean*) - Output project data as JSON --- diff --git a/docs/commands/status.md b/docs/commands/status.md index 9529891046a..8a76f13fe28 100644 --- a/docs/commands/status.md +++ b/docs/commands/status.md @@ -18,10 +18,10 @@ netlify status **Flags** -- `json` (*boolean*) - Output status information as JSON -- `verbose` (*boolean*) - Output system info - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `json` (*boolean*) - Output status information as JSON +- `verbose` (*boolean*) - Output system info | Subcommand | description | |:--------------------------- |:-----| @@ -41,9 +41,9 @@ netlify status:hooks **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in --- diff --git a/docs/commands/unlink.md b/docs/commands/unlink.md index 030a0506d15..c44e1f780e9 100644 --- a/docs/commands/unlink.md +++ b/docs/commands/unlink.md @@ -18,9 +18,9 @@ netlify unlink **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in diff --git a/docs/commands/watch.md b/docs/commands/watch.md index ac7062847d5..95a4c45727d 100644 --- a/docs/commands/watch.md +++ b/docs/commands/watch.md @@ -18,9 +18,9 @@ netlify watch **Flags** -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in **Examples** diff --git a/docs/index.md b/docs/index.md index a306d1b873d..151b0f2000d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -132,6 +132,7 @@ Stream logs from your project | Subcommand | description | |:--------------------------- |:-----| | [`logs:deploy`](/commands/logs#logsdeploy) | Stream the logs of deploys currently being built to the console | +| [`logs:edge-functions`](/commands/logs#logsedge-functions) | Stream netlify edge function logs to the console | | [`logs:function`](/commands/logs#logsfunction) | Stream netlify function logs to the console | From a79f5d9467076347d68adaa497749b1900c15986 Mon Sep 17 00:00:00 2001 From: DavidWells Date: Wed, 25 Feb 2026 21:26:01 -0800 Subject: [PATCH 11/14] doc gen --- docs/commands/agents.md | 14 +++++++------- docs/commands/api.md | 4 ++-- docs/commands/blobs.md | 18 +++++++++--------- docs/commands/build.md | 4 ++-- docs/commands/clone.md | 4 ++-- docs/commands/completion.md | 2 +- docs/commands/db.md | 8 ++++---- docs/commands/dev.md | 4 ++-- docs/commands/env.md | 24 ++++++++++++------------ docs/commands/functions.md | 18 +++++++++--------- docs/commands/init.md | 4 ++-- docs/commands/link.md | 4 ++-- docs/commands/login.md | 2 +- docs/commands/logs.md | 12 ++++++------ docs/commands/open.md | 8 ++++---- docs/commands/recipes.md | 4 ++-- docs/commands/sites.md | 10 +++++----- docs/commands/status.md | 6 +++--- docs/commands/unlink.md | 2 +- docs/commands/watch.md | 2 +- 20 files changed, 77 insertions(+), 77 deletions(-) diff --git a/docs/commands/agents.md b/docs/commands/agents.md index 215b3c64aee..1f6cafdee62 100644 --- a/docs/commands/agents.md +++ b/docs/commands/agents.md @@ -21,9 +21,9 @@ netlify agents **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -91,12 +91,12 @@ netlify agents:list **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - output result as JSON - `project` (*string*) - project ID or name (if not in a linked directory) - `status` (*string*) - filter by status (new, running, done, error, cancelled) +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** @@ -123,11 +123,11 @@ netlify agents:show **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - output result as JSON - `project` (*string*) - project ID or name (if not in a linked directory) +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** @@ -153,11 +153,11 @@ netlify agents:stop **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - output result as JSON - `project` (*string*) - project ID or name (if not in a linked directory) +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** diff --git a/docs/commands/api.md b/docs/commands/api.md index f5b74c676f8..a5561037f92 100644 --- a/docs/commands/api.md +++ b/docs/commands/api.md @@ -24,10 +24,10 @@ netlify api **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `data` (*string*) - Data to use - `list` (*boolean*) - List out available API methods +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** diff --git a/docs/commands/blobs.md b/docs/commands/blobs.md index a9c6b3d82cb..a0a6fb52b4f 100644 --- a/docs/commands/blobs.md +++ b/docs/commands/blobs.md @@ -18,9 +18,9 @@ netlify blobs **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -59,10 +59,10 @@ netlify blobs:delete **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `force` (*boolean*) - Bypasses prompts & Force the command to run. +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- ## `blobs:get` @@ -82,10 +82,10 @@ netlify blobs:get **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `output` (*string*) - Defines the filesystem path where the blob data should be persisted +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- ## `blobs:list` @@ -104,12 +104,12 @@ netlify blobs:list **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `directories` (*boolean*) - Indicates that keys with the '/' character should be treated as directories, returning a list of sub-directories at a given level rather than all the keys inside them - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - Output list contents as JSON - `prefix` (*string*) - A string for filtering down the entries; when specified, only the entries whose key starts with that prefix are returned +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- ## `blobs:set` @@ -130,11 +130,11 @@ netlify blobs:set **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `force` (*boolean*) - Bypasses prompts & Force the command to run. - `input` (*string*) - Defines the filesystem path where the blob data should be read from +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- diff --git a/docs/commands/build.md b/docs/commands/build.md index 1da787629f2..2b345292b36 100644 --- a/docs/commands/build.md +++ b/docs/commands/build.md @@ -17,11 +17,11 @@ netlify build **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `context` (*string*) - Specify a deploy context for environment variables read during the build (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch (default: value of CONTEXT or ”production”) - `dry` (*boolean*) - Dry run: show instructions without running them - `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `offline` (*boolean*) - Disables any features that require network access **Examples** diff --git a/docs/commands/clone.md b/docs/commands/clone.md index c82806c8769..d67d38b62b5 100644 --- a/docs/commands/clone.md +++ b/docs/commands/clone.md @@ -28,11 +28,11 @@ netlify clone **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `id` (*string*) - ID of existing Netlify project to link to - `name` (*string*) - Name of existing Netlify project to link to +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** diff --git a/docs/commands/completion.md b/docs/commands/completion.md index c460b785bfb..71e9ee5d967 100644 --- a/docs/commands/completion.md +++ b/docs/commands/completion.md @@ -46,9 +46,9 @@ netlify completion:install **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in --- diff --git a/docs/commands/db.md b/docs/commands/db.md index dbf21b4d75f..de8ca48e83c 100644 --- a/docs/commands/db.md +++ b/docs/commands/db.md @@ -19,9 +19,9 @@ netlify db **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -51,12 +51,12 @@ netlify init **Flags** - `assume-no` (*boolean*) - Non-interactive setup. Does not initialize any third-party tools/boilerplate. Ideal for CI environments or AI tools. -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `boilerplate` (*drizzle*) - Type of boilerplate to add to your project. - `filter` (*string*) - For monorepos, specify the name of the application to run the command in -- `no-boilerplate` (*boolean*) - Don't add any boilerplate to your project. - `overwrite` (*boolean*) - Overwrites existing files that would be created when setting up boilerplate +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `no-boilerplate` (*boolean*) - Don't add any boilerplate to your project. **Examples** diff --git a/docs/commands/dev.md b/docs/commands/dev.md index a873f732a89..cba068156ce 100644 --- a/docs/commands/dev.md +++ b/docs/commands/dev.md @@ -78,10 +78,10 @@ netlify dev:exec **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `context` (*string*) - Specify a deploy context for environment variables (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch (default: dev) - `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** diff --git a/docs/commands/env.md b/docs/commands/env.md index 3aa7b84789b..f21e118241a 100644 --- a/docs/commands/env.md +++ b/docs/commands/env.md @@ -18,9 +18,9 @@ netlify env **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -56,12 +56,12 @@ netlify env:clone **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `force` (*boolean*) - Bypasses prompts & Force the command to run. - `from` (*string*) - Project ID (From) - `to` (*string*) - Project ID (To) +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** @@ -87,11 +87,11 @@ netlify env:get **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `context` (*string*) - Specify a deploy context for environment variables (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - Output environment variables as JSON +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `scope` (*builds | functions | post-processing | runtime | any*) - Specify a scope **Examples** @@ -120,11 +120,11 @@ netlify env:import **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - Output environment variables as JSON - `replace-existing` (*boolean*) - Replace all existing variables instead of merging them with the current ones +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- ## `env:list` @@ -139,13 +139,13 @@ netlify env:list **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `context` (*string*) - Specify a deploy context for environment variables (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch (default: all contexts) - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - Output environment variables as JSON -- `plain` (*boolean*) - Output environment variables as plaintext - `scope` (*builds | functions | post-processing | runtime | any*) - Specify a scope +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `plain` (*boolean*) - Output environment variables as plaintext **Examples** @@ -214,12 +214,12 @@ netlify env:unset **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `context` (*string*) - Specify a deploy context for environment variables (”production”, ”deploy-preview”, ”branch-deploy”, ”dev”) or `branch:your-branch` where `your-branch` is the name of a branch (default: all contexts) - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `force` (*boolean*) - Bypasses prompts & Force the command to run. - `json` (*boolean*) - Output environment variables as JSON +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** diff --git a/docs/commands/functions.md b/docs/commands/functions.md index fc30702f885..11f5da7b1ba 100644 --- a/docs/commands/functions.md +++ b/docs/commands/functions.md @@ -19,9 +19,9 @@ netlify functions **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -52,11 +52,11 @@ netlify functions:build **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `functions` (*string*) - Specify a functions directory to build to - `src` (*string*) - Specify the source directory for the functions +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- ## `functions:create` @@ -75,13 +75,13 @@ netlify functions:create **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `language` (*string*) - function language - `name` (*string*) - function name - `offline` (*boolean*) - Disables any features that require network access - `url` (*string*) - pull template from URL +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** @@ -149,11 +149,11 @@ netlify functions:list **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `functions` (*string*) - Specify a functions directory to list - `json` (*boolean*) - Output function data as JSON +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- ## `functions:serve` @@ -168,12 +168,12 @@ netlify functions:serve **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `functions` (*string*) - Specify a functions directory to serve - `offline` (*boolean*) - Disables any features that require network access - `port` (*string*) - Specify a port for the functions server +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- diff --git a/docs/commands/init.md b/docs/commands/init.md index 7521d8b24c0..9aa21e7e4fe 100644 --- a/docs/commands/init.md +++ b/docs/commands/init.md @@ -18,12 +18,12 @@ netlify init **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `force` (*boolean*) - Reinitialize CI hooks if the linked project is already configured to use CI - `git-remote-name` (*string*) - Name of Git remote to use. e.g. "origin" - `manual` (*boolean*) - Manually configure a git remote for CI +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in diff --git a/docs/commands/link.md b/docs/commands/link.md index f7ad7656510..5d1b233e7b6 100644 --- a/docs/commands/link.md +++ b/docs/commands/link.md @@ -18,13 +18,13 @@ netlify link **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `git-remote-name` (*string*) - Name of Git remote to use. e.g. "origin" - `git-remote-url` (*string*) - URL of the repository (or Github `owner/repo`) to link to - `id` (*string*) - ID of project to link to - `name` (*string*) - Name of project to link to +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** diff --git a/docs/commands/login.md b/docs/commands/login.md index 4059fd1cfc1..2fdd7b4865b 100644 --- a/docs/commands/login.md +++ b/docs/commands/login.md @@ -19,9 +19,9 @@ netlify login **Flags** +- `new` (*boolean*) - Login to new Netlify account - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `new` (*boolean*) - Login to new Netlify account diff --git a/docs/commands/logs.md b/docs/commands/logs.md index 3b3426c2afb..3aa133598ad 100644 --- a/docs/commands/logs.md +++ b/docs/commands/logs.md @@ -17,9 +17,9 @@ netlify logs **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -51,9 +51,9 @@ netlify logs:deploy **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in --- ## `logs:edge-functions` @@ -68,12 +68,12 @@ netlify logs:edge-functions **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `deploy-id` (*string*) - Deploy ID to stream edge function logs for - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `from` (*string*) - Start date for historical logs (ISO 8601 format) - `level` (*string*) - Log levels to stream. Choices are: trace, debug, info, warn, error, fatal +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `to` (*string*) - End date for historical logs (ISO 8601 format, defaults to now) **Examples** @@ -103,12 +103,12 @@ netlify logs:function **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `deploy-id` (*string*) - Deploy ID to look up the function from - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `from` (*string*) - Start date for historical logs (ISO 8601 format) - `level` (*string*) - Log levels to stream. Choices are: trace, debug, info, warn, error, fatal +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `to` (*string*) - End date for historical logs (ISO 8601 format, defaults to now) **Examples** diff --git a/docs/commands/open.md b/docs/commands/open.md index 1accfa6af95..fc15acdd7a9 100644 --- a/docs/commands/open.md +++ b/docs/commands/open.md @@ -18,10 +18,10 @@ netlify open **Flags** - `admin` (*boolean*) - Open Netlify project -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `site` (*boolean*) - Open project +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in | Subcommand | description | |:--------------------------- |:-----| @@ -51,9 +51,9 @@ netlify open:admin **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in **Examples** @@ -74,9 +74,9 @@ netlify open:site **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in **Examples** diff --git a/docs/commands/recipes.md b/docs/commands/recipes.md index 29f5ddbd8a7..dcd1ed9ced1 100644 --- a/docs/commands/recipes.md +++ b/docs/commands/recipes.md @@ -21,9 +21,9 @@ netlify recipes **Flags** +- `name` (*string*) - recipe name to use - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `name` (*string*) - recipe name to use | Subcommand | description | |:--------------------------- |:-----| @@ -50,9 +50,9 @@ netlify recipes:list **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in **Examples** diff --git a/docs/commands/sites.md b/docs/commands/sites.md index 69f65660496..94ef29bcad2 100644 --- a/docs/commands/sites.md +++ b/docs/commands/sites.md @@ -19,9 +19,9 @@ netlify sites **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in | Subcommand | description | |:--------------------------- |:-----| @@ -78,10 +78,10 @@ netlify sites:delete **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `force` (*boolean*) - Delete without prompting (useful for CI). +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in **Examples** @@ -102,10 +102,10 @@ netlify sites:list **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `json` (*boolean*) - Output project data as JSON +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in --- diff --git a/docs/commands/status.md b/docs/commands/status.md index 8a76f13fe28..9529891046a 100644 --- a/docs/commands/status.md +++ b/docs/commands/status.md @@ -18,10 +18,10 @@ netlify status **Flags** -- `debug` (*boolean*) - Print debugging information -- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in - `json` (*boolean*) - Output status information as JSON - `verbose` (*boolean*) - Output system info +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in | Subcommand | description | |:--------------------------- |:-----| @@ -41,9 +41,9 @@ netlify status:hooks **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in --- diff --git a/docs/commands/unlink.md b/docs/commands/unlink.md index c44e1f780e9..030a0506d15 100644 --- a/docs/commands/unlink.md +++ b/docs/commands/unlink.md @@ -18,9 +18,9 @@ netlify unlink **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in diff --git a/docs/commands/watch.md b/docs/commands/watch.md index 95a4c45727d..ac7062847d5 100644 --- a/docs/commands/watch.md +++ b/docs/commands/watch.md @@ -18,9 +18,9 @@ netlify watch **Flags** +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in -- `filter` (*string*) - For monorepos, specify the name of the application to run the command in **Examples** From 0ba377aa1ad5458bab2c575db25784d4530611cf Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Date: Sun, 29 Mar 2026 21:38:56 -0700 Subject: [PATCH 12/14] fix: address PR review comments for logs commands Centralize analytics URL generation into log-api.ts, add siteId null guard in functions.ts, encode URL path segments, normalize log level filtering, fix lint issues in tests, and update deploy output labels. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/commands/logs.md | 4 +-- src/commands/deploy/deploy.ts | 8 ++--- src/commands/logs/edge-functions.ts | 6 ++-- src/commands/logs/functions.ts | 13 +++++--- src/commands/logs/log-api.ts | 33 ++++++++++++++++++- .../commands/logs/edge-functions.test.ts | 10 +++--- .../commands/logs/functions.test.ts | 6 ++-- 7 files changed, 59 insertions(+), 21 deletions(-) diff --git a/docs/commands/logs.md b/docs/commands/logs.md index 3aa133598ad..6426550a37c 100644 --- a/docs/commands/logs.md +++ b/docs/commands/logs.md @@ -99,11 +99,11 @@ netlify logs:function **Arguments** -- functionName - Name or ID of the function to stream logs for +- `functionName` - Name or ID of the function to stream logs for **Flags** -- `deploy-id` (*string*) - Deploy ID to look up the function from +- `deploy-id` (*string*) - Deploy ID to find the function from - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `from` (*string*) - Start date for historical logs (ISO 8601 format) - `level` (*string*) - Log levels to stream. Choices are: trace, debug, info, warn, error, fatal diff --git a/src/commands/deploy/deploy.ts b/src/commands/deploy/deploy.ts index c6250819699..4c68a01b2ee 100644 --- a/src/commands/deploy/deploy.ts +++ b/src/commands/deploy/deploy.ts @@ -813,13 +813,13 @@ const printResults = ({ } const functionLogsData: Record = { - 'Function logs': terminalLink(results.functionLogsUrl, results.functionLogsUrl, { fallback: false }), - 'Function CLI': `netlify logs:function --deploy-id ${results.deployId} `, + 'Functions logs': terminalLink(results.functionLogsUrl, results.functionLogsUrl, { fallback: false }), + 'Functions CLI': `netlify logs:function --deploy-id ${results.deployId} `, } const edgeFunctionLogsData: Record = { - 'Edge function logs': terminalLink(results.edgeFunctionLogsUrl, results.edgeFunctionLogsUrl, { fallback: false }), - 'Edge function CLI': `netlify logs:edge-functions --deploy-id ${results.deployId}`, + 'Edge Functions logs': terminalLink(results.edgeFunctionLogsUrl, results.edgeFunctionLogsUrl, { fallback: false }), + 'Edge Functions CLI': `netlify logs:edge-functions --deploy-id ${results.deployId}`, } log('') diff --git a/src/commands/logs/edge-functions.ts b/src/commands/logs/edge-functions.ts index 6737118af8d..44ba93f785a 100644 --- a/src/commands/logs/edge-functions.ts +++ b/src/commands/logs/edge-functions.ts @@ -5,7 +5,7 @@ import { chalk, log } from '../../utils/command-helpers.js' import { getWebSocket } from '../../utils/websockets/index.js' import type BaseCommand from '../base-command.js' -import { parseDateToMs, fetchHistoricalLogs, printHistoricalLogs, formatLogEntry } from './log-api.js' +import { parseDateToMs, buildEdgeFunctionLogsUrl, fetchHistoricalLogs, printHistoricalLogs, formatLogEntry } from './log-api.js' import { CLI_LOG_LEVEL_CHOICES_STRING, LOG_LEVELS_LIST } from './log-levels.js' import { getName } from './build.js' @@ -24,7 +24,7 @@ export const logsEdgeFunction = async (options: OptionValues, command: BaseComma const levels = options.level as string[] | undefined if (levels && !levels.every((level) => LOG_LEVELS_LIST.includes(level))) { - log(`Invalid log level. Choices are:${CLI_LOG_LEVEL_CHOICES_STRING.toString()}`) + log(`Invalid log level. Choices are:${CLI_LOG_LEVEL_CHOICES_STRING.join(',')}`) } const levelsToPrint: string[] = levels || LOG_LEVELS_LIST @@ -33,7 +33,7 @@ export const logsEdgeFunction = async (options: OptionValues, command: BaseComma const fromMs = parseDateToMs(options.from as string) const toMs = options.to ? parseDateToMs(options.to as string) : Date.now() - const url = `https://analytics.services.netlify.com/v2/sites/${siteId}/edge_function_logs?from=${fromMs.toString()}&to=${toMs.toString()}` + const url = buildEdgeFunctionLogsUrl({ siteId, from: fromMs, to: toMs }) const data = await fetchHistoricalLogs({ url, accessToken: client.accessToken ?? '' }) printHistoricalLogs(data, levelsToPrint) return diff --git a/src/commands/logs/functions.ts b/src/commands/logs/functions.ts index 22d0932cda4..3ca5c4f5c37 100644 --- a/src/commands/logs/functions.ts +++ b/src/commands/logs/functions.ts @@ -5,7 +5,7 @@ import { chalk, log } from '../../utils/command-helpers.js' import { getWebSocket } from '../../utils/websockets/index.js' import type BaseCommand from '../base-command.js' -import { parseDateToMs, fetchHistoricalLogs, printHistoricalLogs } from './log-api.js' +import { parseDateToMs, buildFunctionLogsUrl, fetchHistoricalLogs, printHistoricalLogs } from './log-api.js' import { CLI_LOG_LEVEL_CHOICES_STRING, LOG_LEVELS, LOG_LEVELS_LIST } from './log-levels.js' function getLog(logData: { level: string; message: string }) { @@ -35,6 +35,11 @@ export const logsFunction = async (functionName: string | undefined, options: Op const { site, siteInfo } = command.netlify const { id: siteId } = site + if (!siteId) { + log('You must link a project before attempting to view function logs') + return + } + if (options.level && !options.level.every((level: string) => LOG_LEVELS_LIST.includes(level))) { log(`Invalid log level. Choices are:${CLI_LOG_LEVEL_CHOICES_STRING}`) } @@ -43,11 +48,11 @@ export const logsFunction = async (functionName: string | undefined, options: Op let functions: any[] if (options.deployId) { - const deploy = (await client.getSiteDeploy({ siteId: siteId!, deployId: options.deployId })) as any + const deploy = (await client.getSiteDeploy({ siteId: siteId, deployId: options.deployId })) as any functions = deploy.available_functions ?? [] } else { // TODO: Update type once the open api spec is updated https://open-api.netlify.com/#tag/function/operation/searchSiteFunctions - const result = (await client.searchSiteFunctions({ siteId: siteId! })) as any + const result = (await client.searchSiteFunctions({ siteId: siteId })) as any functions = result.functions ?? [] } @@ -82,7 +87,7 @@ export const logsFunction = async (functionName: string | undefined, options: Op const toMs = options.to ? parseDateToMs(options.to) : Date.now() const branch = siteInfo.build_settings?.repo_branch ?? 'main' - const url = `https://analytics.services.netlify.com/v2/sites/${siteId}/branch/${branch}/function_logs/${resolvedFunctionName}?from=${fromMs.toString()}&to=${toMs.toString()}` + const url = buildFunctionLogsUrl({ siteId, branch, functionName: resolvedFunctionName, from: fromMs, to: toMs }) const data = await fetchHistoricalLogs({ url, accessToken: client.accessToken ?? '' }) printHistoricalLogs(data, levelsToPrint) return diff --git a/src/commands/logs/log-api.ts b/src/commands/logs/log-api.ts index bd8312d2579..47159f1813c 100644 --- a/src/commands/logs/log-api.ts +++ b/src/commands/logs/log-api.ts @@ -9,6 +9,36 @@ export function parseDateToMs(dateString: string): number { return ms } +const ANALYTICS_BASE_URL = 'https://analytics.services.netlify.com/v2/sites' + +export function buildFunctionLogsUrl({ + siteId, + branch, + functionName, + from, + to, +}: { + siteId: string + branch: string + functionName: string + from: number + to: number +}): string { + return `${ANALYTICS_BASE_URL}/${encodeURIComponent(siteId)}/branch/${encodeURIComponent(branch)}/function_logs/${encodeURIComponent(functionName)}?from=${from.toString()}&to=${to.toString()}` +} + +export function buildEdgeFunctionLogsUrl({ + siteId, + from, + to, +}: { + siteId: string + from: number + to: number +}): string { + return `${ANALYTICS_BASE_URL}/${encodeURIComponent(siteId)}/edge_function_logs?from=${from.toString()}&to=${to.toString()}` +} + export async function fetchHistoricalLogs({ url, accessToken, @@ -55,6 +85,7 @@ export function formatLogEntry(entry: { timestamp?: string; level?: string; mess export function printHistoricalLogs(data: unknown, levelsToPrint: string[]): void { const entries = Array.isArray(data) ? (data as { timestamp?: string; level?: string; message?: string }[]) : [] + const normalizedLevels = levelsToPrint.map((level) => level.toLowerCase()) if (entries.length === 0) { log('No logs found for the specified time range') @@ -63,7 +94,7 @@ export function printHistoricalLogs(data: unknown, levelsToPrint: string[]): voi for (const entry of entries) { const level = (entry.level ?? '').toLowerCase() - if (levelsToPrint.length > 0 && !levelsToPrint.includes(level)) { + if (normalizedLevels.length > 0 && !normalizedLevels.includes(level)) { continue } log(formatLogEntry(entry)) diff --git a/tests/integration/commands/logs/edge-functions.test.ts b/tests/integration/commands/logs/edge-functions.test.ts index adebf139ac3..a65d7fe2252 100644 --- a/tests/integration/commands/logs/edge-functions.test.ts +++ b/tests/integration/commands/logs/edge-functions.test.ts @@ -197,7 +197,8 @@ describe('logs:edge-functions command', () => { const originalFetch = global.fetch const spyFetch = vi.fn().mockImplementation((url: string) => { - if (url.includes('analytics.services.netlify.com')) { + const parsedUrl = new URL(url) + if (parsedUrl.hostname === 'analytics.services.netlify.com') { return Promise.resolve({ ok: true, json: () => Promise.resolve(mockLogs), @@ -211,9 +212,10 @@ describe('logs:edge-functions command', () => { await program.parseAsync(['', '', 'logs:edge-functions', '--from', '2026-01-01T00:00:00Z']) expect(spyWebsocket).not.toHaveBeenCalled() - const analyticsCall = spyFetch.mock.calls.find((args: string[]) => - args[0].includes('analytics.services.netlify.com'), - ) + const analyticsCall = spyFetch.mock.calls.find((args: string[]) => { + const parsedUrl = new URL(args[0]) + return parsedUrl.hostname === 'analytics.services.netlify.com' + }) expect(analyticsCall).toBeDefined() expect((analyticsCall as string[])[0]).toContain('edge_function_logs') expect((analyticsCall as string[])[0]).toContain('site_id') diff --git a/tests/integration/commands/logs/functions.test.ts b/tests/integration/commands/logs/functions.test.ts index d663ec38820..feb76e70639 100644 --- a/tests/integration/commands/logs/functions.test.ts +++ b/tests/integration/commands/logs/functions.test.ts @@ -202,7 +202,7 @@ describe('logs:function command', () => { expect(spyLog).toHaveBeenCalledTimes(2) }) - test('should find function by ID', async ({}) => { + test('should find function by ID', async () => { const { apiUrl } = await startMockApi({ routes }) const spyWebsocket = getWebSocket as unknown as Mock const spyOn = vi.fn() @@ -228,7 +228,7 @@ describe('logs:function command', () => { expect(body.site_id).toEqual('site_id') }) - test('should look up function from deploy when --deploy is specified', async ({}) => { + test('should look up function from deploy when --deploy-id is specified', async () => { const deployRoutes = [ ...routes, { @@ -264,7 +264,7 @@ describe('logs:function command', () => { expect(body.site_id).toEqual('site_id') }) - test('should fetch historical logs when --from is specified', async ({}) => { + test('should fetch historical logs when --from is specified', async () => { const { apiUrl } = await startMockApi({ routes }) const spyWebsocket = getWebSocket as unknown as Mock From 82bd7e5fe6551ceb1f7b4e40214b6e1d84464bb0 Mon Sep 17 00:00:00 2001 From: DavidWells Date: Tue, 31 Mar 2026 08:07:47 -0700 Subject: [PATCH 13/14] feat: add deploy:logs and functions:logs command aliases Add cleaner aliases so log commands are discoverable under their parent namespaces (deploy:logs, functions:logs, function:logs) while keeping the existing logs:* commands intact. --- src/commands/deploy/deploy.ts | 2 +- src/commands/logs/index.ts | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/commands/deploy/deploy.ts b/src/commands/deploy/deploy.ts index 4c68a01b2ee..5af91d36592 100644 --- a/src/commands/deploy/deploy.ts +++ b/src/commands/deploy/deploy.ts @@ -814,7 +814,7 @@ const printResults = ({ const functionLogsData: Record = { 'Functions logs': terminalLink(results.functionLogsUrl, results.functionLogsUrl, { fallback: false }), - 'Functions CLI': `netlify logs:function --deploy-id ${results.deployId} `, + 'Functions CLI': `netlify functions:logs --deploy-id ${results.deployId} `, } const edgeFunctionLogsData: Record = { diff --git a/src/commands/logs/index.ts b/src/commands/logs/index.ts index d0053ed1db6..d3c871e8c65 100644 --- a/src/commands/logs/index.ts +++ b/src/commands/logs/index.ts @@ -64,6 +64,34 @@ export const createLogsEdgeFunctionCommand = (program: BaseCommand) => { }) } +export const createDeployLogsCommand = (program: BaseCommand) => { + program + .command('deploy:logs') + .description('Stream the logs of deploys currently being built to the console') + .action(async (options: OptionValues, command: BaseCommand) => { + const { logsBuild } = await import('./build.js') + await logsBuild(options, command) + }) +} + +export const createFunctionsLogsCommand = (program: BaseCommand) => { + program + .command('functions:logs') + .alias('function:logs') + .addOption( + new Option('-l, --level ', `Log levels to stream. Choices are:${CLI_LOG_LEVEL_CHOICES_STRING}`), + ) + .addOption(new Option('--deploy-id ', 'Deploy ID to look up the function from')) + .addOption(new Option('--from ', 'Start date for historical logs (ISO 8601 format)')) + .addOption(new Option('--to ', 'End date for historical logs (ISO 8601 format, defaults to now)')) + .addArgument(new Argument('[functionName]', 'Name or ID of the function to stream logs for')) + .description('Stream netlify function logs to the console') + .action(async (functionName: string | undefined, options: OptionValues, command: BaseCommand) => { + const { logsFunction } = await import('./functions.js') + await logsFunction(functionName, options, command) + }) +} + export const createLogsCommand = (program: BaseCommand) => { createLogsBuildCommand(program) @@ -71,6 +99,10 @@ export const createLogsCommand = (program: BaseCommand) => { createLogsEdgeFunctionCommand(program) + createDeployLogsCommand(program) + + createFunctionsLogsCommand(program) + return program .command('logs') .alias('log') From 06bffb4db33e43c3c2a28a0adfb930e5e9c74cb2 Mon Sep 17 00:00:00 2001 From: DavidWells Date: Tue, 31 Mar 2026 08:11:55 -0700 Subject: [PATCH 14/14] chore: fix formatting and regenerate docs --- docs/commands/deploy.md | 23 +++++++++++++++++++++++ docs/commands/functions.md | 26 ++++++++++++++++++++++++++ docs/commands/logs.md | 4 ++-- docs/index.md | 6 ++++++ src/commands/logs/edge-functions.ts | 8 +++++++- src/commands/logs/log-api.ts | 18 +++++++----------- 6 files changed, 71 insertions(+), 14 deletions(-) diff --git a/docs/commands/deploy.md b/docs/commands/deploy.md index 30e3a0cb7a9..15629536eb1 100644 --- a/docs/commands/deploy.md +++ b/docs/commands/deploy.md @@ -48,6 +48,11 @@ netlify deploy - `timeout` (*string*) - Timeout to wait for deployment to finish - `trigger` (*boolean*) - Trigger a new build of your project on Netlify without uploading local files +| Subcommand | description | +|:--------------------------- |:-----| +| [`deploy:logs`](/commands/deploy#deploylogs) | Stream the logs of deploys currently being built to the console | + + **Examples** ```bash @@ -64,5 +69,23 @@ netlify deploy --context deploy-preview netlify deploy --create-site my-new-site --team my-team # Create site and deploy ``` +--- +## `deploy:logs` + +Stream the logs of deploys currently being built to the console + +**Usage** + +```bash +netlify deploy:logs +``` + +**Flags** + +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in + +--- diff --git a/docs/commands/functions.md b/docs/commands/functions.md index 11f5da7b1ba..9a2019509ce 100644 --- a/docs/commands/functions.md +++ b/docs/commands/functions.md @@ -29,6 +29,7 @@ netlify functions | [`functions:create`](/commands/functions#functionscreate) | Create a new function locally | | [`functions:invoke`](/commands/functions#functionsinvoke) | Trigger a function while in netlify dev with simulated data, good for testing function calls including Netlify's Event Triggered Functions | | [`functions:list`](/commands/functions#functionslist) | List functions that exist locally | +| [`functions:logs`](/commands/functions#functionslogs) | Stream netlify function logs to the console | | [`functions:serve`](/commands/functions#functionsserve) | Serve functions locally | @@ -155,6 +156,31 @@ netlify functions:list - `debug` (*boolean*) - Print debugging information - `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +--- +## `functions:logs` + +Stream netlify function logs to the console + +**Usage** + +```bash +netlify functions:logs +``` + +**Arguments** + +- functionName - Name or ID of the function to stream logs for + +**Flags** + +- `deploy-id` (*string*) - Deploy ID to look up the function from +- `filter` (*string*) - For monorepos, specify the name of the application to run the command in +- `from` (*string*) - Start date for historical logs (ISO 8601 format) +- `level` (*string*) - Log levels to stream. Choices are: trace, debug, info, warn, error, fatal +- `debug` (*boolean*) - Print debugging information +- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in +- `to` (*string*) - End date for historical logs (ISO 8601 format, defaults to now) + --- ## `functions:serve` diff --git a/docs/commands/logs.md b/docs/commands/logs.md index 6426550a37c..3aa133598ad 100644 --- a/docs/commands/logs.md +++ b/docs/commands/logs.md @@ -99,11 +99,11 @@ netlify logs:function **Arguments** -- `functionName` - Name or ID of the function to stream logs for +- functionName - Name or ID of the function to stream logs for **Flags** -- `deploy-id` (*string*) - Deploy ID to find the function from +- `deploy-id` (*string*) - Deploy ID to look up the function from - `filter` (*string*) - For monorepos, specify the name of the application to run the command in - `from` (*string*) - Start date for historical logs (ISO 8601 format) - `level` (*string*) - Log levels to stream. Choices are: trace, debug, info, warn, error, fatal diff --git a/docs/index.md b/docs/index.md index 151b0f2000d..e128e0fe894 100644 --- a/docs/index.md +++ b/docs/index.md @@ -77,6 +77,11 @@ Provision a production ready Postgres database with a single command Deploy your project to Netlify +| Subcommand | description | +|:--------------------------- |:-----| +| [`deploy:logs`](/commands/deploy#deploylogs) | Stream the logs of deploys currently being built to the console | + + ### [dev](/commands/dev) Local dev server @@ -110,6 +115,7 @@ Manage netlify functions | [`functions:create`](/commands/functions#functionscreate) | Create a new function locally | | [`functions:invoke`](/commands/functions#functionsinvoke) | Trigger a function while in netlify dev with simulated data, good for testing function calls including Netlify's Event Triggered Functions | | [`functions:list`](/commands/functions#functionslist) | List functions that exist locally | +| [`functions:logs`](/commands/functions#functionslogs) | Stream netlify function logs to the console | | [`functions:serve`](/commands/functions#functionsserve) | Serve functions locally | diff --git a/src/commands/logs/edge-functions.ts b/src/commands/logs/edge-functions.ts index 44ba93f785a..ce5d5e0b666 100644 --- a/src/commands/logs/edge-functions.ts +++ b/src/commands/logs/edge-functions.ts @@ -5,7 +5,13 @@ import { chalk, log } from '../../utils/command-helpers.js' import { getWebSocket } from '../../utils/websockets/index.js' import type BaseCommand from '../base-command.js' -import { parseDateToMs, buildEdgeFunctionLogsUrl, fetchHistoricalLogs, printHistoricalLogs, formatLogEntry } from './log-api.js' +import { + parseDateToMs, + buildEdgeFunctionLogsUrl, + fetchHistoricalLogs, + printHistoricalLogs, + formatLogEntry, +} from './log-api.js' import { CLI_LOG_LEVEL_CHOICES_STRING, LOG_LEVELS_LIST } from './log-levels.js' import { getName } from './build.js' diff --git a/src/commands/logs/log-api.ts b/src/commands/logs/log-api.ts index 47159f1813c..58c4694f378 100644 --- a/src/commands/logs/log-api.ts +++ b/src/commands/logs/log-api.ts @@ -24,19 +24,15 @@ export function buildFunctionLogsUrl({ from: number to: number }): string { - return `${ANALYTICS_BASE_URL}/${encodeURIComponent(siteId)}/branch/${encodeURIComponent(branch)}/function_logs/${encodeURIComponent(functionName)}?from=${from.toString()}&to=${to.toString()}` + return `${ANALYTICS_BASE_URL}/${encodeURIComponent(siteId)}/branch/${encodeURIComponent( + branch, + )}/function_logs/${encodeURIComponent(functionName)}?from=${from.toString()}&to=${to.toString()}` } -export function buildEdgeFunctionLogsUrl({ - siteId, - from, - to, -}: { - siteId: string - from: number - to: number -}): string { - return `${ANALYTICS_BASE_URL}/${encodeURIComponent(siteId)}/edge_function_logs?from=${from.toString()}&to=${to.toString()}` +export function buildEdgeFunctionLogsUrl({ siteId, from, to }: { siteId: string; from: number; to: number }): string { + return `${ANALYTICS_BASE_URL}/${encodeURIComponent( + siteId, + )}/edge_function_logs?from=${from.toString()}&to=${to.toString()}` } export async function fetchHistoricalLogs({