@crimsonsunset/jsg-logger 1.4.0 → 1.5.2
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/CHANGELOG.md +149 -0
- package/README.md +130 -4
- package/config/config-manager.js +39 -9
- package/config/default-config.json +1 -2
- package/docs/next-session.md +52 -9
- package/formatters/browser-formatter.js +1 -1
- package/formatters/cli-formatter.js +66 -43
- package/index.js +126 -18
- package/package.json +3 -5
- package/utils/environment-detector.js +33 -1
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,155 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
16
|
### Fixed
|
|
17
17
|
- None
|
|
18
18
|
|
|
19
|
+
## [1.5.2] - 2025-10-25 🐛 **PATCH: CLI Formatter Custom Component Display**
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **CLI formatter custom component names** - Formatter was using hardcoded `COMPONENT_SCHEME` instead of `configManager`, causing custom component names to display as `[JSG-CORE]` instead of user-defined names like `[SETUP]`
|
|
23
|
+
- **Browser formatter** - Removed redundant component name transformation
|
|
24
|
+
|
|
25
|
+
### Technical Changes
|
|
26
|
+
- `formatters/cli-formatter.js` - Use `configManager.getComponentConfig()` instead of static `COMPONENT_SCHEME`
|
|
27
|
+
- `formatters/browser-formatter.js` - Remove redundant name transformation
|
|
28
|
+
- `tests/custom-components.test.js` - Added Test 6 for formatter output validation
|
|
29
|
+
|
|
30
|
+
## [1.5.1] - 2025-10-25 🔧 **PATCH: Component Initialization Optimization**
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- **Component initialization pollution** - `getAvailableComponents()` no longer initializes all 13 default COMPONENT_SCHEME components when user defines custom components (3 defined → 3 initialized instead of 16)
|
|
34
|
+
- **Component name formatting** - Changed from PascalCase (`MyComponent`) to uppercase with separators (`MY-COMPONENT`)
|
|
35
|
+
|
|
36
|
+
### Technical Changes
|
|
37
|
+
- `config/config-manager.js` - Return only user components when defined, fallback to COMPONENT_SCHEME if empty; components replaced instead of merged; enhanced `_formatComponentName()`
|
|
38
|
+
- `index.js` - Clean reinitialization: reset config, clear loggers, normalize inline config
|
|
39
|
+
- `tests/custom-components.test.js` - New comprehensive test suite (5 tests)
|
|
40
|
+
|
|
41
|
+
## [1.5.0] - 2025-10-25 🎯 **CRITICAL FIX: CLI Tool Support**
|
|
42
|
+
|
|
43
|
+
### 🚨 **Critical Fixes**
|
|
44
|
+
These fixes resolve major blockers for CLI tool usage reported in production.
|
|
45
|
+
|
|
46
|
+
#### **Fixed: CLI Formatter Context Data Display** (Critical)
|
|
47
|
+
- **Replaced pino-colada** with custom formatter that displays context data
|
|
48
|
+
- Context objects now render as indented tree format in terminal
|
|
49
|
+
- Example output:
|
|
50
|
+
```
|
|
51
|
+
21:32:11.6 ✨ [SYSTEM] ✓ macOS version compatible
|
|
52
|
+
├─ version: 14.2
|
|
53
|
+
├─ build: 23C64
|
|
54
|
+
└─ command: sw_vers
|
|
55
|
+
```
|
|
56
|
+
- **Problem solved**: Context data was being silently ignored by pino-colada
|
|
57
|
+
- **Impact**: Terminal applications now show full diagnostic information, not just messages
|
|
58
|
+
|
|
59
|
+
#### **Fixed: Environment Detection for CLI Tools** (Critical)
|
|
60
|
+
- **Enhanced `isCLI()` detection** - Now checks multiple signals:
|
|
61
|
+
- `process.stdout.isTTY` OR `process.stderr.isTTY` (not just stdout)
|
|
62
|
+
- `process.env.TERM` or `process.env.COLORTERM` environment variables
|
|
63
|
+
- Not running in CI/GitHub Actions context
|
|
64
|
+
- **Problem solved**: CLI tools were being detected as "server" mode → outputting JSON instead of pretty terminal formatting
|
|
65
|
+
- **Impact**: Terminal applications now properly display colored, formatted output instead of raw JSON blobs
|
|
66
|
+
|
|
67
|
+
#### **Added: Force Environment Override** (Critical)
|
|
68
|
+
- **New config option**: `forceEnvironment: 'cli' | 'browser' | 'server'`
|
|
69
|
+
- Allows explicit environment override when auto-detection fails
|
|
70
|
+
- Works in both inline config and `logger-config.json`
|
|
71
|
+
- **Use case**: Essential for CLI tools in non-TTY contexts (piped output, automation scripts, etc.)
|
|
72
|
+
|
|
73
|
+
#### **Added: Custom Component Name Support** (High Priority)
|
|
74
|
+
- **Auto-create loggers for ANY component name** - No longer restricted to `COMPONENT_SCHEME`
|
|
75
|
+
- Components not in config get auto-generated with sensible defaults:
|
|
76
|
+
- Default emoji: 📦
|
|
77
|
+
- Default color: #999999
|
|
78
|
+
- Uppercase display name
|
|
79
|
+
- Global level inheritance
|
|
80
|
+
- **Problem solved**: Custom components like 'system', 'installer', 'nvm' now work without pre-definition
|
|
81
|
+
- **Impact**: True zero-configuration for component names
|
|
82
|
+
|
|
83
|
+
### ✨ **API Enhancements**
|
|
84
|
+
|
|
85
|
+
#### **Updated: `getComponent()` Method**
|
|
86
|
+
- Now auto-creates loggers for undefined components instead of returning error loggers
|
|
87
|
+
- Adds new components to auto-discovery getters dynamically
|
|
88
|
+
- Seamless experience for custom component names
|
|
89
|
+
|
|
90
|
+
#### **Updated: `getComponentConfig()` Method**
|
|
91
|
+
- Added 3-tier priority system:
|
|
92
|
+
1. Config components (project-defined)
|
|
93
|
+
2. COMPONENT_SCHEME defaults (built-in)
|
|
94
|
+
3. Auto-generated (for custom components)
|
|
95
|
+
- Always returns valid config, never null/undefined
|
|
96
|
+
|
|
97
|
+
#### **Updated: `init()` and `initSync()` Methods**
|
|
98
|
+
- Now load config BEFORE environment detection
|
|
99
|
+
- Apply `forceEnvironment` config before determining environment
|
|
100
|
+
- `initSync()` properly handles inline config objects
|
|
101
|
+
|
|
102
|
+
### 📚 **Documentation**
|
|
103
|
+
- **Updated README** - New v1.5.0 Quick Start section highlighting CLI tool fixes
|
|
104
|
+
- **Added Force Environment docs** - When and how to override environment detection
|
|
105
|
+
- **Added Custom Components docs** - Examples of using arbitrary component names
|
|
106
|
+
- **Updated Environment Detection section** - Document enhanced CLI detection logic
|
|
107
|
+
|
|
108
|
+
### 🎯 **Real-World Impact**
|
|
109
|
+
**Before v1.5.0 (Broken for CLI tools):**
|
|
110
|
+
```javascript
|
|
111
|
+
const logger = JSGLogger.getInstanceSync({ components: { system: {...} } });
|
|
112
|
+
logger.getComponent('system').info('✓ macOS compatible', { version: '14.2', build: '23C64' });
|
|
113
|
+
// Output: {"level":30,"time":...,"msg":"✓ macOS compatible"} ❌ JSON blob
|
|
114
|
+
// Component 'system' not found error ❌
|
|
115
|
+
// Context data not visible ❌
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**After v1.5.0 (All Fixed!):**
|
|
119
|
+
```javascript
|
|
120
|
+
const logger = JSGLogger.getInstanceSync({
|
|
121
|
+
forceEnvironment: 'cli',
|
|
122
|
+
components: { system: { emoji: '⚙️' } }
|
|
123
|
+
});
|
|
124
|
+
logger.getComponent('system').info('✓ macOS compatible', { version: '14.2', build: '23C64' });
|
|
125
|
+
// Output:
|
|
126
|
+
// 21:32:11.6 ⚙️ [SYSTEM] ✓ macOS compatible ✅ Pretty formatted
|
|
127
|
+
// ├─ version: 14.2 ✅ Context data visible
|
|
128
|
+
// └─ build: 23C64 ✅ Tree formatting
|
|
129
|
+
// Custom component works ✅
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 🔧 **Technical Changes**
|
|
133
|
+
- **File**: `formatters/cli-formatter.js` ⭐ NEW FIX
|
|
134
|
+
- Removed pino-colada dependency (wasn't showing context data)
|
|
135
|
+
- Implemented custom formatter with context tree rendering
|
|
136
|
+
- Context data now displays with tree formatting (├─ and └─)
|
|
137
|
+
- Filters out pino internal fields (level, time, msg, pid, hostname, name, v, environment)
|
|
138
|
+
|
|
139
|
+
- **File**: `utils/environment-detector.js`
|
|
140
|
+
- Added `forceEnvironment()` function for manual override
|
|
141
|
+
- Enhanced `isCLI()` with multi-signal detection
|
|
142
|
+
- All detection functions now respect forced environment
|
|
143
|
+
|
|
144
|
+
- **File**: `config/config-manager.js`
|
|
145
|
+
- `getComponentConfig()` now has 3-tier fallback with auto-generation
|
|
146
|
+
|
|
147
|
+
- **File**: `index.js`
|
|
148
|
+
- Import `forceEnvironment` from environment detector
|
|
149
|
+
- Config loading moved BEFORE environment detection
|
|
150
|
+
- `getComponent()` auto-creates loggers instead of error loggers
|
|
151
|
+
- Added dynamic auto-discovery getter registration
|
|
152
|
+
|
|
153
|
+
- **File**: `package.json`
|
|
154
|
+
- Removed pino-colada from dependencies (no longer required)
|
|
155
|
+
|
|
156
|
+
### 📋 **Migration Guide**
|
|
157
|
+
**No breaking changes** - This is a backward-compatible enhancement.
|
|
158
|
+
|
|
159
|
+
**Recommended for CLI tools:**
|
|
160
|
+
```javascript
|
|
161
|
+
// Add this to your config for reliable terminal output
|
|
162
|
+
const logger = JSGLogger.getInstanceSync({
|
|
163
|
+
forceEnvironment: 'cli', // ← Add this line
|
|
164
|
+
// ... rest of your config
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
19
168
|
## [1.2.0] - 2025-08-21 🎯 **MAJOR: Fully Generic Logger**
|
|
20
169
|
|
|
21
170
|
### 🚀 **BREAKING CHANGES**
|
package/README.md
CHANGED
|
@@ -11,7 +11,9 @@ A sophisticated, fully generic logging system that automatically detects its env
|
|
|
11
11
|
- 🔧 **Auto-Discovery Components** - Both camelCase and kebab-case component access
|
|
12
12
|
- ⚡ **Built-in Performance Logging** - Static utilities with auto-getInstance
|
|
13
13
|
- 🛡️ **Non-Destructive Error Handling** - Missing components log but don't break apps
|
|
14
|
-
-
|
|
14
|
+
- 🎨 **Custom Component Names** - *New in v1.5.0!* Use ANY component name, auto-generated styling
|
|
15
|
+
- 🔧 **Force Environment Override** - *New in v1.5.0!* Override auto-detection for CLI tools
|
|
16
|
+
- 🧠 **Enhanced Environment Detection** - *New in v1.5.0!* Robust CLI detection with fallbacks
|
|
15
17
|
- 🎨 **Beautiful Visual Output** - Emoji, colors, and structured context display
|
|
16
18
|
- 📱 **Multi-Environment** - Browser console, terminal, and production JSON
|
|
17
19
|
- 🏪 **Log Store** - In-memory storage for debugging and popup interfaces
|
|
@@ -25,6 +27,41 @@ A sophisticated, fully generic logging system that automatically detects its env
|
|
|
25
27
|
|
|
26
28
|
## 🚀 Quick Start
|
|
27
29
|
|
|
30
|
+
### **v1.5.0: Custom Components & Force Environment - Perfect for CLI Tools!**
|
|
31
|
+
|
|
32
|
+
> **✨ New in v1.5.0:** Use ANY component name (not just pre-defined ones) and force CLI mode for terminal applications!
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
import JSGLogger from '@crimsonsunset/jsg-logger';
|
|
36
|
+
|
|
37
|
+
// ✨ NEW: Force environment for CLI tools (fixes terminal detection)
|
|
38
|
+
const logger = JSGLogger.getInstanceSync({
|
|
39
|
+
forceEnvironment: 'cli', // Forces pretty terminal output
|
|
40
|
+
globalLevel: 'info',
|
|
41
|
+
components: {
|
|
42
|
+
system: { emoji: '⚙️', level: 'info' }, // Custom component names!
|
|
43
|
+
installer: { emoji: '📦', level: 'info' }, // No need to pre-define
|
|
44
|
+
ssh: { emoji: '🔑', level: 'info' }, // Auto-generated styling
|
|
45
|
+
nvm: { emoji: '🟢', level: 'info' }
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// ✨ NEW: Custom components work immediately
|
|
50
|
+
const sysLog = logger.getComponent('system');
|
|
51
|
+
sysLog.info('✓ macOS version compatible', { version: '14.2', build: '23C64' });
|
|
52
|
+
// Output: Pretty formatted terminal output with colors AND context data!
|
|
53
|
+
// 21:32:11.6 ⚙️ [SYSTEM] ✓ macOS version compatible
|
|
54
|
+
// ├─ version: 14.2
|
|
55
|
+
// └─ build: 23C64
|
|
56
|
+
|
|
57
|
+
const installLog = logger.getComponent('installer');
|
|
58
|
+
installLog.info('✓ Applications installed', { installed: 25, duration: '5m' });
|
|
59
|
+
// 21:32:11.8 📦 [INSTALLER] ✓ Applications installed
|
|
60
|
+
// ├─ installed: 25
|
|
61
|
+
// └─ duration: 5m
|
|
62
|
+
// No more JSON blobs in terminal! 🎉
|
|
63
|
+
```
|
|
64
|
+
|
|
28
65
|
### **v1.2.0: Fully Generic Design - Works with Any Project!**
|
|
29
66
|
|
|
30
67
|
> **⚠️ Breaking Change:** v1.2.0 requires defining components in your logger-config.json. The logger is now 100% generic with no hardcoded assumptions.
|
|
@@ -47,7 +84,7 @@ const startTime = performance.now();
|
|
|
47
84
|
// ... do work ...
|
|
48
85
|
JSGLogger.logPerformance('Page Generation', startTime, 'api');
|
|
49
86
|
|
|
50
|
-
//
|
|
87
|
+
// ✨ NEW: Custom components auto-created on demand
|
|
51
88
|
const dynamicLogger = logger.getComponent('new-feature');
|
|
52
89
|
dynamicLogger.info('Auto-created component!'); // Works immediately
|
|
53
90
|
```
|
|
@@ -82,10 +119,68 @@ This allows surgical debugging - you can turn on trace logging for just one prob
|
|
|
82
119
|
|
|
83
120
|
## ⚙️ **Advanced Configuration**
|
|
84
121
|
|
|
122
|
+
### **Force Environment Override** ✨ *New in v1.5.0*
|
|
123
|
+
|
|
124
|
+
Perfect for CLI tools that get mis-detected as "server" mode:
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
// Inline config approach (recommended for CLI tools)
|
|
128
|
+
const logger = JSGLogger.getInstanceSync({
|
|
129
|
+
forceEnvironment: 'cli', // Options: 'browser', 'cli', 'server'
|
|
130
|
+
globalLevel: 'info',
|
|
131
|
+
components: {
|
|
132
|
+
system: { emoji: '⚙️', level: 'info' }
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Or in `logger-config.json`:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"forceEnvironment": "cli",
|
|
142
|
+
"projectName": "My CLI Tool",
|
|
143
|
+
"globalLevel": "info",
|
|
144
|
+
"components": {
|
|
145
|
+
"system": { "emoji": "⚙️", "level": "info" }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**When to use `forceEnvironment`:**
|
|
151
|
+
- CLI tools running in non-TTY contexts (CI, piped output, etc.)
|
|
152
|
+
- Override incorrect environment detection
|
|
153
|
+
- Testing different output formats
|
|
154
|
+
- Production deployments with specific requirements
|
|
155
|
+
|
|
156
|
+
### **Custom Component Names** ✨ *New in v1.5.0*
|
|
157
|
+
|
|
158
|
+
Use ANY component name - no need to pre-define in COMPONENT_SCHEME:
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
const logger = JSGLogger.getInstanceSync({
|
|
162
|
+
components: {
|
|
163
|
+
'my-custom-component': { emoji: '🎯', level: 'debug' },
|
|
164
|
+
'another-one': { emoji: '🚀', level: 'info' },
|
|
165
|
+
'system-checker': { emoji: '⚙️', level: 'trace' }
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// All these work immediately - auto-created with sensible defaults
|
|
170
|
+
const log1 = logger.getComponent('my-custom-component');
|
|
171
|
+
const log2 = logger.getComponent('another-one');
|
|
172
|
+
const log3 = logger.getComponent('system-checker');
|
|
173
|
+
|
|
174
|
+
// Even undefined components work (auto-generated with 📦 emoji)
|
|
175
|
+
const log4 = logger.getComponent('undefined-component');
|
|
176
|
+
log4.info('This works!'); // Uses auto-generated styling
|
|
177
|
+
```
|
|
178
|
+
|
|
85
179
|
### **Full Configuration Example**
|
|
86
180
|
|
|
87
181
|
```json
|
|
88
182
|
{
|
|
183
|
+
"forceEnvironment": "cli",
|
|
89
184
|
"projectName": "My Advanced Project",
|
|
90
185
|
"globalLevel": "info",
|
|
91
186
|
"timestampMode": "absolute",
|
|
@@ -255,6 +350,9 @@ logger.controls.addFileOverride('src/popup.js', {
|
|
|
255
350
|
```
|
|
256
351
|
|
|
257
352
|
### **Context Data**
|
|
353
|
+
|
|
354
|
+
✨ **New in v1.5.0:** Context data now displays in CLI/terminal mode with tree formatting!
|
|
355
|
+
|
|
258
356
|
```javascript
|
|
259
357
|
logger.api.error('Request failed', {
|
|
260
358
|
url: window.location.href,
|
|
@@ -267,7 +365,15 @@ logger.api.error('Request failed', {
|
|
|
267
365
|
userAgent: navigator.userAgent
|
|
268
366
|
});
|
|
269
367
|
|
|
270
|
-
//
|
|
368
|
+
// CLI/Terminal output (v1.5.0+):
|
|
369
|
+
// 22:15:30.1 🚨 [API] Request failed
|
|
370
|
+
// ├─ url: https://soundcloud.com/track/example
|
|
371
|
+
// ├─ selectors: {"title":".track-title","artist":".track-artist"}
|
|
372
|
+
// ├─ retryCount: 3
|
|
373
|
+
// ├─ lastError: Element not found
|
|
374
|
+
// └─ userAgent: Mozilla/5.0...
|
|
375
|
+
|
|
376
|
+
// Browser Console output:
|
|
271
377
|
// 22:15:30.123 🚨 [API] Request failed
|
|
272
378
|
// ├─ url: https://soundcloud.com/track/example
|
|
273
379
|
// ├─ selectors: {title: ".track-title", artist: ".track-artist"}
|
|
@@ -393,7 +499,7 @@ const stats = logger.controls.getStats();
|
|
|
393
499
|
npm install @crimsonsunset/jsg-logger
|
|
394
500
|
```
|
|
395
501
|
|
|
396
|
-
**Latest**: v1.
|
|
502
|
+
**Latest**: v1.5.0 includes critical CLI tool fixes and custom component support!
|
|
397
503
|
|
|
398
504
|
## 🎯 Environment Detection
|
|
399
505
|
|
|
@@ -403,6 +509,26 @@ The logger automatically detects its environment and uses optimal implementation
|
|
|
403
509
|
- **CLI**: Uses pino-colada for beautiful terminal output
|
|
404
510
|
- **Server**: Uses structured JSON for production logging
|
|
405
511
|
|
|
512
|
+
### **Enhanced CLI Detection** ✨ *Improved in v1.5.0*
|
|
513
|
+
|
|
514
|
+
The CLI detection now checks multiple signals:
|
|
515
|
+
1. **TTY Check**: `process.stdout.isTTY` or `process.stderr.isTTY`
|
|
516
|
+
2. **Terminal Environment**: `process.env.TERM` or `process.env.COLORTERM`
|
|
517
|
+
3. **Non-CI Context**: Not running in CI/GitHub Actions
|
|
518
|
+
|
|
519
|
+
This fixes detection issues in various terminal contexts where `isTTY` may be undefined.
|
|
520
|
+
|
|
521
|
+
### **Force Environment Override** ✨ *New in v1.5.0*
|
|
522
|
+
|
|
523
|
+
If auto-detection fails, you can force the environment:
|
|
524
|
+
|
|
525
|
+
```javascript
|
|
526
|
+
const logger = JSGLogger.getInstanceSync({
|
|
527
|
+
forceEnvironment: 'cli', // Override auto-detection
|
|
528
|
+
// ... rest of config
|
|
529
|
+
});
|
|
530
|
+
```
|
|
531
|
+
|
|
406
532
|
**Why Browser is Different:**
|
|
407
533
|
Our testing revealed that Pino's browser detection was interfering with custom formatters, especially in Chrome extensions. By creating a custom direct browser logger that bypasses Pino entirely, we achieved:
|
|
408
534
|
- Perfect emoji and color display
|
package/config/config-manager.js
CHANGED
|
@@ -292,10 +292,16 @@ export class ConfigManager {
|
|
|
292
292
|
* @private
|
|
293
293
|
*/
|
|
294
294
|
_formatComponentName(componentName) {
|
|
295
|
+
// If already uppercase, return as-is
|
|
296
|
+
if (componentName === componentName.toUpperCase()) {
|
|
297
|
+
return componentName;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Convert to uppercase and preserve separators for readability
|
|
295
301
|
return componentName
|
|
296
|
-
.
|
|
297
|
-
.
|
|
298
|
-
.
|
|
302
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2') // camelCase → kebab-case
|
|
303
|
+
.replace(/_/g, '-') // snake_case → kebab-case
|
|
304
|
+
.toUpperCase();
|
|
299
305
|
}
|
|
300
306
|
|
|
301
307
|
/**
|
|
@@ -315,7 +321,11 @@ export class ConfigManager {
|
|
|
315
321
|
|
|
316
322
|
for (const key in override) {
|
|
317
323
|
if (override.hasOwnProperty(key)) {
|
|
318
|
-
|
|
324
|
+
// Special case: 'components' should be replaced, not merged
|
|
325
|
+
// This allows users to define their own components without getting defaults
|
|
326
|
+
if (key === 'components' && typeof override[key] === 'object') {
|
|
327
|
+
merged[key] = override[key];
|
|
328
|
+
} else if (typeof override[key] === 'object' && !Array.isArray(override[key])) {
|
|
319
329
|
merged[key] = this.mergeConfigs(merged[key] || {}, override[key]);
|
|
320
330
|
} else {
|
|
321
331
|
merged[key] = override[key];
|
|
@@ -406,7 +416,23 @@ export class ConfigManager {
|
|
|
406
416
|
* @returns {Object} Component configuration
|
|
407
417
|
*/
|
|
408
418
|
getComponentConfig(componentName, filePath = null) {
|
|
409
|
-
|
|
419
|
+
// Priority 1: Config components
|
|
420
|
+
let baseComponent = this.config.components?.[componentName];
|
|
421
|
+
|
|
422
|
+
// Priority 2: COMPONENT_SCHEME defaults
|
|
423
|
+
if (!baseComponent) {
|
|
424
|
+
baseComponent = COMPONENT_SCHEME[componentName];
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Priority 3: Auto-generate for custom components
|
|
428
|
+
if (!baseComponent) {
|
|
429
|
+
baseComponent = {
|
|
430
|
+
emoji: '📦',
|
|
431
|
+
color: '#999999',
|
|
432
|
+
name: this._formatComponentName(componentName),
|
|
433
|
+
level: this.config.globalLevel || 'info'
|
|
434
|
+
};
|
|
435
|
+
}
|
|
410
436
|
|
|
411
437
|
// Check for file-specific overrides
|
|
412
438
|
const checkFile = filePath || this.currentFile;
|
|
@@ -523,10 +549,14 @@ export class ConfigManager {
|
|
|
523
549
|
*/
|
|
524
550
|
getAvailableComponents() {
|
|
525
551
|
const configComponents = Object.keys(this.config.components || {});
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
552
|
+
|
|
553
|
+
// If user has defined components, only return those
|
|
554
|
+
if (configComponents.length > 0) {
|
|
555
|
+
return configComponents;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Fallback to COMPONENT_SCHEME if no components configured (backward compatibility)
|
|
559
|
+
return Object.keys(COMPONENT_SCHEME);
|
|
530
560
|
}
|
|
531
561
|
|
|
532
562
|
/**
|
package/docs/next-session.md
CHANGED
|
@@ -14,12 +14,44 @@
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
**Date:** October
|
|
18
|
-
**Session Goal:** 🎯 **
|
|
19
|
-
**Status:**
|
|
17
|
+
**Date:** October 25, 2025
|
|
18
|
+
**Session Goal:** 🎯 **Critical CLI Tool Fixes** - Resolve environment detection and custom component blockers
|
|
19
|
+
**Status:** ✅ **COMPLETE** - v1.5.0 shipped with all critical fixes
|
|
20
20
|
|
|
21
21
|
## 🎉 MAJOR ACCOMPLISHMENTS THIS SESSION
|
|
22
22
|
|
|
23
|
+
### ✅ Critical CLI Tool Fixes Complete (October 25, 2025) 🚨→✅
|
|
24
|
+
- **🎨 CLI Context Data Display Fixed** - Replaced pino-colada with custom formatter
|
|
25
|
+
- Context data now renders as indented tree in terminal
|
|
26
|
+
- Shows all diagnostic information, not just messages
|
|
27
|
+
- Example: version, build, command data visible with ├─ and └─ formatting
|
|
28
|
+
- **🔧 Environment Detection Fixed** - Enhanced `isCLI()` with multi-signal detection
|
|
29
|
+
- Now checks TTY, TERM env vars, and CI context
|
|
30
|
+
- CLI tools no longer mis-detected as "server" mode
|
|
31
|
+
- Fixes JSON output in terminal applications
|
|
32
|
+
- **✨ Force Environment Override** - New `forceEnvironment` config option
|
|
33
|
+
- Allows manual override of auto-detection
|
|
34
|
+
- Works in inline config and logger-config.json
|
|
35
|
+
- Essential for non-TTY contexts (piped output, automation)
|
|
36
|
+
- **🎯 Custom Component Names** - Any component name now works
|
|
37
|
+
- Auto-creation for undefined components
|
|
38
|
+
- Sensible default styling (📦 emoji, gray color)
|
|
39
|
+
- No longer restricted to COMPONENT_SCHEME
|
|
40
|
+
- **📦 Version Bump** - Published v1.5.0 with all fixes
|
|
41
|
+
- **🗑️ Dependency Cleanup** - Removed pino-colada (no longer needed)
|
|
42
|
+
- **📚 Comprehensive Documentation** - Updated README, CHANGELOG
|
|
43
|
+
- New Quick Start section for v1.5.0
|
|
44
|
+
- Detailed forceEnvironment examples
|
|
45
|
+
- Custom component usage patterns
|
|
46
|
+
- Context data rendering examples
|
|
47
|
+
|
|
48
|
+
### **Real-World Impact**
|
|
49
|
+
Fixed production blocker in macOS setup automation tool:
|
|
50
|
+
- **Before**: JSON blobs in 30-minute terminal script → unusable
|
|
51
|
+
- **After**: Pretty colored output with component organization → perfect UX
|
|
52
|
+
|
|
53
|
+
## 🎉 PREVIOUS SESSION ACCOMPLISHMENTS
|
|
54
|
+
|
|
23
55
|
### ✅ DevTools Integration Blocker RESOLVED (October 24, 2025)
|
|
24
56
|
- **🔧 Import Path Fixed** - Installed JSG Logger as local file dependency
|
|
25
57
|
- **📦 Dependencies Complete** - All parent dependencies installed (pino, pino-colada)
|
|
@@ -70,17 +102,28 @@
|
|
|
70
102
|
|
|
71
103
|
## 📋 IMMEDIATE PRIORITIES
|
|
72
104
|
|
|
73
|
-
###
|
|
105
|
+
### **🚀 Ready to Publish v1.5.0:**
|
|
106
|
+
- [x] **Environment Detection** - Enhanced CLI detection with multi-signal check
|
|
107
|
+
- [x] **Force Environment** - Config option to override auto-detection
|
|
108
|
+
- [x] **Custom Components** - Auto-create loggers for any component name
|
|
109
|
+
- [x] **Documentation** - README, CHANGELOG updated with v1.5.0 features
|
|
110
|
+
- [x] **Version Bump** - Package version updated to 1.5.0
|
|
111
|
+
- [ ] **Publish to NPM** - `npm run release:minor` when ready
|
|
112
|
+
|
|
113
|
+
### **🔧 DevTools Theme Fixes (Optional, Low Priority):**
|
|
74
114
|
- [ ] **Fix Text Components** - Pass theme data correctly to Evergreen UI Text components
|
|
75
115
|
- [ ] **Test Panel Interaction** - Click floating button and verify panel opens
|
|
76
116
|
- [ ] **Verify Filtering** - Test component toggles affect console output
|
|
77
117
|
- [ ] **Apply Custom Theme** - Implement devtools-theme.js once basic theme works
|
|
78
118
|
|
|
79
|
-
### **✅ COMPLETED:**
|
|
80
|
-
- [x] **
|
|
81
|
-
- [x] **
|
|
82
|
-
- [x] **
|
|
83
|
-
- [x] **
|
|
119
|
+
### **✅ COMPLETED THIS SESSION:**
|
|
120
|
+
- [x] **CLI Context Data Display** - Custom formatter with tree rendering
|
|
121
|
+
- [x] **Environment Detection Fixed** - Multi-signal CLI detection (TTY, TERM, CI check)
|
|
122
|
+
- [x] **forceEnvironment Config** - Override auto-detection via config
|
|
123
|
+
- [x] **Custom Component Names** - getComponent() auto-creates loggers
|
|
124
|
+
- [x] **Config Loading Order** - Load config BEFORE environment detection
|
|
125
|
+
- [x] **Dependency Cleanup** - Removed pino-colada from package
|
|
126
|
+
- [x] **Documentation Complete** - README, CHANGELOG, version bump
|
|
84
127
|
|
|
85
128
|
## 🔮 Future Possibilities (Phase 10)
|
|
86
129
|
|
|
@@ -57,7 +57,7 @@ export const createBrowserFormatter = (componentName, logStore = null) => {
|
|
|
57
57
|
|
|
58
58
|
// 3. Component name
|
|
59
59
|
if (displayConfig.component) {
|
|
60
|
-
const componentName = component.name
|
|
60
|
+
const componentName = component.name; // Already formatted by configManager
|
|
61
61
|
logParts.push(`%c[${componentName}]`);
|
|
62
62
|
logStyles.push(`color: ${component.color}; font-weight: bold;`);
|
|
63
63
|
}
|
|
@@ -1,56 +1,79 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CLI/Terminal Formatter for JSG Logger
|
|
3
|
-
*
|
|
3
|
+
* Custom formatter with context data display
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
// Note: pino-pretty imported conditionally to avoid browser bundle issues
|
|
6
|
+
import { LEVEL_SCHEME } from '../config/component-schemes.js';
|
|
7
|
+
import { configManager } from '../config/config-manager.js';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
|
-
*
|
|
10
|
+
* Format a value for display in context tree
|
|
11
|
+
* @param {*} value - Value to format
|
|
12
|
+
* @returns {string} Formatted value
|
|
13
|
+
*/
|
|
14
|
+
const formatValue = (value) => {
|
|
15
|
+
if (value === null) return 'null';
|
|
16
|
+
if (value === undefined) return 'undefined';
|
|
17
|
+
if (typeof value === 'string') return value;
|
|
18
|
+
if (typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
19
|
+
if (typeof value === 'object') {
|
|
20
|
+
// For objects/arrays, show compact JSON
|
|
21
|
+
try {
|
|
22
|
+
return JSON.stringify(value);
|
|
23
|
+
} catch {
|
|
24
|
+
return String(value);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return String(value);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create CLI formatter with context data support
|
|
12
32
|
* @returns {Object} Stream-like object for Pino
|
|
13
33
|
*/
|
|
14
34
|
export const createCLIFormatter = () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
return {
|
|
36
|
+
write: (chunk) => {
|
|
37
|
+
try {
|
|
38
|
+
const log = JSON.parse(chunk);
|
|
39
|
+
|
|
40
|
+
// Get component info from configManager (supports custom components)
|
|
41
|
+
const component = configManager.getComponentConfig(log.name);
|
|
42
|
+
const componentName = component.name;
|
|
43
|
+
|
|
44
|
+
// Get level info
|
|
45
|
+
const level = LEVEL_SCHEME[log.level] || LEVEL_SCHEME[30];
|
|
46
|
+
|
|
47
|
+
// Format timestamp
|
|
48
|
+
const timestamp = new Date(log.time).toLocaleTimeString('en-US', {
|
|
49
|
+
hour12: false,
|
|
50
|
+
hour: '2-digit',
|
|
51
|
+
minute: '2-digit',
|
|
52
|
+
second: '2-digit',
|
|
53
|
+
fractionalSecondDigits: 1
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Format main message
|
|
57
|
+
const message = `${level.emoji} [${componentName}] ${log.msg || ''}`;
|
|
58
|
+
console.log(`${timestamp} ${message}`);
|
|
59
|
+
|
|
60
|
+
// Display context data (exclude pino internal fields)
|
|
61
|
+
const internalFields = ['level', 'time', 'msg', 'pid', 'hostname', 'name', 'v', 'environment'];
|
|
62
|
+
const contextKeys = Object.keys(log).filter(key => !internalFields.includes(key));
|
|
63
|
+
|
|
64
|
+
if (contextKeys.length > 0) {
|
|
65
|
+
contextKeys.forEach((key, index) => {
|
|
66
|
+
const isLast = index === contextKeys.length - 1;
|
|
67
|
+
const prefix = isLast ? ' └─' : ' ├─';
|
|
68
|
+
const value = formatValue(log[key]);
|
|
69
|
+
console.log(`${prefix} ${key}: ${value}`);
|
|
41
70
|
});
|
|
42
|
-
|
|
43
|
-
// Format message like pino-pretty messageFormat
|
|
44
|
-
const message = `${level.emoji} [${componentName}] ${log.msg || ''}`;
|
|
45
|
-
|
|
46
|
-
// Output with timestamp prefix
|
|
47
|
-
console.log(`${timestamp} ${message}`);
|
|
48
|
-
|
|
49
|
-
} catch (error) {
|
|
50
|
-
// Raw fallback
|
|
51
|
-
console.log(chunk);
|
|
52
71
|
}
|
|
72
|
+
|
|
73
|
+
} catch (error) {
|
|
74
|
+
// Raw fallback for malformed JSON
|
|
75
|
+
console.log(chunk);
|
|
53
76
|
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
56
79
|
};
|
package/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import pino from 'pino';
|
|
|
7
7
|
import {configManager} from './config/config-manager.js';
|
|
8
8
|
import {COMPONENT_SCHEME} from './config/component-schemes.js';
|
|
9
9
|
import defaultConfig from './config/default-config.json' with { type: 'json' };
|
|
10
|
-
import {getEnvironment, isBrowser, isCLI} from './utils/environment-detector.js';
|
|
10
|
+
import {getEnvironment, isBrowser, isCLI, forceEnvironment} from './utils/environment-detector.js';
|
|
11
11
|
import {createBrowserFormatter} from './formatters/browser-formatter.js';
|
|
12
12
|
import {createCLIFormatter} from './formatters/cli-formatter.js';
|
|
13
13
|
import {createServerFormatter, getServerConfig} from './formatters/server-formatter.js';
|
|
@@ -25,7 +25,7 @@ class JSGLogger {
|
|
|
25
25
|
constructor() {
|
|
26
26
|
this.loggers = {};
|
|
27
27
|
this.logStore = new LogStore();
|
|
28
|
-
this.environment =
|
|
28
|
+
this.environment = null; // Will be set after config loads
|
|
29
29
|
this.initialized = false;
|
|
30
30
|
this.components = {}; // Auto-discovery getters
|
|
31
31
|
}
|
|
@@ -49,10 +49,17 @@ class JSGLogger {
|
|
|
49
49
|
* @returns {Object} Enhanced logger exports with controls API
|
|
50
50
|
*/
|
|
51
51
|
static getInstanceSync(options = {}) {
|
|
52
|
+
const hasOptions = options && Object.keys(options).length > 0;
|
|
53
|
+
|
|
52
54
|
if (!JSGLogger._instance) {
|
|
55
|
+
// First time initialization
|
|
53
56
|
JSGLogger._instance = new JSGLogger();
|
|
54
57
|
JSGLogger._enhancedLoggers = JSGLogger._instance.initSync(options);
|
|
58
|
+
} else if (hasOptions) {
|
|
59
|
+
// Instance exists but new options provided - reinitialize
|
|
60
|
+
JSGLogger._enhancedLoggers = JSGLogger._instance.initSync(options);
|
|
55
61
|
}
|
|
62
|
+
|
|
56
63
|
return JSGLogger._enhancedLoggers;
|
|
57
64
|
}
|
|
58
65
|
|
|
@@ -63,11 +70,22 @@ class JSGLogger {
|
|
|
63
70
|
*/
|
|
64
71
|
async init(options = {}) {
|
|
65
72
|
try {
|
|
66
|
-
// Load configuration
|
|
73
|
+
// Load configuration FIRST (before environment detection)
|
|
67
74
|
if (options.configPath || options.config) {
|
|
68
75
|
await configManager.loadConfig(options.configPath || options.config);
|
|
76
|
+
} else if (options) {
|
|
77
|
+
// Support inline config passed as options
|
|
78
|
+
await configManager.loadConfig(options);
|
|
69
79
|
}
|
|
70
80
|
|
|
81
|
+
// Apply forceEnvironment if specified in config
|
|
82
|
+
if (configManager.config.forceEnvironment) {
|
|
83
|
+
forceEnvironment(configManager.config.forceEnvironment);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// NOW determine environment (after config is loaded and forceEnvironment is applied)
|
|
87
|
+
this.environment = getEnvironment();
|
|
88
|
+
|
|
71
89
|
// Create loggers for all available components
|
|
72
90
|
const components = configManager.getAvailableComponents();
|
|
73
91
|
|
|
@@ -107,15 +125,42 @@ class JSGLogger {
|
|
|
107
125
|
|
|
108
126
|
/**
|
|
109
127
|
* Initialize synchronously with default configuration
|
|
128
|
+
* @param {Object} options - Initialization options
|
|
110
129
|
* @returns {Object} Logger instance with all components
|
|
111
130
|
*/
|
|
112
|
-
initSync() {
|
|
131
|
+
initSync(options = {}) {
|
|
113
132
|
try {
|
|
133
|
+
// Load inline config if provided (sync loading for objects)
|
|
134
|
+
if (options && Object.keys(options).length > 0) {
|
|
135
|
+
// Reset to default config for clean reinitialization
|
|
136
|
+
// This ensures each reinit starts from a known state
|
|
137
|
+
configManager.config = {...defaultConfig};
|
|
138
|
+
|
|
139
|
+
// Normalize the inline config first
|
|
140
|
+
const normalizedOptions = configManager._normalizeConfigStructure(options);
|
|
141
|
+
// Merge inline config with default config
|
|
142
|
+
configManager.config = configManager.mergeConfigs(configManager.config, normalizedOptions);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Apply forceEnvironment if specified in config
|
|
146
|
+
if (configManager.config.forceEnvironment) {
|
|
147
|
+
forceEnvironment(configManager.config.forceEnvironment);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// NOW determine environment (after config is loaded and forceEnvironment is applied)
|
|
151
|
+
this.environment = getEnvironment();
|
|
152
|
+
|
|
153
|
+
// Clear existing loggers for clean reinitialization
|
|
154
|
+
this.loggers = {};
|
|
155
|
+
this.components = {};
|
|
156
|
+
|
|
114
157
|
// Create loggers for all available components using default config
|
|
115
158
|
const components = configManager.getAvailableComponents();
|
|
116
159
|
|
|
117
160
|
components.forEach(componentName => {
|
|
118
|
-
|
|
161
|
+
// Use original createLogger to bypass utility method caching
|
|
162
|
+
const createFn = this._createLoggerOriginal || this.createLogger.bind(this);
|
|
163
|
+
this.loggers[componentName] = createFn(componentName);
|
|
119
164
|
});
|
|
120
165
|
|
|
121
166
|
// Create legacy compatibility aliases
|
|
@@ -181,7 +226,54 @@ class JSGLogger {
|
|
|
181
226
|
logger._componentName = component.name;
|
|
182
227
|
logger._effectiveLevel = configManager.getEffectiveLevel(componentName);
|
|
183
228
|
|
|
184
|
-
|
|
229
|
+
// Wrap pino logger to support (message, context) syntax
|
|
230
|
+
const wrappedLogger = this._wrapPinoLogger(logger);
|
|
231
|
+
|
|
232
|
+
return wrappedLogger;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Wrap Pino logger to support (message, context) syntax
|
|
237
|
+
* Transforms calls from logger.info('msg', {ctx}) to pino's logger.info({ctx}, 'msg')
|
|
238
|
+
* @param {Object} pinoLogger - Original pino logger instance
|
|
239
|
+
* @returns {Object} Wrapped logger with enhanced syntax
|
|
240
|
+
* @private
|
|
241
|
+
*/
|
|
242
|
+
_wrapPinoLogger(pinoLogger) {
|
|
243
|
+
const levels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
|
|
244
|
+
const wrapped = {};
|
|
245
|
+
|
|
246
|
+
levels.forEach(level => {
|
|
247
|
+
wrapped[level] = (first, ...args) => {
|
|
248
|
+
// Handle different argument patterns
|
|
249
|
+
if (typeof first === 'string') {
|
|
250
|
+
// Pattern: logger.info('message', {context})
|
|
251
|
+
const message = first;
|
|
252
|
+
if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null) {
|
|
253
|
+
// Has context object
|
|
254
|
+
pinoLogger[level](args[0], message);
|
|
255
|
+
} else {
|
|
256
|
+
// Just message
|
|
257
|
+
pinoLogger[level](message);
|
|
258
|
+
}
|
|
259
|
+
} else if (typeof first === 'object' && first !== null) {
|
|
260
|
+
// Pattern: logger.info({context}, 'message') - already pino format
|
|
261
|
+
pinoLogger[level](first, ...args);
|
|
262
|
+
} else {
|
|
263
|
+
// Fallback: just pass through
|
|
264
|
+
pinoLogger[level](first, ...args);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Copy over all other properties from original logger
|
|
270
|
+
Object.keys(pinoLogger).forEach(key => {
|
|
271
|
+
if (!wrapped[key]) {
|
|
272
|
+
wrapped[key] = pinoLogger[key];
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
return wrapped;
|
|
185
277
|
}
|
|
186
278
|
|
|
187
279
|
/**
|
|
@@ -203,13 +295,19 @@ class JSGLogger {
|
|
|
203
295
|
* @private
|
|
204
296
|
*/
|
|
205
297
|
addUtilityMethods() {
|
|
206
|
-
//
|
|
298
|
+
// Store reference to original createLogger before overriding
|
|
299
|
+
const originalCreateLogger = this.createLogger.bind(this);
|
|
300
|
+
|
|
301
|
+
// Create logger on demand (reuses existing loggers)
|
|
207
302
|
this.createLogger = (componentName) => {
|
|
208
303
|
if (!this.loggers[componentName]) {
|
|
209
|
-
this.loggers[componentName] =
|
|
304
|
+
this.loggers[componentName] = originalCreateLogger(componentName);
|
|
210
305
|
}
|
|
211
306
|
return this.loggers[componentName];
|
|
212
307
|
};
|
|
308
|
+
|
|
309
|
+
// Store the original for internal use
|
|
310
|
+
this._createLoggerOriginal = originalCreateLogger;
|
|
213
311
|
}
|
|
214
312
|
|
|
215
313
|
/**
|
|
@@ -506,23 +604,33 @@ class JSGLogger {
|
|
|
506
604
|
}
|
|
507
605
|
|
|
508
606
|
/**
|
|
509
|
-
* Get a specific component logger with
|
|
607
|
+
* Get a specific component logger with auto-creation for custom components
|
|
510
608
|
* @param {string} componentName - Component name to retrieve
|
|
511
|
-
* @returns {Object} Logger instance
|
|
609
|
+
* @returns {Object} Logger instance (auto-created if needed)
|
|
512
610
|
*/
|
|
513
611
|
getComponent(componentName) {
|
|
612
|
+
// If logger doesn't exist, auto-create it for custom components
|
|
514
613
|
if (!this.loggers[componentName]) {
|
|
515
|
-
|
|
614
|
+
// Check if this is a configured component or custom component
|
|
615
|
+
const hasConfig = configManager.config.components?.[componentName];
|
|
616
|
+
const hasScheme = COMPONENT_SCHEME[componentName];
|
|
516
617
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
this.loggers.
|
|
520
|
-
|
|
521
|
-
|
|
618
|
+
if (!hasConfig && !hasScheme) {
|
|
619
|
+
// Custom component - log info and auto-create
|
|
620
|
+
if (this.loggers.core) {
|
|
621
|
+
this.loggers.core.debug(`Auto-creating custom component logger: ${componentName}`);
|
|
622
|
+
}
|
|
522
623
|
}
|
|
523
624
|
|
|
524
|
-
//
|
|
525
|
-
|
|
625
|
+
// Create the logger (getComponentConfig will auto-generate config for custom components)
|
|
626
|
+
this.loggers[componentName] = this.createLogger(componentName);
|
|
627
|
+
|
|
628
|
+
// Also add to auto-discovery getters
|
|
629
|
+
this.components[componentName] = () => this.getComponent(componentName);
|
|
630
|
+
const camelName = componentName.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
|
|
631
|
+
if (camelName !== componentName) {
|
|
632
|
+
this.components[camelName] = () => this.getComponent(componentName);
|
|
633
|
+
}
|
|
526
634
|
}
|
|
527
635
|
|
|
528
636
|
return this.loggers[componentName];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crimsonsunset/jsg-logger",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "JSG Logger - Multi-environment logger with smart detection, file-level overrides, and beautiful console formatting",
|
|
6
6
|
"main": "index.js",
|
|
@@ -34,12 +34,8 @@
|
|
|
34
34
|
"preact": "^10.27.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"pino-colada": "^2.2.2",
|
|
38
37
|
"vite": "^5.1.3"
|
|
39
38
|
},
|
|
40
|
-
"peerDependencies": {
|
|
41
|
-
"pino-colada": "^2.2.2"
|
|
42
|
-
},
|
|
43
39
|
"files": [
|
|
44
40
|
"index.js",
|
|
45
41
|
"config/",
|
|
@@ -69,6 +65,8 @@
|
|
|
69
65
|
"./examples/*": "./examples/*"
|
|
70
66
|
},
|
|
71
67
|
"scripts": {
|
|
68
|
+
"test": "node tests/run-all.js",
|
|
69
|
+
"test:watch": "nodemon --watch . --ext js --exec 'npm test'",
|
|
72
70
|
"dev": "vite",
|
|
73
71
|
"dev:devtools": "vite",
|
|
74
72
|
"test:devtools": "vite",
|
|
@@ -3,20 +3,50 @@
|
|
|
3
3
|
* Smart detection of browser, CLI, and server environments
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
// Store forced environment override
|
|
7
|
+
let forcedEnvironment = null;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Force environment detection to a specific value
|
|
11
|
+
* @param {'browser'|'cli'|'server'|null} env - Environment to force, or null to reset
|
|
12
|
+
*/
|
|
13
|
+
export const forceEnvironment = (env) => {
|
|
14
|
+
if (env !== null && !['browser', 'cli', 'server'].includes(env)) {
|
|
15
|
+
console.warn(`[JSG-LOGGER] Invalid environment "${env}". Must be 'browser', 'cli', 'server', or null.`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
forcedEnvironment = env;
|
|
19
|
+
};
|
|
20
|
+
|
|
6
21
|
/**
|
|
7
22
|
* Check if running in browser environment
|
|
8
23
|
* @returns {boolean}
|
|
9
24
|
*/
|
|
10
25
|
export const isBrowser = () => {
|
|
26
|
+
if (forcedEnvironment) return forcedEnvironment === 'browser';
|
|
11
27
|
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
12
28
|
};
|
|
13
29
|
|
|
14
30
|
/**
|
|
15
31
|
* Check if running in CLI/terminal environment
|
|
32
|
+
* Enhanced detection for various terminal contexts
|
|
16
33
|
* @returns {boolean}
|
|
17
34
|
*/
|
|
18
35
|
export const isCLI = () => {
|
|
19
|
-
return
|
|
36
|
+
if (forcedEnvironment) return forcedEnvironment === 'cli';
|
|
37
|
+
|
|
38
|
+
if (typeof process === 'undefined') return false;
|
|
39
|
+
|
|
40
|
+
// Check multiple signals for TTY/terminal environment
|
|
41
|
+
const hasTTY = process.stdout?.isTTY || process.stderr?.isTTY;
|
|
42
|
+
const hasTermEnv = process.env.TERM || process.env.COLORTERM;
|
|
43
|
+
const notCI = !process.env.CI && !process.env.GITHUB_ACTIONS;
|
|
44
|
+
|
|
45
|
+
// Consider it CLI if:
|
|
46
|
+
// 1. Has TTY (traditional check)
|
|
47
|
+
// 2. Has TERM/COLORTERM environment variables (terminal detected)
|
|
48
|
+
// 3. Not running in CI/automation environment
|
|
49
|
+
return hasTTY || (hasTermEnv && notCI);
|
|
20
50
|
};
|
|
21
51
|
|
|
22
52
|
/**
|
|
@@ -24,6 +54,7 @@ export const isCLI = () => {
|
|
|
24
54
|
* @returns {boolean}
|
|
25
55
|
*/
|
|
26
56
|
export const isServer = () => {
|
|
57
|
+
if (forcedEnvironment) return forcedEnvironment === 'server';
|
|
27
58
|
return !isBrowser() && !isCLI();
|
|
28
59
|
};
|
|
29
60
|
|
|
@@ -32,6 +63,7 @@ export const isServer = () => {
|
|
|
32
63
|
* @returns {'browser'|'cli'|'server'}
|
|
33
64
|
*/
|
|
34
65
|
export const getEnvironment = () => {
|
|
66
|
+
if (forcedEnvironment) return forcedEnvironment;
|
|
35
67
|
if (isBrowser()) return 'browser';
|
|
36
68
|
if (isCLI()) return 'cli';
|
|
37
69
|
return 'server';
|