@mks2508/better-logger 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +13 -0
- package/CLAUDE.md +113 -0
- package/dist/assets/index-DxvJByYN.js +183 -0
- package/dist/index.html +334 -0
- package/dist/vite.svg +1 -0
- package/index.html +334 -0
- package/package.json +35 -0
- package/public/vite.svg +1 -0
- package/src/Logger.ts +577 -0
- package/src/Logger.ts.backup +1684 -0
- package/src/cli/CommandProcessor.ts +77 -0
- package/src/cli/commands/ConfigCommand.ts +93 -0
- package/src/cli/commands/ExportCommand.ts +271 -0
- package/src/cli/commands/StatusCommand.ts +111 -0
- package/src/cli/commands/ThemeCommand.ts +88 -0
- package/src/cli/help.ts +127 -0
- package/src/cli/index.ts +59 -0
- package/src/constants.ts +89 -0
- package/src/example.ts +88 -0
- package/src/handlers/AnalyticsLogHandler.ts +22 -0
- package/src/handlers/ExportLogHandler.ts +447 -0
- package/src/handlers/FileLogHandler.ts +30 -0
- package/src/handlers/RemoteLogHandler.ts +42 -0
- package/src/handlers/index.ts +8 -0
- package/src/index.ts +122 -0
- package/src/main.ts +126 -0
- package/src/style.css +96 -0
- package/src/styling/StyleBuilder.ts +305 -0
- package/src/styling/banners.ts +168 -0
- package/src/styling/index.ts +12 -0
- package/src/styling/themes.ts +235 -0
- package/src/types/core.ts +80 -0
- package/src/types/handlers.ts +95 -0
- package/src/types/index.ts +29 -0
- package/src/typescript.svg +1 -0
- package/src/utils/index.ts +18 -0
- package/src/utils/output.ts +127 -0
- package/src/utils/stackTrace.ts +66 -0
- package/src/utils/timestamps.ts +80 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +24 -0
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mks2508/better-logger",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "State-of-the-art console logger with advanced CSS styling, SVG support, animations, and CLI interface",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"logger",
|
|
10
|
+
"console",
|
|
11
|
+
"styling",
|
|
12
|
+
"css",
|
|
13
|
+
"svg",
|
|
14
|
+
"animation",
|
|
15
|
+
"typescript",
|
|
16
|
+
"browser",
|
|
17
|
+
"cli",
|
|
18
|
+
"debug"
|
|
19
|
+
],
|
|
20
|
+
"author": "MKS2508",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/MKS2508/advanced-logger.git"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"dev": "vite",
|
|
28
|
+
"build": "tsc && vite build",
|
|
29
|
+
"preview": "vite preview"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"typescript": "~5.8.3",
|
|
33
|
+
"vite": "^7.1.2"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/public/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/src/Logger.ts
ADDED
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Refactored Advanced Logger with modular architecture
|
|
3
|
+
* @version 2.0.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Type imports
|
|
7
|
+
import type {
|
|
8
|
+
LogLevel,
|
|
9
|
+
Verbosity,
|
|
10
|
+
ThemeVariant,
|
|
11
|
+
BannerType,
|
|
12
|
+
LoggerConfig,
|
|
13
|
+
TimerEntry,
|
|
14
|
+
ILogHandler,
|
|
15
|
+
LogMetadata,
|
|
16
|
+
StyleOptions
|
|
17
|
+
} from './types/index.js';
|
|
18
|
+
|
|
19
|
+
// Utility imports
|
|
20
|
+
import {
|
|
21
|
+
parseStackTrace,
|
|
22
|
+
formatTimestamp,
|
|
23
|
+
createStyledOutput
|
|
24
|
+
} from './utils/index.js';
|
|
25
|
+
|
|
26
|
+
// Styling imports
|
|
27
|
+
import {
|
|
28
|
+
THEME_PRESETS,
|
|
29
|
+
THEME_BANNERS,
|
|
30
|
+
displayInitBanner,
|
|
31
|
+
StylePresets,
|
|
32
|
+
StyleBuilder
|
|
33
|
+
} from './styling/index.js';
|
|
34
|
+
|
|
35
|
+
// Handler imports
|
|
36
|
+
import { ExportLogHandler } from './handlers/index.js';
|
|
37
|
+
|
|
38
|
+
// CLI imports
|
|
39
|
+
import { createDefaultCLI, type CommandProcessor } from './cli/index.js';
|
|
40
|
+
|
|
41
|
+
// Constants
|
|
42
|
+
import { DEFAULT_CONFIG } from './constants.js';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Current active theme styles
|
|
46
|
+
*/
|
|
47
|
+
let LEVEL_STYLES = THEME_PRESETS.default;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Main Logger class implementing state-of-the-art logging capabilities
|
|
51
|
+
*/
|
|
52
|
+
export class Logger {
|
|
53
|
+
private config: LoggerConfig;
|
|
54
|
+
private scopedPrefix?: string;
|
|
55
|
+
private handlers: ILogHandler[] = [];
|
|
56
|
+
private timers: Map<string, TimerEntry> = new Map();
|
|
57
|
+
private groupDepth: number = 0;
|
|
58
|
+
private exportHandler?: ExportLogHandler;
|
|
59
|
+
private cliProcessor?: CommandProcessor;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Creates a new Logger instance
|
|
63
|
+
*/
|
|
64
|
+
constructor(config: Partial<LoggerConfig> = {}) {
|
|
65
|
+
this.config = {
|
|
66
|
+
...DEFAULT_CONFIG,
|
|
67
|
+
...config,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Initialize export handler if buffer size is specified
|
|
71
|
+
if (this.config.bufferSize) {
|
|
72
|
+
this.exportHandler = new ExportLogHandler(this.config.bufferSize);
|
|
73
|
+
this.handlers.push(this.exportHandler);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Initialize CLI processor
|
|
77
|
+
this.cliProcessor = createDefaultCLI();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ===== CONFIGURATION METHODS =====
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get current configuration
|
|
84
|
+
*/
|
|
85
|
+
getConfig(): LoggerConfig {
|
|
86
|
+
return { ...this.config };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Update configuration
|
|
91
|
+
*/
|
|
92
|
+
updateConfig(updates: Partial<LoggerConfig>): void {
|
|
93
|
+
this.config = { ...this.config, ...updates };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Sets the global prefix for all log messages
|
|
98
|
+
*/
|
|
99
|
+
setGlobalPrefix(prefix: string): void {
|
|
100
|
+
this.config.globalPrefix = prefix;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Sets the verbosity level for filtering log output
|
|
105
|
+
*/
|
|
106
|
+
setVerbosity(level: Verbosity): void {
|
|
107
|
+
this.config.verbosity = level;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Sets the logger theme
|
|
112
|
+
*/
|
|
113
|
+
setTheme(theme: ThemeVariant): void {
|
|
114
|
+
if (theme in THEME_PRESETS) {
|
|
115
|
+
LEVEL_STYLES = (THEME_PRESETS as any)[theme];
|
|
116
|
+
this.config.theme = theme;
|
|
117
|
+
|
|
118
|
+
// Show theme-specific banner
|
|
119
|
+
if (theme in THEME_BANNERS) {
|
|
120
|
+
const themeBanner = (THEME_BANNERS as any)[theme];
|
|
121
|
+
console.log(`%c${themeBanner.simple}`, themeBanner.style);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.success(`Theme changed to: ${theme}`);
|
|
125
|
+
} else {
|
|
126
|
+
this.error(`Invalid theme: ${theme}. Available themes:`, Object.keys(THEME_PRESETS));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Set banner type for initialization display
|
|
132
|
+
*/
|
|
133
|
+
setBannerType(bannerType: BannerType): void {
|
|
134
|
+
this.config.bannerType = bannerType;
|
|
135
|
+
this.success(`Banner type changed to: ${bannerType}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Reset logger to default configuration
|
|
140
|
+
*/
|
|
141
|
+
resetConfig(): void {
|
|
142
|
+
this.config = { ...DEFAULT_CONFIG };
|
|
143
|
+
LEVEL_STYLES = THEME_PRESETS.default;
|
|
144
|
+
this.success('Logger configuration reset to defaults');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ===== SCOPED LOGGER =====
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Creates a scoped logger with a specific prefix
|
|
151
|
+
*/
|
|
152
|
+
createScopedLogger(prefix: string): Logger {
|
|
153
|
+
const scopedLogger = new Logger(this.config);
|
|
154
|
+
scopedLogger.scopedPrefix = prefix;
|
|
155
|
+
scopedLogger.handlers = [...this.handlers];
|
|
156
|
+
scopedLogger.exportHandler = this.exportHandler;
|
|
157
|
+
return scopedLogger;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ===== HANDLER MANAGEMENT =====
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Adds a custom log handler for extensibility
|
|
164
|
+
*/
|
|
165
|
+
addHandler(handler: ILogHandler): void {
|
|
166
|
+
this.handlers.push(handler);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Get all registered handlers
|
|
171
|
+
*/
|
|
172
|
+
getHandlers(): ILogHandler[] {
|
|
173
|
+
return [...this.handlers];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get export handler if available
|
|
178
|
+
*/
|
|
179
|
+
getExportHandler(): ExportLogHandler | undefined {
|
|
180
|
+
return this.exportHandler;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ===== CORE LOGGING METHODS =====
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Checks if a log level should be output based on current verbosity
|
|
187
|
+
*/
|
|
188
|
+
private shouldLog(level: LogLevel): boolean {
|
|
189
|
+
if (this.config.verbosity === 'silent') return false;
|
|
190
|
+
const levels = { debug: 0, info: 1, warn: 2, error: 3, critical: 4 };
|
|
191
|
+
return levels[level] >= levels[this.config.verbosity];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Gets the effective prefix (global + scoped)
|
|
196
|
+
*/
|
|
197
|
+
private getEffectivePrefix(): string | undefined {
|
|
198
|
+
const parts = [this.config.globalPrefix, this.scopedPrefix].filter(Boolean);
|
|
199
|
+
return parts.length > 0 ? parts.join(':') : undefined;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Core logging method that handles styling and formatting
|
|
204
|
+
*/
|
|
205
|
+
private log(level: LogLevel, ...args: any[]): void {
|
|
206
|
+
if (!this.shouldLog(level)) return;
|
|
207
|
+
|
|
208
|
+
const stackInfo = this.config.enableStackTrace ? parseStackTrace() : null;
|
|
209
|
+
const prefix = this.getEffectivePrefix();
|
|
210
|
+
const message = args.length > 0 ? String(args[0]) : '';
|
|
211
|
+
const additionalArgs = args.slice(1);
|
|
212
|
+
|
|
213
|
+
// Create styled output
|
|
214
|
+
const [format, ...styles] = createStyledOutput(level, LEVEL_STYLES, prefix, message, stackInfo);
|
|
215
|
+
|
|
216
|
+
// Add group indentation
|
|
217
|
+
const groupIndent = ' '.repeat(this.groupDepth);
|
|
218
|
+
const finalFormat = groupIndent + format;
|
|
219
|
+
|
|
220
|
+
// Output to console
|
|
221
|
+
if (additionalArgs.length > 0) {
|
|
222
|
+
console.log(finalFormat, ...styles, ...additionalArgs);
|
|
223
|
+
} else {
|
|
224
|
+
console.log(finalFormat, ...styles);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Update export handler group info
|
|
228
|
+
if (this.exportHandler) {
|
|
229
|
+
this.exportHandler.setGroupInfo(this.groupDepth);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Call custom handlers
|
|
233
|
+
const metadata: LogMetadata = {
|
|
234
|
+
timestamp: formatTimestamp(),
|
|
235
|
+
level,
|
|
236
|
+
prefix,
|
|
237
|
+
stackInfo: stackInfo || undefined,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
this.handlers.forEach(handler => {
|
|
241
|
+
try {
|
|
242
|
+
handler.handle(level, message, args, metadata);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.error('Log handler failed:', error);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Logs debug information (lowest priority)
|
|
251
|
+
*/
|
|
252
|
+
debug(...args: any[]): void {
|
|
253
|
+
this.log('debug', ...args);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Logs informational messages
|
|
258
|
+
*/
|
|
259
|
+
info(...args: any[]): void {
|
|
260
|
+
this.log('info', ...args);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Logs warning messages
|
|
265
|
+
*/
|
|
266
|
+
warn(...args: any[]): void {
|
|
267
|
+
this.log('warn', ...args);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Logs error messages
|
|
272
|
+
*/
|
|
273
|
+
error(...args: any[]): void {
|
|
274
|
+
this.log('error', ...args);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Logs success messages (special info level)
|
|
279
|
+
*/
|
|
280
|
+
success(...args: any[]): void {
|
|
281
|
+
if (!this.shouldLog('info')) return;
|
|
282
|
+
|
|
283
|
+
const stackInfo = this.config.enableStackTrace ? parseStackTrace() : null;
|
|
284
|
+
const prefix = this.getEffectivePrefix();
|
|
285
|
+
const message = args.length > 0 ? String(args[0]) : '';
|
|
286
|
+
const additionalArgs = args.slice(1);
|
|
287
|
+
|
|
288
|
+
// Handle success as special case - use info level with success styling
|
|
289
|
+
const [format, ...styles] = createStyledOutput('info', LEVEL_STYLES, prefix, message, stackInfo);
|
|
290
|
+
|
|
291
|
+
// Override with success styling
|
|
292
|
+
const successStyle = LEVEL_STYLES.success;
|
|
293
|
+
const successFormat = format.replace(/ℹ️ INFO/, `${successStyle.emoji} ${successStyle.label}`);
|
|
294
|
+
|
|
295
|
+
const groupIndent = ' '.repeat(this.groupDepth);
|
|
296
|
+
const finalFormat = groupIndent + successFormat;
|
|
297
|
+
|
|
298
|
+
if (additionalArgs.length > 0) {
|
|
299
|
+
console.log(finalFormat, ...styles, ...additionalArgs);
|
|
300
|
+
} else {
|
|
301
|
+
console.log(finalFormat, ...styles);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Call handlers
|
|
305
|
+
const metadata: LogMetadata = {
|
|
306
|
+
timestamp: formatTimestamp(),
|
|
307
|
+
level: 'info',
|
|
308
|
+
prefix,
|
|
309
|
+
stackInfo: stackInfo || undefined,
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
this.handlers.forEach(handler => {
|
|
313
|
+
try {
|
|
314
|
+
handler.handle('info', message, args, metadata);
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error('Log handler failed:', error);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Logs trace information (detailed debugging)
|
|
323
|
+
*/
|
|
324
|
+
trace(...args: any[]): void {
|
|
325
|
+
this.log('debug', ...args);
|
|
326
|
+
if (this.shouldLog('debug')) {
|
|
327
|
+
console.trace(...args);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Logs critical errors (highest priority)
|
|
333
|
+
*/
|
|
334
|
+
critical(...args: any[]): void {
|
|
335
|
+
this.log('critical', ...args);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// ===== ADVANCED LOGGING FEATURES =====
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Displays data in a table format
|
|
342
|
+
*/
|
|
343
|
+
table(data: any, columns?: string[]): void {
|
|
344
|
+
if (!this.shouldLog('info')) return;
|
|
345
|
+
|
|
346
|
+
const prefix = this.getEffectivePrefix();
|
|
347
|
+
const tableStyle = StylePresets.accent().build();
|
|
348
|
+
|
|
349
|
+
const format = `%c📊 TABLE${prefix ? ` [${prefix}]` : ''}`;
|
|
350
|
+
console.log(format, tableStyle);
|
|
351
|
+
|
|
352
|
+
if (columns) {
|
|
353
|
+
console.table(data, columns);
|
|
354
|
+
} else {
|
|
355
|
+
console.table(data);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Starts a collapsible group in the console
|
|
361
|
+
*/
|
|
362
|
+
group(label: string, collapsed: boolean = false): void {
|
|
363
|
+
const groupStyle = new StyleBuilder()
|
|
364
|
+
.bg('linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%)')
|
|
365
|
+
.color('#1565c0')
|
|
366
|
+
.border('1px solid #90caf9')
|
|
367
|
+
.padding('4px 12px')
|
|
368
|
+
.rounded('6px')
|
|
369
|
+
.bold()
|
|
370
|
+
.build();
|
|
371
|
+
|
|
372
|
+
const format = `%c📁 ${label}`;
|
|
373
|
+
|
|
374
|
+
if (collapsed) {
|
|
375
|
+
console.groupCollapsed(format, groupStyle);
|
|
376
|
+
} else {
|
|
377
|
+
console.group(format, groupStyle);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
this.groupDepth++;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Ends the current console group
|
|
385
|
+
*/
|
|
386
|
+
groupEnd(): void {
|
|
387
|
+
if (this.groupDepth > 0) {
|
|
388
|
+
console.groupEnd();
|
|
389
|
+
this.groupDepth--;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// ===== PERFORMANCE TIMING =====
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Starts a timer with the given label
|
|
397
|
+
*/
|
|
398
|
+
time(label: string): void {
|
|
399
|
+
const timer: TimerEntry = {
|
|
400
|
+
label,
|
|
401
|
+
startTime: performance.now(),
|
|
402
|
+
};
|
|
403
|
+
this.timers.set(label, timer);
|
|
404
|
+
|
|
405
|
+
const timerStyle = StylePresets.warning().build();
|
|
406
|
+
console.log(`%c⏱️ Timer started: ${label}`, timerStyle);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Ends a timer and logs the elapsed time
|
|
411
|
+
*/
|
|
412
|
+
timeEnd(label: string): void {
|
|
413
|
+
const timer = this.timers.get(label);
|
|
414
|
+
if (!timer) {
|
|
415
|
+
this.warn(`Timer '${label}' does not exist`);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const elapsed = performance.now() - timer.startTime;
|
|
420
|
+
this.timers.delete(label);
|
|
421
|
+
|
|
422
|
+
const timerStyle = StylePresets.success().build();
|
|
423
|
+
console.log(`%c⏱️ Timer ended: ${label} - ${elapsed.toFixed(2)}ms`, timerStyle);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// ===== ADVANCED VISUAL FEATURES =====
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Display banner with specified or configured type
|
|
430
|
+
*/
|
|
431
|
+
showBanner(bannerType?: BannerType): void {
|
|
432
|
+
displayInitBanner(bannerType || this.config.bannerType);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Log with SVG background image
|
|
437
|
+
*/
|
|
438
|
+
logWithSVG(message: string, svgContent?: string, options: StyleOptions = {}): void {
|
|
439
|
+
const { width = 300, height = 60, padding = '30px 150px' } = options;
|
|
440
|
+
|
|
441
|
+
let svgDataUri = '';
|
|
442
|
+
if (svgContent) {
|
|
443
|
+
const encodedSVG = encodeURIComponent(svgContent);
|
|
444
|
+
svgDataUri = `data:image/svg+xml,${encodedSVG}`;
|
|
445
|
+
} else {
|
|
446
|
+
const defaultSVG = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${width} ${height}'><defs><linearGradient id='grad' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:%23667eea'/><stop offset='100%' style='stop-color:%23764ba2'/></linearGradient></defs><rect width='100%' height='100%' fill='url(%23grad)' rx='4'/><text x='${width/2}' y='${height/2 + 5}' text-anchor='middle' fill='white' font-family='monospace' font-size='14' font-weight='bold'>${message}</text></svg>`;
|
|
447
|
+
svgDataUri = `data:image/svg+xml,${encodeURIComponent(defaultSVG)}`;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const svgStyle = new StyleBuilder()
|
|
451
|
+
.bg(`url("${svgDataUri}") no-repeat center center`)
|
|
452
|
+
.padding(padding)
|
|
453
|
+
.color('transparent')
|
|
454
|
+
.rounded('4px')
|
|
455
|
+
.build();
|
|
456
|
+
|
|
457
|
+
console.log(`%c${message}`, svgStyle);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Log with animated background gradient
|
|
462
|
+
*/
|
|
463
|
+
logAnimated(message: string, duration: number = 3): void {
|
|
464
|
+
// Inject CSS animation if not already present
|
|
465
|
+
if (!document.getElementById('logger-animations')) {
|
|
466
|
+
const style = document.createElement('style');
|
|
467
|
+
style.id = 'logger-animations';
|
|
468
|
+
style.textContent = `
|
|
469
|
+
@keyframes loggerGradient {
|
|
470
|
+
0% { background-position: 0% 50%; }
|
|
471
|
+
50% { background-position: 100% 50%; }
|
|
472
|
+
100% { background-position: 0% 50%; }
|
|
473
|
+
}
|
|
474
|
+
`;
|
|
475
|
+
document.head.appendChild(style);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const animatedStyle = new StyleBuilder()
|
|
479
|
+
.bg('linear-gradient(-45deg, #667eea, #764ba2, #667eea, #764ba2)')
|
|
480
|
+
.css('background-size', '400% 400%')
|
|
481
|
+
.color('#ffffff')
|
|
482
|
+
.padding('12px 20px')
|
|
483
|
+
.rounded('8px')
|
|
484
|
+
.bold()
|
|
485
|
+
.font('Monaco, Consolas, monospace')
|
|
486
|
+
.animation(`loggerGradient ${duration}s ease infinite`)
|
|
487
|
+
.display('inline-block')
|
|
488
|
+
.build();
|
|
489
|
+
|
|
490
|
+
console.log(`%c${message}`, animatedStyle);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Groups logs by a specific property using modern Object.groupBy (when available)
|
|
495
|
+
*/
|
|
496
|
+
logGrouped<T>(items: T[], groupBy: (item: T) => string): void {
|
|
497
|
+
try {
|
|
498
|
+
// Use Object.groupBy if available (ES2024)
|
|
499
|
+
const grouped = (Object as any).groupBy?.(items, groupBy) ||
|
|
500
|
+
items.reduce((acc, item) => {
|
|
501
|
+
const key = groupBy(item);
|
|
502
|
+
if (!acc[key]) acc[key] = [];
|
|
503
|
+
acc[key].push(item);
|
|
504
|
+
return acc;
|
|
505
|
+
}, {} as Record<string, T[]>);
|
|
506
|
+
|
|
507
|
+
Object.entries(grouped).forEach(([group, groupItems]) => {
|
|
508
|
+
this.group(`Group: ${group}`);
|
|
509
|
+
this.table(groupItems);
|
|
510
|
+
this.groupEnd();
|
|
511
|
+
});
|
|
512
|
+
} catch {
|
|
513
|
+
this.info('Grouped data:', items);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// ===== CLI SYSTEM =====
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* CLI command processor for logger configuration and export
|
|
521
|
+
*/
|
|
522
|
+
async cli(command: string): Promise<void> {
|
|
523
|
+
if (!this.cliProcessor) {
|
|
524
|
+
this.error('CLI processor not initialized');
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
await this.cliProcessor.processCommand(command, this);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Create and export the singleton instance
|
|
533
|
+
const defaultLogger = new Logger({
|
|
534
|
+
verbosity: 'info',
|
|
535
|
+
enableColors: true,
|
|
536
|
+
enableTimestamps: true,
|
|
537
|
+
enableStackTrace: true,
|
|
538
|
+
bufferSize: 1000, // Enable export functionality by default
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
// Display initialization banner
|
|
542
|
+
displayInitBanner();
|
|
543
|
+
|
|
544
|
+
// Export the singleton instance as default
|
|
545
|
+
export default defaultLogger;
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Export individual methods for convenience (with proper binding)
|
|
549
|
+
*/
|
|
550
|
+
export const debug = (...args: any[]) => defaultLogger.debug(...args);
|
|
551
|
+
export const info = (...args: any[]) => defaultLogger.info(...args);
|
|
552
|
+
export const warn = (...args: any[]) => defaultLogger.warn(...args);
|
|
553
|
+
export const error = (...args: any[]) => defaultLogger.error(...args);
|
|
554
|
+
export const success = (...args: any[]) => defaultLogger.success(...args);
|
|
555
|
+
export const trace = (...args: any[]) => defaultLogger.trace(...args);
|
|
556
|
+
export const critical = (...args: any[]) => defaultLogger.critical(...args);
|
|
557
|
+
export const table = (data: any, columns?: string[]) => defaultLogger.table(data, columns);
|
|
558
|
+
export const group = (label: string, collapsed?: boolean) => defaultLogger.group(label, collapsed);
|
|
559
|
+
export const groupEnd = () => defaultLogger.groupEnd();
|
|
560
|
+
export const time = (label: string) => defaultLogger.time(label);
|
|
561
|
+
export const timeEnd = (label: string) => defaultLogger.timeEnd(label);
|
|
562
|
+
export const setGlobalPrefix = (prefix: string) => defaultLogger.setGlobalPrefix(prefix);
|
|
563
|
+
export const createScopedLogger = (prefix: string) => defaultLogger.createScopedLogger(prefix);
|
|
564
|
+
export const setVerbosity = (level: Verbosity) => defaultLogger.setVerbosity(level);
|
|
565
|
+
export const addHandler = (handler: ILogHandler) => defaultLogger.addHandler(handler);
|
|
566
|
+
export const setTheme = (theme: ThemeVariant) => defaultLogger.setTheme(theme);
|
|
567
|
+
export const setBannerType = (bannerType: BannerType) => defaultLogger.setBannerType(bannerType);
|
|
568
|
+
export const showBanner = (bannerType?: BannerType) => defaultLogger.showBanner(bannerType);
|
|
569
|
+
export const logWithSVG = (message: string, svgContent?: string, options?: StyleOptions) =>
|
|
570
|
+
defaultLogger.logWithSVG(message, svgContent, options);
|
|
571
|
+
export const logAnimated = (message: string, duration?: number) =>
|
|
572
|
+
defaultLogger.logAnimated(message, duration);
|
|
573
|
+
export const cli = (command: string) => defaultLogger.cli(command);
|
|
574
|
+
|
|
575
|
+
// Re-export handlers and utilities for backward compatibility
|
|
576
|
+
export { FileLogHandler, RemoteLogHandler, AnalyticsLogHandler, ExportLogHandler } from './handlers/index.js';
|
|
577
|
+
export { StyleBuilder, StylePresets as Styles } from './styling/index.js';
|