@crimsonsunset/jsg-logger 1.0.10 → 1.1.0
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/docs/next-session.md +31 -17
- package/docs/roadmap.md +149 -3
- package/index.js +142 -1
- package/package.json +1 -1
package/docs/next-session.md
CHANGED
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
**Date:** August
|
|
18
|
-
**Session Goal:**
|
|
19
|
-
**
|
|
17
|
+
**Date:** August 21, 2025
|
|
18
|
+
**Session Goal:** 🚀 **API Enhancement - Phase 8** - Eliminate boilerplate code for projects using JSG Logger
|
|
19
|
+
**Status:** 🔄 **IN PROGRESS** - Core enhancements implemented, testing & publishing remain
|
|
20
20
|
|
|
21
21
|
## 🎉 MAJOR ACCOMPLISHMENTS THIS SESSION
|
|
22
22
|
|
|
@@ -61,21 +61,35 @@
|
|
|
61
61
|
- **Clean Integration** - DeskThing-Apps migration successful
|
|
62
62
|
- **Documentation Complete** - All standard files in place
|
|
63
63
|
|
|
64
|
-
## 📋 CURRENT PRIORITIES
|
|
65
|
-
|
|
66
|
-
###
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- [
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
64
|
+
## 📋 CURRENT PRIORITIES - PHASE 8 API ENHANCEMENT
|
|
65
|
+
|
|
66
|
+
### **🎯 Primary Goal: Eliminate Project Boilerplate** 🔄 IN PROGRESS
|
|
67
|
+
**Problem**: Projects need ~220 lines of boilerplate code to use JSG Logger effectively
|
|
68
|
+
**Solution**: Build essential patterns directly into the JSG Logger package
|
|
69
|
+
|
|
70
|
+
### **✅ COMPLETED THIS SESSION:**
|
|
71
|
+
- [x] **Static Singleton Pattern** - `CACPLogger.getInstance()` methods
|
|
72
|
+
- [x] **Auto-Discovery Getters** - Both camelCase and kebab-case component access
|
|
73
|
+
- [x] **Non-Destructive Error Handling** - Missing components log but don't break
|
|
74
|
+
- [x] **Static Performance Logging** - `CACPLogger.logPerformance()` utility
|
|
75
|
+
- [x] **Enhanced Export Structure** - Components and getComponent available
|
|
76
|
+
|
|
77
|
+
### **🔄 REMAINING TASKS:**
|
|
78
|
+
- [ ] **Complete Export Structure** - Ensure static methods accessible
|
|
79
|
+
- [ ] **Version Bump** - Update to 1.1.0 (minor for new features)
|
|
80
|
+
- [ ] **NPM Publish** - Deploy enhanced package
|
|
81
|
+
- [ ] **Test Integration** - Validate simplified project usage
|
|
82
|
+
- [ ] **Update README** - Document new API patterns
|
|
83
|
+
|
|
84
|
+
### **📊 Expected Impact:**
|
|
85
|
+
- **Project boilerplate**: 220 lines → 15 lines (93% reduction)
|
|
86
|
+
- **Initialization**: Complex setup → Single `getInstance()` call
|
|
87
|
+
- **Component access**: Manual mapping → Auto-discovery with both naming conventions
|
|
88
|
+
- **Performance logging**: Custom utilities → Built-in static method
|
|
89
|
+
|
|
90
|
+
### **🚀 Next Steps After Completion:**
|
|
91
|
+
- [ ] **DevTools Panel** - Browser-based log filtering interface (Phase 6)
|
|
77
92
|
- [ ] **Performance Monitoring** - Track logging overhead metrics
|
|
78
|
-
- [ ] **Export Utilities** - Save logs to file formats
|
|
79
93
|
- [ ] **Framework Integration Guides** - React, Vue, Svelte examples
|
|
80
94
|
|
|
81
95
|
## 🔧 Technical Notes
|
package/docs/roadmap.md
CHANGED
|
@@ -390,10 +390,156 @@ Console filtering updates
|
|
|
390
390
|
|
|
391
391
|
## 🎯 Next Steps
|
|
392
392
|
|
|
393
|
-
### **
|
|
394
|
-
|
|
393
|
+
### **Phase 8: API Enhancement for Project Simplification** 🚀 IN PROGRESS
|
|
394
|
+
**Goal**: Eliminate boilerplate code that every project needs to implement when using JSG Logger
|
|
395
395
|
|
|
396
|
-
|
|
396
|
+
#### **Background - The Problem**
|
|
397
|
+
Projects using JSG Logger currently need to implement ~220 lines of boilerplate:
|
|
398
|
+
- Singleton/caching patterns
|
|
399
|
+
- Component logger getters with fallback handling
|
|
400
|
+
- Performance logging utilities
|
|
401
|
+
- Auto-discovery of available components
|
|
402
|
+
- Error handling when components don't exist
|
|
403
|
+
|
|
404
|
+
**This defeats the purpose of having a reusable logger package.**
|
|
405
|
+
|
|
406
|
+
#### **Solution - Built-in Enhancement Features**
|
|
407
|
+
|
|
408
|
+
**✅ Design Decisions Made:**
|
|
409
|
+
1. **getInstance location**: Static on CACPLogger class
|
|
410
|
+
2. **Auto-discovery naming**: Both camelCase and kebab-case support
|
|
411
|
+
3. **Performance logging**: Static utility `JSGLogger.logPerformance(...)`
|
|
412
|
+
4. **Error handling**: Non-destructive with helpful logging (no fallbacks)
|
|
413
|
+
5. **Config auto-discovery**: Strict mode - only configured components work
|
|
414
|
+
6. **Getter creation**: Eagerly during init (not lazy)
|
|
415
|
+
|
|
416
|
+
#### **🔧 Implementation Plan**
|
|
417
|
+
|
|
418
|
+
##### **Enhancement 1: Static Singleton Pattern**
|
|
419
|
+
```javascript
|
|
420
|
+
// Static method on CACPLogger class
|
|
421
|
+
const logger = CACPLogger.getInstance(config);
|
|
422
|
+
const logger2 = CACPLogger.getInstance(); // Same instance, no config needed
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
**Implementation Location**: `index.js` CACPLogger class
|
|
426
|
+
- Add `static _instance = null`
|
|
427
|
+
- Add `static async getInstance(options = {})`
|
|
428
|
+
- Add `static getInstanceSync(options = {})` for sync environments
|
|
429
|
+
|
|
430
|
+
##### **Enhancement 2: Auto-Discovery Component Getters**
|
|
431
|
+
```javascript
|
|
432
|
+
// From config: { "components": { "astro-build": {}, "react-components": {} }}
|
|
433
|
+
|
|
434
|
+
// Both naming conventions work:
|
|
435
|
+
logger.components.astroBuild() // camelCase convenience
|
|
436
|
+
logger.components['astro-build']() // original kebab-case
|
|
437
|
+
logger.components.reactComponents() // camelCase
|
|
438
|
+
logger.components['react-components']() // kebab-case
|
|
439
|
+
|
|
440
|
+
// Plus explicit method
|
|
441
|
+
logger.getComponent('astro-build')
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
**Implementation**:
|
|
445
|
+
- Add `this.components = {}` to constructor
|
|
446
|
+
- Add `_createAutoDiscoveryGetters()` method - called eagerly during init
|
|
447
|
+
- Create getters for both kebab-case and camelCase from config components
|
|
448
|
+
- Add to `getLoggerExports()` return object
|
|
449
|
+
|
|
450
|
+
##### **Enhancement 3: Non-Destructive Component Access**
|
|
451
|
+
```javascript
|
|
452
|
+
// If 'missing-component' not in config:
|
|
453
|
+
const missingLogger = logger.getComponent('missing-component');
|
|
454
|
+
// Logs: "Component 'missing-component' not found. Available: astro-build, react-components"
|
|
455
|
+
// Returns: Logger that outputs error context but doesn't break
|
|
456
|
+
|
|
457
|
+
missingLogger.info('test');
|
|
458
|
+
// Outputs: "[MISSING-COMPONENT] ⚠️ Component not configured - test"
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
**Implementation**:
|
|
462
|
+
- Add `getComponent(componentName)` method
|
|
463
|
+
- Add `_createErrorLogger(componentName)` helper
|
|
464
|
+
- Error prefix: `[COMPONENT-NAME] ⚠️ Component not configured -`
|
|
465
|
+
- Strict mode: Only configured components, log missing ones
|
|
466
|
+
|
|
467
|
+
##### **Enhancement 4: Static Performance Logging**
|
|
468
|
+
```javascript
|
|
469
|
+
const startTime = performance.now();
|
|
470
|
+
// ... do work ...
|
|
471
|
+
JSGLogger.logPerformance('Page Generation', startTime, 'astro-build');
|
|
472
|
+
// Auto-thresholds: >1000ms = warn, >100ms = info, else = debug
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
**Implementation**:
|
|
476
|
+
- Add `static async logPerformance(operation, startTime, component = 'performance')`
|
|
477
|
+
- Auto-getInstance() - no manual initialization required
|
|
478
|
+
- Built-in performance thresholds and formatting
|
|
479
|
+
- Fallback to console if logger fails
|
|
480
|
+
|
|
481
|
+
#### **🎯 Result - Dramatically Simplified Project Usage**
|
|
482
|
+
|
|
483
|
+
**Before Enhancement** (220+ lines of boilerplate):
|
|
484
|
+
```typescript
|
|
485
|
+
// Complex singleton pattern, fallback handling, component getters, etc.
|
|
486
|
+
let loggerInstance: any = null;
|
|
487
|
+
// ... 200+ lines of infrastructure code ...
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
**After Enhancement** (15-20 lines):
|
|
491
|
+
```typescript
|
|
492
|
+
import JSGLogger from '@crimsonsunset/jsg-logger';
|
|
493
|
+
|
|
494
|
+
const logger = JSGLogger.getInstance({
|
|
495
|
+
configPath: './logger-config.json'
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// Optional project-specific convenience exports
|
|
499
|
+
export const loggers = {
|
|
500
|
+
build: logger.components.astroBuild,
|
|
501
|
+
react: logger.components.reactComponents,
|
|
502
|
+
textUtils: logger.components.textUtils
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
export { logger, JSGLogger };
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
#### **📋 Implementation Checklist**
|
|
509
|
+
|
|
510
|
+
**✅ COMPLETED:**
|
|
511
|
+
- [x] Added static `_instance` property and `getInstance()` methods
|
|
512
|
+
- [x] Added `_createAutoDiscoveryGetters()` calls to init/initSync
|
|
513
|
+
- [x] Implemented `_createAutoDiscoveryGetters()` with both naming conventions
|
|
514
|
+
- [x] Implemented `getComponent()` with non-destructive error handling
|
|
515
|
+
- [x] Implemented `_createErrorLogger()` with proper error messaging
|
|
516
|
+
- [x] Added static `logPerformance()` with auto-getInstance
|
|
517
|
+
- [x] Updated `getLoggerExports()` to include components and getComponent
|
|
518
|
+
|
|
519
|
+
**🔄 IN PROGRESS:**
|
|
520
|
+
- [ ] Complete export structure for static methods
|
|
521
|
+
- [ ] Version bump and publish to NPM
|
|
522
|
+
- [ ] Test new API with simplified project integration
|
|
523
|
+
- [ ] Update project files to use new simplified API
|
|
524
|
+
|
|
525
|
+
**📊 Expected Outcome:**
|
|
526
|
+
- **Project boilerplate reduced**: 220 lines → 15 lines (93% reduction)
|
|
527
|
+
- **API simplification**: Single `getInstance()` call vs complex initialization
|
|
528
|
+
- **Auto-discovery**: No manual component mapping required
|
|
529
|
+
- **Non-destructive errors**: Missing components log but don't break apps
|
|
530
|
+
- **Built-in utilities**: Performance logging included
|
|
531
|
+
|
|
532
|
+
#### **🚀 Next Implementation Steps**
|
|
533
|
+
1. Complete JSG Logger package enhancements
|
|
534
|
+
2. Bump version to 1.1.0 (minor version for new features)
|
|
535
|
+
3. Publish updated package to NPM
|
|
536
|
+
4. Update jsg-tech-check-site to use simplified API
|
|
537
|
+
5. Test and validate 93% boilerplate reduction
|
|
538
|
+
6. Document new API in README examples
|
|
539
|
+
|
|
540
|
+
---
|
|
541
|
+
|
|
542
|
+
### **Previous Optional Enhancements** (Lower Priority)
|
|
397
543
|
- **DevTools Panel** - Browser interface for log filtering
|
|
398
544
|
- **Performance Monitoring** - Track logging overhead
|
|
399
545
|
- **Framework Guides** - React, Vue, Svelte integration examples
|
package/index.js
CHANGED
|
@@ -18,11 +18,41 @@ import {LogStore} from './stores/log-store.js';
|
|
|
18
18
|
* Manages logger instances and provides the public API
|
|
19
19
|
*/
|
|
20
20
|
class CACPLogger {
|
|
21
|
+
// Static singleton instance
|
|
22
|
+
static _instance = null;
|
|
23
|
+
|
|
21
24
|
constructor() {
|
|
22
25
|
this.loggers = {};
|
|
23
26
|
this.logStore = new LogStore();
|
|
24
27
|
this.environment = getEnvironment();
|
|
25
28
|
this.initialized = false;
|
|
29
|
+
this.components = {}; // Auto-discovery getters
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get singleton instance with auto-initialization
|
|
34
|
+
* @param {Object} options - Initialization options (only used on first call)
|
|
35
|
+
* @returns {Promise<CACPLogger>} Singleton logger instance
|
|
36
|
+
*/
|
|
37
|
+
static async getInstance(options = {}) {
|
|
38
|
+
if (!CACPLogger._instance) {
|
|
39
|
+
CACPLogger._instance = new CACPLogger();
|
|
40
|
+
await CACPLogger._instance.init(options);
|
|
41
|
+
}
|
|
42
|
+
return CACPLogger._instance;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get singleton instance synchronously (for environments without async support)
|
|
47
|
+
* @param {Object} options - Initialization options (only used on first call)
|
|
48
|
+
* @returns {CACPLogger} Singleton logger instance
|
|
49
|
+
*/
|
|
50
|
+
static getInstanceSync(options = {}) {
|
|
51
|
+
if (!CACPLogger._instance) {
|
|
52
|
+
CACPLogger._instance = new CACPLogger();
|
|
53
|
+
CACPLogger._instance.initSync(options);
|
|
54
|
+
}
|
|
55
|
+
return CACPLogger._instance;
|
|
26
56
|
}
|
|
27
57
|
|
|
28
58
|
/**
|
|
@@ -50,6 +80,9 @@ class CACPLogger {
|
|
|
50
80
|
// Add utility methods
|
|
51
81
|
this.addUtilityMethods();
|
|
52
82
|
|
|
83
|
+
// Create auto-discovery getters (eager)
|
|
84
|
+
this._createAutoDiscoveryGetters();
|
|
85
|
+
|
|
53
86
|
this.initialized = true;
|
|
54
87
|
|
|
55
88
|
// Log initialization success
|
|
@@ -90,6 +123,9 @@ class CACPLogger {
|
|
|
90
123
|
// Add utility methods
|
|
91
124
|
this.addUtilityMethods();
|
|
92
125
|
|
|
126
|
+
// Create auto-discovery getters (eager)
|
|
127
|
+
this._createAutoDiscoveryGetters();
|
|
128
|
+
|
|
93
129
|
this.initialized = true;
|
|
94
130
|
|
|
95
131
|
// Log initialization success
|
|
@@ -181,6 +217,12 @@ class CACPLogger {
|
|
|
181
217
|
// All component loggers
|
|
182
218
|
...this.loggers,
|
|
183
219
|
|
|
220
|
+
// Auto-discovery convenience getters (kebab-case and camelCase)
|
|
221
|
+
components: this.components,
|
|
222
|
+
|
|
223
|
+
// Component getter with error handling
|
|
224
|
+
getComponent: (componentName) => this.getComponent(componentName),
|
|
225
|
+
|
|
184
226
|
// Utility methods
|
|
185
227
|
createLogger: (componentName) => {
|
|
186
228
|
if (!this.loggers[componentName]) {
|
|
@@ -400,6 +442,99 @@ class CACPLogger {
|
|
|
400
442
|
}
|
|
401
443
|
};
|
|
402
444
|
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Create auto-discovery getters for easy component access
|
|
448
|
+
* Supports both kebab-case (original) and camelCase naming
|
|
449
|
+
* @private
|
|
450
|
+
*/
|
|
451
|
+
_createAutoDiscoveryGetters() {
|
|
452
|
+
this.components = {};
|
|
453
|
+
|
|
454
|
+
Object.keys(this.loggers).forEach(name => {
|
|
455
|
+
// Original kebab-case name
|
|
456
|
+
this.components[name] = () => this.getComponent(name);
|
|
457
|
+
|
|
458
|
+
// camelCase convenience getter
|
|
459
|
+
const camelName = name.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
|
|
460
|
+
if (camelName !== name) {
|
|
461
|
+
this.components[camelName] = () => this.getComponent(name);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Get a specific component logger with non-destructive error handling
|
|
468
|
+
* @param {string} componentName - Component name to retrieve
|
|
469
|
+
* @returns {Object} Logger instance or error-context logger
|
|
470
|
+
*/
|
|
471
|
+
getComponent(componentName) {
|
|
472
|
+
if (!this.loggers[componentName]) {
|
|
473
|
+
const available = Object.keys(this.loggers).join(', ');
|
|
474
|
+
|
|
475
|
+
// Log the error using the config logger if available
|
|
476
|
+
if (this.loggers.config) {
|
|
477
|
+
this.loggers.config.warn(`Component '${componentName}' not found. Available: ${available}`);
|
|
478
|
+
} else {
|
|
479
|
+
console.warn(`[JSG-LOGGER] Component '${componentName}' not found. Available: ${available}`);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Return non-destructive error logger
|
|
483
|
+
return this._createErrorLogger(componentName);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return this.loggers[componentName];
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Create error-context logger that doesn't break the app
|
|
491
|
+
* @param {string} componentName - Name of the missing component
|
|
492
|
+
* @returns {Object} Logger with error context in all messages
|
|
493
|
+
* @private
|
|
494
|
+
*/
|
|
495
|
+
_createErrorLogger(componentName) {
|
|
496
|
+
const prefix = `[${componentName.toUpperCase()}]`;
|
|
497
|
+
const errorMsg = '⚠️ Component not configured -';
|
|
498
|
+
|
|
499
|
+
return {
|
|
500
|
+
trace: (msg, ...args) => console.log(`${prefix} ${errorMsg}`, msg, ...args),
|
|
501
|
+
debug: (msg, ...args) => console.log(`${prefix} ${errorMsg}`, msg, ...args),
|
|
502
|
+
info: (msg, ...args) => console.info(`${prefix} ${errorMsg}`, msg, ...args),
|
|
503
|
+
warn: (msg, ...args) => console.warn(`${prefix} ${errorMsg}`, msg, ...args),
|
|
504
|
+
error: (msg, ...args) => console.error(`${prefix} ${errorMsg}`, msg, ...args),
|
|
505
|
+
fatal: (msg, ...args) => console.error(`${prefix} ${errorMsg}`, msg, ...args)
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Static utility for performance logging with auto-getInstance
|
|
511
|
+
* @param {string} operation - Description of the operation being measured
|
|
512
|
+
* @param {number} startTime - Start time from performance.now()
|
|
513
|
+
* @param {string} component - Component name for logging (defaults to 'performance')
|
|
514
|
+
* @returns {number} Duration in milliseconds
|
|
515
|
+
*/
|
|
516
|
+
static async logPerformance(operation, startTime, component = 'performance') {
|
|
517
|
+
try {
|
|
518
|
+
const instance = await CACPLogger.getInstance();
|
|
519
|
+
const logger = instance.getComponent(component);
|
|
520
|
+
const duration = performance.now() - startTime;
|
|
521
|
+
|
|
522
|
+
if (duration > 1000) {
|
|
523
|
+
logger.warn(`${operation} took ${duration.toFixed(2)}ms (slow)`);
|
|
524
|
+
} else if (duration > 100) {
|
|
525
|
+
logger.info(`${operation} took ${duration.toFixed(2)}ms`);
|
|
526
|
+
} else {
|
|
527
|
+
logger.debug(`${operation} took ${duration.toFixed(2)}ms (fast)`);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return duration;
|
|
531
|
+
} catch (error) {
|
|
532
|
+
// Fallback to console if logger fails
|
|
533
|
+
const duration = performance.now() - startTime;
|
|
534
|
+
console.log(`[${component.toUpperCase()}] ${operation} took ${duration.toFixed(2)}ms`);
|
|
535
|
+
return duration;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
403
538
|
}
|
|
404
539
|
|
|
405
540
|
// Create singleton instance
|
|
@@ -414,6 +549,12 @@ if (isBrowser() && typeof window !== 'undefined') {
|
|
|
414
549
|
window.CACP_Logger = enhancedLoggers.controls;
|
|
415
550
|
}
|
|
416
551
|
|
|
417
|
-
//
|
|
552
|
+
// Add static methods to the enhanced loggers for convenience
|
|
553
|
+
enhancedLoggers.getInstance = CACPLogger.getInstance;
|
|
554
|
+
enhancedLoggers.getInstanceSync = CACPLogger.getInstanceSync;
|
|
555
|
+
enhancedLoggers.logPerformance = CACPLogger.logPerformance;
|
|
556
|
+
enhancedLoggers.CACPLogger = CACPLogger;
|
|
557
|
+
|
|
558
|
+
// Export both the initialized loggers and the class for advanced usage
|
|
418
559
|
export default enhancedLoggers;
|
|
419
560
|
export {logger as CACPLogger};
|
package/package.json
CHANGED