feat: standardize logging across UI components

- Replaced console.log and console.error statements with logger methods from @automaker/utils in various UI components, ensuring consistent log formatting and improved readability.
- Enhanced error handling by utilizing logger methods to provide clearer context for issues encountered during operations.
- Updated multiple views and hooks to integrate the new logging system, improving maintainability and debugging capabilities.

This update significantly enhances the observability of UI components, facilitating easier troubleshooting and monitoring.
This commit is contained in:
Shirone
2026-01-02 17:25:13 +01:00
parent 96a999817f
commit 69f3ba9724
86 changed files with 1079 additions and 677 deletions

View File

@@ -40,7 +40,15 @@ export {
} from './prompt-builder.js';
// Logger
export { createLogger, getLogLevel, setLogLevel, LogLevel } from './logger.js';
export {
createLogger,
getLogLevel,
setLogLevel,
setColorsEnabled,
setTimestampsEnabled,
LogLevel,
type Logger,
} from './logger.js';
// File system utilities
export { mkdirSafe, existsSafe } from './fs-utils.js';

View File

@@ -1,7 +1,10 @@
/**
* Simple logger utility with log levels
* Configure via LOG_LEVEL environment variable: error, warn, info, debug
* Defaults to 'info' if not set
* Enhanced logger with colors and timestamps
*
* Environment Variables:
* - LOG_LEVEL: error, warn, info, debug (default: info)
* - LOG_COLORS: true/false (default: auto-detect TTY)
* - LOG_TIMESTAMPS: true/false (default: false)
*/
export enum LogLevel {
@@ -18,42 +21,207 @@ const LOG_LEVEL_NAMES: Record<string, LogLevel> = {
debug: LogLevel.DEBUG,
};
// ANSI color codes for terminal output
const ANSI = {
reset: '\x1b[0m',
bold: '\x1b[1m',
dim: '\x1b[2m',
// Foreground colors
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m',
gray: '\x1b[90m',
};
// Browser CSS styles for console output
const BROWSER_STYLES = {
timestamp: 'color: #6b7280; font-size: 11px;',
context: 'color: #3b82f6; font-weight: 600;',
reset: 'color: inherit; font-weight: inherit;',
levels: {
ERROR:
'background: #ef4444; color: white; font-weight: bold; padding: 1px 6px; border-radius: 3px;',
WARN: 'background: #f59e0b; color: white; font-weight: bold; padding: 1px 6px; border-radius: 3px;',
INFO: 'background: #3b82f6; color: white; font-weight: bold; padding: 1px 6px; border-radius: 3px;',
DEBUG:
'background: #8b5cf6; color: white; font-weight: bold; padding: 1px 6px; border-radius: 3px;',
},
};
// Environment detection - use globalThis for cross-platform compatibility
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const isBrowser = typeof (globalThis as any).window !== 'undefined';
// Configuration state
let currentLogLevel: LogLevel = LogLevel.INFO;
// Detect if we're in a Node.js environment with TTY support
function isTTY(): boolean {
if (isBrowser) return false;
try {
return process?.stdout?.isTTY ?? false;
} catch {
return false;
}
}
// Get environment variable safely (works in both Node.js and browser)
function getEnvVar(name: string): string | undefined {
if (isBrowser) return undefined;
try {
return process?.env?.[name];
} catch {
return undefined;
}
}
// Initialize configuration from environment variables
let colorsEnabled = isTTY() && getEnvVar('LOG_COLORS') !== 'false';
let timestampsEnabled = getEnvVar('LOG_TIMESTAMPS') === 'true';
// Initialize log level from environment variable
const envLogLevel = process.env.LOG_LEVEL?.toLowerCase();
const envLogLevel = getEnvVar('LOG_LEVEL')?.toLowerCase();
if (envLogLevel && LOG_LEVEL_NAMES[envLogLevel] !== undefined) {
currentLogLevel = LOG_LEVEL_NAMES[envLogLevel];
}
/**
* Format ISO timestamp
*/
function formatTimestamp(): string {
return new Date().toISOString();
}
/**
* Format short time for browser (HH:mm:ss.SSS)
*/
function formatShortTime(): string {
return new Date().toISOString().split('T')[1].slice(0, 12);
}
/**
* Format a log line for Node.js terminal output
*/
function formatNodeLog(level: string, context: string, levelColor: string): string {
const parts: string[] = [];
if (timestampsEnabled) {
parts.push(colorsEnabled ? `${ANSI.gray}${formatTimestamp()}${ANSI.reset}` : formatTimestamp());
}
const levelPadded = level.padEnd(5);
parts.push(colorsEnabled ? `${levelColor}${levelPadded}${ANSI.reset}` : levelPadded);
parts.push(colorsEnabled ? `${ANSI.blue}[${context}]${ANSI.reset}` : `[${context}]`);
return parts.join(' ');
}
/**
* Logger interface returned by createLogger
*/
export interface Logger {
error: (...args: unknown[]) => void;
warn: (...args: unknown[]) => void;
info: (...args: unknown[]) => void;
debug: (...args: unknown[]) => void;
}
/**
* Create a logger instance with a context prefix
*/
export function createLogger(context: string) {
const prefix = `[${context}]`;
export function createLogger(context: string): Logger {
if (isBrowser) {
// Browser implementation with CSS styling
return {
error: (...args: unknown[]): void => {
if (currentLogLevel >= LogLevel.ERROR) {
console.error(
`%cERROR%c %c${formatShortTime()}%c %c[${context}]%c`,
BROWSER_STYLES.levels.ERROR,
BROWSER_STYLES.reset,
BROWSER_STYLES.timestamp,
BROWSER_STYLES.reset,
BROWSER_STYLES.context,
BROWSER_STYLES.reset,
...args
);
}
},
warn: (...args: unknown[]): void => {
if (currentLogLevel >= LogLevel.WARN) {
console.warn(
`%cWARN%c %c${formatShortTime()}%c %c[${context}]%c`,
BROWSER_STYLES.levels.WARN,
BROWSER_STYLES.reset,
BROWSER_STYLES.timestamp,
BROWSER_STYLES.reset,
BROWSER_STYLES.context,
BROWSER_STYLES.reset,
...args
);
}
},
info: (...args: unknown[]): void => {
if (currentLogLevel >= LogLevel.INFO) {
console.log(
`%cINFO%c %c${formatShortTime()}%c %c[${context}]%c`,
BROWSER_STYLES.levels.INFO,
BROWSER_STYLES.reset,
BROWSER_STYLES.timestamp,
BROWSER_STYLES.reset,
BROWSER_STYLES.context,
BROWSER_STYLES.reset,
...args
);
}
},
debug: (...args: unknown[]): void => {
if (currentLogLevel >= LogLevel.DEBUG) {
console.log(
`%cDEBUG%c %c${formatShortTime()}%c %c[${context}]%c`,
BROWSER_STYLES.levels.DEBUG,
BROWSER_STYLES.reset,
BROWSER_STYLES.timestamp,
BROWSER_STYLES.reset,
BROWSER_STYLES.context,
BROWSER_STYLES.reset,
...args
);
}
},
};
}
// Node.js implementation with ANSI colors
return {
error: (...args: unknown[]): void => {
if (currentLogLevel >= LogLevel.ERROR) {
console.error(prefix, ...args);
console.error(formatNodeLog('ERROR', context, ANSI.red), ...args);
}
},
warn: (...args: unknown[]): void => {
if (currentLogLevel >= LogLevel.WARN) {
console.warn(prefix, ...args);
console.warn(formatNodeLog('WARN', context, ANSI.yellow), ...args);
}
},
info: (...args: unknown[]): void => {
if (currentLogLevel >= LogLevel.INFO) {
console.log(prefix, ...args);
console.log(formatNodeLog('INFO', context, ANSI.cyan), ...args);
}
},
debug: (...args: unknown[]): void => {
if (currentLogLevel >= LogLevel.DEBUG) {
console.log(prefix, '[DEBUG]', ...args);
console.log(formatNodeLog('DEBUG', context, ANSI.magenta), ...args);
}
},
};
@@ -72,3 +240,17 @@ export function getLogLevel(): LogLevel {
export function setLogLevel(level: LogLevel): void {
currentLogLevel = level;
}
/**
* Enable or disable colored output
*/
export function setColorsEnabled(enabled: boolean): void {
colorsEnabled = enabled;
}
/**
* Enable or disable timestamps in output
*/
export function setTimestampsEnabled(enabled: boolean): void {
timestampsEnabled = enabled;
}