diff --git a/code/core/src/bin/core.ts b/code/core/src/bin/core.ts index ee757dfd7356..280e1888efe2 100644 --- a/code/core/src/bin/core.ts +++ b/code/core/src/bin/core.ts @@ -27,8 +27,10 @@ addToGlobalContext('cliVersion', version); */ const handleCommandFailure = async (logFilePath: string | boolean): Promise => { - const logFile = await logTracker.writeToFile(logFilePath); - logger.log(`Debug logs are written to: ${logFile}`); + try { + const logFile = await logTracker.writeToFile(logFilePath); + logger.log(`Debug logs are written to: ${logFile}`); + } catch {} logger.outro('Storybook exited with an error'); process.exit(1); }; @@ -66,8 +68,10 @@ const command = (name: string) => }) .hook('postAction', async (command) => { if (logTracker.shouldWriteLogsToFile) { - const logFile = await logTracker.writeToFile(command.getOptionValue('logfile')); - logger.outro(`Debug logs are written to: ${logFile}`); + try { + const logFile = await logTracker.writeToFile(command.getOptionValue('logfile')); + logger.outro(`Debug logs are written to: ${logFile}`); + } catch {} } }); diff --git a/code/core/src/core-server/withTelemetry.ts b/code/core/src/core-server/withTelemetry.ts index 2e0ce5726da8..c0d6deb37815 100644 --- a/code/core/src/core-server/withTelemetry.ts +++ b/code/core/src/core-server/withTelemetry.ts @@ -9,8 +9,6 @@ import { import type { EventType } from 'storybook/internal/telemetry'; import type { CLIOptions } from 'storybook/internal/types'; -import { dedent } from 'ts-dedent'; - import { StorybookError } from '../storybook-error'; type TelemetryOptions = { diff --git a/code/core/src/node-logger/index.ts b/code/core/src/node-logger/index.ts index 0184a017c2e9..ae2de0410ed1 100644 --- a/code/core/src/node-logger/index.ts +++ b/code/core/src/node-logger/index.ts @@ -11,6 +11,8 @@ export { protectUrls, createHyperlink } from './wrap-utils'; export { CLI_COLORS } from './logger/colors'; export { ConsoleLogger, StyledConsoleLogger } from './logger/console'; +export type { LogLevel } from './logger/logger'; + // The default is stderr, which can cause some tools (like rush.js) to think // there are issues with the build: https://github.com/storybookjs/storybook/issues/14621 npmLog.stream = process.stdout; diff --git a/code/core/src/types/modules/core-common.ts b/code/core/src/types/modules/core-common.ts index 3523f60f7f0c..b8f347124a4d 100644 --- a/code/core/src/types/modules/core-common.ts +++ b/code/core/src/types/modules/core-common.ts @@ -2,6 +2,7 @@ import type { FileSystemCache } from 'storybook/internal/common'; import { type StoryIndexGenerator } from 'storybook/internal/core-server'; import { type CsfFile } from 'storybook/internal/csf-tools'; +import type { LogLevel } from 'storybook/internal/node-logger'; import type { Server as HttpServer, IncomingMessage, ServerResponse } from 'http'; import type { Server as NetServer } from 'net'; @@ -173,7 +174,8 @@ export interface CLIBaseOptions { disableTelemetry?: boolean; enableCrashReports?: boolean; configDir?: string; - loglevel?: string; + loglevel?: LogLevel; + logfile?: string | boolean; quiet?: boolean; } diff --git a/code/frameworks/angular/build-schema.json b/code/frameworks/angular/build-schema.json index 9753db540f2d..d3963edc7215 100644 --- a/code/frameworks/angular/build-schema.json +++ b/code/frameworks/angular/build-schema.json @@ -32,7 +32,11 @@ "loglevel": { "type": "string", "description": "Controls level of logging during build. Can be one of: [silly, verbose, info (default), warn, error, silent].", - "pattern": "(silly|verbose|info|warn|silent)" + "pattern": "(trace|debug|info|warn|error|silent)" + }, + "logfile": { + "type": "string", + "description": "If provided, the log output will be written to the specified file path." }, "debugWebpack": { "type": "boolean", diff --git a/code/frameworks/angular/src/builders/build-storybook/index.ts b/code/frameworks/angular/src/builders/build-storybook/index.ts index 191f93a16e31..2f34d7bc3aba 100644 --- a/code/frameworks/angular/src/builders/build-storybook/index.ts +++ b/code/frameworks/angular/src/builders/build-storybook/index.ts @@ -4,7 +4,7 @@ import { getEnvConfig, getProjectRoot, versions } from 'storybook/internal/commo import { buildStaticStandalone, withTelemetry } from 'storybook/internal/core-server'; import { addToGlobalContext } from 'storybook/internal/telemetry'; import type { CLIOptions } from 'storybook/internal/types'; -import { logger } from 'storybook/internal/node-logger'; +import { logger, logTracker } from 'storybook/internal/node-logger'; import type { BuilderContext, @@ -60,6 +60,7 @@ export type StorybookBuilderOptions = JsonObject & { | 'statsJson' | 'disableTelemetry' | 'debugWebpack' + | 'logfile' | 'previewUrl' >; @@ -71,6 +72,14 @@ const commandBuilder: BuilderHandlerFn = async ( options, context ): Promise => { + // Apply logger configuration from builder options + if (options.loglevel) { + logger.setLogLevel(options.loglevel); + } + if (options.logfile) { + logTracker.enableLogWriting(); + } + logger.intro('Building Storybook'); const { tsConfig } = await setup(options, context); @@ -147,6 +156,10 @@ const commandBuilder: BuilderHandlerFn = async ( }; await runInstance({ ...standaloneOptions, mode: 'static' }); + if (logTracker.shouldWriteLogsToFile) { + const logFile = await logTracker.writeToFile(options.logfile as any); + logger.info(`Debug logs are written to: ${logFile}`); + } logger.outro('Storybook build completed successfully'); return { success: true } as BuilderOutput; }; diff --git a/code/frameworks/angular/src/builders/start-storybook/index.ts b/code/frameworks/angular/src/builders/start-storybook/index.ts index 9562ab66ba0c..977dd4cc717f 100644 --- a/code/frameworks/angular/src/builders/start-storybook/index.ts +++ b/code/frameworks/angular/src/builders/start-storybook/index.ts @@ -4,7 +4,7 @@ import { getEnvConfig, getProjectRoot, versions } from 'storybook/internal/commo import { buildDevStandalone, withTelemetry } from 'storybook/internal/core-server'; import { addToGlobalContext } from 'storybook/internal/telemetry'; import type { CLIOptions } from 'storybook/internal/types'; -import { logger } from 'storybook/internal/node-logger'; +import { logger, logTracker } from 'storybook/internal/node-logger'; import type { BuilderContext, @@ -65,6 +65,7 @@ export type StorybookBuilderOptions = JsonObject & { | 'open' | 'docs' | 'debugWebpack' + | 'logfile' | 'webpackStatsJson' | 'statsJson' | 'loglevel' @@ -80,6 +81,14 @@ const commandBuilder: BuilderHandlerFn = ( return new Observable((observer) => { (async () => { try { + // Apply logger configuration from builder options + if (options.loglevel) { + logger.setLogLevel(options.loglevel); + } + if (options.logfile) { + logTracker.enableLogWriting(); + } + logger.intro('Starting Storybook'); const { tsConfig } = await setup(options, context); @@ -187,6 +196,15 @@ const commandBuilder: BuilderHandlerFn = ( // so the dev server continues running. Architect will keep subscribing // until the Observable completes, which allows watch mode to work. } catch (error) { + // Write logs to file on failure when enabled + try { + if (logTracker.shouldWriteLogsToFile) { + try { + const logFile = await logTracker.writeToFile(options.logfile as any); + logger.outro(`Debug logs are written to: ${logFile}`); + } catch {} + } + } catch {} observer.error(error); } })(); diff --git a/code/frameworks/angular/start-schema.json b/code/frameworks/angular/start-schema.json index 84d6bd80861b..ac81c01d6ab0 100644 --- a/code/frameworks/angular/start-schema.json +++ b/code/frameworks/angular/start-schema.json @@ -148,7 +148,11 @@ "loglevel": { "type": "string", "description": "Controls level of logging during build. Can be one of: [silly, verbose, info (default), warn, error, silent].", - "pattern": "(silly|verbose|info|warn|silent)" + "pattern": "(trace|debug|info|warn|error|silent)" + }, + "logfile": { + "type": "string", + "description": "If provided, the log output will be written to the specified file path." }, "sourceMap": { "type": ["boolean", "object"], diff --git a/code/lib/cli-storybook/src/bin/run.ts b/code/lib/cli-storybook/src/bin/run.ts index f0cb4dc9591f..cab65aa2eedf 100644 --- a/code/lib/cli-storybook/src/bin/run.ts +++ b/code/lib/cli-storybook/src/bin/run.ts @@ -36,8 +36,10 @@ const handleCommandFailure = logger.error(String(error)); } - const logFile = await logTracker.writeToFile(logFilePath); - logger.log(`Debug logs are written to: ${logFile}`); + try { + const logFile = await logTracker.writeToFile(logFilePath); + logger.log(`Debug logs are written to: ${logFile}`); + } catch {} logger.outro(''); process.exit(1); }; @@ -79,8 +81,10 @@ const command = (name: string) => }) .hook('postAction', async (command) => { if (logTracker.shouldWriteLogsToFile) { - const logFile = await logTracker.writeToFile(command.getOptionValue('logfile')); - logger.log(`Debug logs are written to: ${logFile}`); + try { + const logFile = await logTracker.writeToFile(command.getOptionValue('logfile')); + logger.log(`Debug logs are written to: ${logFile}`); + } catch {} logger.outro(CLI_COLORS.success('Done!')); } }); diff --git a/code/lib/cli-storybook/src/upgrade.ts b/code/lib/cli-storybook/src/upgrade.ts index 74a9c5d4e404..914f96193620 100644 --- a/code/lib/cli-storybook/src/upgrade.ts +++ b/code/lib/cli-storybook/src/upgrade.ts @@ -7,6 +7,7 @@ import { logger, prompt, } from 'storybook/internal/node-logger'; +import type { LogLevel } from 'storybook/internal/node-logger'; import { UpgradeStorybookToLowerVersionError, UpgradeStorybookUnknownCurrentVersionError, @@ -123,6 +124,7 @@ export type UpgradeOptions = { configDir?: string[]; fixId?: string; skipInstall?: boolean; + loglevel?: LogLevel; logfile?: string | boolean; }; diff --git a/code/lib/create-storybook/src/bin/run.ts b/code/lib/create-storybook/src/bin/run.ts index 977ce2adbeba..322c6370987b 100644 --- a/code/lib/create-storybook/src/bin/run.ts +++ b/code/lib/create-storybook/src/bin/run.ts @@ -104,7 +104,9 @@ const createStorybookProgram = program }) .hook('postAction', async (command) => { if (logTracker.shouldWriteLogsToFile) { - await logTracker.writeToFile(command.getOptionValue('logfile')); + try { + await logTracker.writeToFile(command.getOptionValue('logfile')); + } catch {} } }); diff --git a/code/lib/create-storybook/src/commands/FinalizationCommand.ts b/code/lib/create-storybook/src/commands/FinalizationCommand.ts index 7d3f3aac832c..887851ada2f6 100644 --- a/code/lib/create-storybook/src/commands/FinalizationCommand.ts +++ b/code/lib/create-storybook/src/commands/FinalizationCommand.ts @@ -68,8 +68,10 @@ export class FinalizationCommand { ); this.printNextSteps(storybookCommand); - const logFile = await logTracker.writeToFile(this.logfile); - logger.warn(`Debug logs are written to: ${logFile}`); + try { + const logFile = await logTracker.writeToFile(this.logfile); + logger.warn(`Debug logs are written to: ${logFile}`); + } catch {} } /** Print success message with feature summary */