@hamak/logging-impl 0.4.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.
Files changed (57) hide show
  1. package/dist/core/context-logger.d.ts +26 -0
  2. package/dist/core/context-logger.d.ts.map +1 -0
  3. package/dist/core/context-logger.js +82 -0
  4. package/dist/core/index.d.ts +3 -0
  5. package/dist/core/index.d.ts.map +1 -0
  6. package/dist/core/index.js +2 -0
  7. package/dist/core/log-manager.d.ts +41 -0
  8. package/dist/core/log-manager.d.ts.map +1 -0
  9. package/dist/core/log-manager.js +241 -0
  10. package/dist/es2015/core/context-logger.js +74 -0
  11. package/dist/es2015/core/index.js +2 -0
  12. package/dist/es2015/core/log-manager.js +255 -0
  13. package/dist/es2015/formatters/dev-formatter.js +152 -0
  14. package/dist/es2015/formatters/index.js +2 -0
  15. package/dist/es2015/formatters/json-formatter.js +69 -0
  16. package/dist/es2015/index.js +19 -0
  17. package/dist/es2015/plugin/index.js +1 -0
  18. package/dist/es2015/plugin/logging-plugin-factory.js +118 -0
  19. package/dist/es2015/transports/console-transport.js +41 -0
  20. package/dist/es2015/transports/index.js +1 -0
  21. package/dist/es2015/utils/console-interceptor.js +105 -0
  22. package/dist/es2015/utils/event-emitter.js +39 -0
  23. package/dist/es2015/utils/index.js +2 -0
  24. package/dist/formatters/dev-formatter.d.ts +20 -0
  25. package/dist/formatters/dev-formatter.d.ts.map +1 -0
  26. package/dist/formatters/dev-formatter.js +140 -0
  27. package/dist/formatters/index.d.ts +3 -0
  28. package/dist/formatters/index.d.ts.map +1 -0
  29. package/dist/formatters/index.js +2 -0
  30. package/dist/formatters/json-formatter.d.ts +24 -0
  31. package/dist/formatters/json-formatter.d.ts.map +1 -0
  32. package/dist/formatters/json-formatter.js +65 -0
  33. package/dist/index.d.ts +16 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +19 -0
  36. package/dist/plugin/index.d.ts +2 -0
  37. package/dist/plugin/index.d.ts.map +1 -0
  38. package/dist/plugin/index.js +1 -0
  39. package/dist/plugin/logging-plugin-factory.d.ts +37 -0
  40. package/dist/plugin/logging-plugin-factory.d.ts.map +1 -0
  41. package/dist/plugin/logging-plugin-factory.js +112 -0
  42. package/dist/transports/console-transport.d.ts +16 -0
  43. package/dist/transports/console-transport.d.ts.map +1 -0
  44. package/dist/transports/console-transport.js +40 -0
  45. package/dist/transports/index.d.ts +2 -0
  46. package/dist/transports/index.d.ts.map +1 -0
  47. package/dist/transports/index.js +1 -0
  48. package/dist/utils/console-interceptor.d.ts +36 -0
  49. package/dist/utils/console-interceptor.d.ts.map +1 -0
  50. package/dist/utils/console-interceptor.js +105 -0
  51. package/dist/utils/event-emitter.d.ts +11 -0
  52. package/dist/utils/event-emitter.d.ts.map +1 -0
  53. package/dist/utils/event-emitter.js +39 -0
  54. package/dist/utils/index.d.ts +3 -0
  55. package/dist/utils/index.d.ts.map +1 -0
  56. package/dist/utils/index.js +2 -0
  57. package/package.json +54 -0
@@ -0,0 +1,255 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { ContextLogger } from './context-logger.js';
11
+ import { EventEmitter } from '../utils/event-emitter.js';
12
+ /**
13
+ * Central log manager implementation
14
+ *
15
+ * Manages transports, creates loggers, and dispatches log entries.
16
+ */
17
+ export class LogManager {
18
+ constructor(config = {}) {
19
+ var _a, _b, _c, _d, _e, _f;
20
+ this.transports = new Map();
21
+ this.transportConfigs = new Map();
22
+ this.loggers = new Map();
23
+ this.buffer = [];
24
+ this.eventEmitter = new EventEmitter();
25
+ this.config = {
26
+ globalLevel: (_a = config.globalLevel) !== null && _a !== void 0 ? _a : 2, // LogLevel.INFO
27
+ bufferSize: (_b = config.bufferSize) !== null && _b !== void 0 ? _b : 1000,
28
+ flushInterval: (_c = config.flushInterval) !== null && _c !== void 0 ? _c : 5000,
29
+ defaultTransports: (_d = config.defaultTransports) !== null && _d !== void 0 ? _d : [],
30
+ pluginLevels: (_e = config.pluginLevels) !== null && _e !== void 0 ? _e : {},
31
+ moduleLevels: (_f = config.moduleLevels) !== null && _f !== void 0 ? _f : {},
32
+ };
33
+ if (this.config.flushInterval > 0) {
34
+ this.startFlushTimer();
35
+ }
36
+ }
37
+ registerTransport(transport, config) {
38
+ this.transports.set(transport.id, transport);
39
+ if (config) {
40
+ this.transportConfigs.set(transport.id, Object.assign({ enabled: true }, config));
41
+ }
42
+ else {
43
+ this.transportConfigs.set(transport.id, {
44
+ id: transport.id,
45
+ enabled: true,
46
+ });
47
+ }
48
+ }
49
+ unregisterTransport(id) {
50
+ const transport = this.transports.get(id);
51
+ if (transport && transport.close) {
52
+ transport.close().catch((error) => {
53
+ this.handleTransportError(transport, error);
54
+ });
55
+ }
56
+ this.transports.delete(id);
57
+ this.transportConfigs.delete(id);
58
+ }
59
+ getTransport(id) {
60
+ return this.transports.get(id);
61
+ }
62
+ listTransports() {
63
+ return Array.from(this.transports.values());
64
+ }
65
+ createLogger(context) {
66
+ const level = this.resolveLevel(context);
67
+ return new ContextLogger(this, context, level);
68
+ }
69
+ getLogger(context) {
70
+ const key = this.createCacheKey(context);
71
+ let logger = this.loggers.get(key);
72
+ if (!logger) {
73
+ logger = this.createLogger(context);
74
+ this.loggers.set(key, logger);
75
+ }
76
+ return logger;
77
+ }
78
+ setGlobalLevel(level) {
79
+ this.config.globalLevel = level;
80
+ }
81
+ setPluginLevel(plugin, level) {
82
+ this.config.pluginLevels[plugin] = level;
83
+ }
84
+ setModuleLevel(module, level) {
85
+ this.config.moduleLevels[module] = level;
86
+ }
87
+ flush() {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ const entries = this.buffer.splice(0);
90
+ if (entries.length === 0) {
91
+ return;
92
+ }
93
+ yield Promise.all(entries.map(entry => this.dispatchToTransports(entry)));
94
+ yield Promise.all(Array.from(this.transports.values())
95
+ .filter(t => t.flush)
96
+ .map(t => {
97
+ try {
98
+ return t.flush();
99
+ }
100
+ catch (error) {
101
+ this.handleTransportError(t, error);
102
+ return Promise.resolve();
103
+ }
104
+ }));
105
+ this.eventEmitter.emit('flush', entries.length);
106
+ });
107
+ }
108
+ clearBuffer() {
109
+ this.buffer = [];
110
+ }
111
+ on(event, handler) {
112
+ this.eventEmitter.on(event, handler);
113
+ }
114
+ off(event, handler) {
115
+ this.eventEmitter.off(event, handler);
116
+ }
117
+ dispatch(entry) {
118
+ this.buffer.push(entry);
119
+ this.eventEmitter.emit('log', entry);
120
+ // Immediate dispatch for high-priority logs
121
+ if (entry.level >= 4) { // LogLevel.ERROR
122
+ this.dispatchToTransports(entry).catch(error => {
123
+ console.error('[LogManager] Error dispatching log entry:', error);
124
+ });
125
+ }
126
+ // Flush if buffer is full
127
+ if (this.buffer.length >= this.config.bufferSize) {
128
+ this.flush().catch(error => {
129
+ console.error('[LogManager] Error flushing buffer:', error);
130
+ });
131
+ }
132
+ }
133
+ /**
134
+ * Clean up resources
135
+ */
136
+ destroy() {
137
+ return __awaiter(this, void 0, void 0, function* () {
138
+ if (this.flushTimer) {
139
+ clearInterval(this.flushTimer);
140
+ this.flushTimer = undefined;
141
+ }
142
+ yield this.flush();
143
+ yield Promise.all(Array.from(this.transports.values())
144
+ .filter(t => t.close)
145
+ .map(t => t.close()));
146
+ this.transports.clear();
147
+ this.transportConfigs.clear();
148
+ this.loggers.clear();
149
+ this.eventEmitter.clear();
150
+ });
151
+ }
152
+ dispatchToTransports(entry) {
153
+ return __awaiter(this, void 0, void 0, function* () {
154
+ const promises = [];
155
+ for (const [id, transport] of this.transports) {
156
+ const config = this.transportConfigs.get(id);
157
+ if (!this.shouldDispatch(entry, config, transport)) {
158
+ continue;
159
+ }
160
+ try {
161
+ const result = transport.log(entry);
162
+ if (result instanceof Promise) {
163
+ promises.push(result.catch(error => {
164
+ this.handleTransportError(transport, error);
165
+ }));
166
+ }
167
+ }
168
+ catch (error) {
169
+ this.handleTransportError(transport, error);
170
+ }
171
+ }
172
+ yield Promise.all(promises);
173
+ });
174
+ }
175
+ shouldDispatch(entry, config, transport) {
176
+ var _a;
177
+ if (config && config.enabled === false) {
178
+ return false;
179
+ }
180
+ if ((config === null || config === void 0 ? void 0 : config.minLevel) !== undefined && entry.level < config.minLevel) {
181
+ return false;
182
+ }
183
+ if ((config === null || config === void 0 ? void 0 : config.maxLevel) !== undefined && entry.level > config.maxLevel) {
184
+ return false;
185
+ }
186
+ if ((config === null || config === void 0 ? void 0 : config.plugins) && config.plugins.length > 0) {
187
+ if (!entry.context.plugin || !config.plugins.includes(entry.context.plugin)) {
188
+ return false;
189
+ }
190
+ }
191
+ if ((config === null || config === void 0 ? void 0 : config.modules) && config.modules.length > 0) {
192
+ if (!entry.context.module || !config.modules.includes(entry.context.module)) {
193
+ return false;
194
+ }
195
+ }
196
+ if ((config === null || config === void 0 ? void 0 : config.tags) && config.tags.length > 0) {
197
+ if (!((_a = entry.metadata) === null || _a === void 0 ? void 0 : _a.tags) || !config.tags.some(tag => entry.metadata.tags.includes(tag))) {
198
+ return false;
199
+ }
200
+ }
201
+ if ((config === null || config === void 0 ? void 0 : config.filter) && !config.filter(entry)) {
202
+ return false;
203
+ }
204
+ if ((transport === null || transport === void 0 ? void 0 : transport.shouldLog) && !transport.shouldLog(entry)) {
205
+ return false;
206
+ }
207
+ return true;
208
+ }
209
+ resolveLevel(context) {
210
+ if (context === null || context === void 0 ? void 0 : context.plugin) {
211
+ const pluginLevel = this.config.pluginLevels[context.plugin];
212
+ if (pluginLevel !== undefined) {
213
+ return pluginLevel;
214
+ }
215
+ }
216
+ if (context === null || context === void 0 ? void 0 : context.module) {
217
+ const moduleLevel = this.config.moduleLevels[context.module];
218
+ if (moduleLevel !== undefined) {
219
+ return moduleLevel;
220
+ }
221
+ }
222
+ return this.config.globalLevel;
223
+ }
224
+ createCacheKey(context) {
225
+ if (!context) {
226
+ return '__default__';
227
+ }
228
+ return JSON.stringify({
229
+ plugin: context.plugin,
230
+ module: context.module,
231
+ component: context.component,
232
+ });
233
+ }
234
+ startFlushTimer() {
235
+ this.flushTimer = setInterval(() => {
236
+ this.flush().catch(error => {
237
+ console.error('[LogManager] Error in flush timer:', error);
238
+ });
239
+ }, this.config.flushInterval);
240
+ }
241
+ handleTransportError(transport, error) {
242
+ this.eventEmitter.emit('error', { transport: transport.id, error });
243
+ if (transport.onError) {
244
+ try {
245
+ transport.onError(error);
246
+ }
247
+ catch (handlerError) {
248
+ console.error('[LogManager] Error in transport error handler:', handlerError);
249
+ }
250
+ }
251
+ else {
252
+ console.error(`[LogManager] Transport '${transport.id}' error:`, error);
253
+ }
254
+ }
255
+ }
@@ -0,0 +1,152 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ /**
13
+ * Development formatter with colors and emojis
14
+ *
15
+ * Provides rich, human-readable console output for development.
16
+ */
17
+ export class DevFormatter {
18
+ constructor(config = {}) {
19
+ var _a, _b, _c, _d;
20
+ this.config = config;
21
+ this.config = {
22
+ colors: (_a = config.colors) !== null && _a !== void 0 ? _a : true,
23
+ emojis: (_b = config.emojis) !== null && _b !== void 0 ? _b : true,
24
+ timestamps: (_c = config.timestamps) !== null && _c !== void 0 ? _c : true,
25
+ showContext: (_d = config.showContext) !== null && _d !== void 0 ? _d : true,
26
+ };
27
+ }
28
+ format(entry) {
29
+ const parts = [];
30
+ // Timestamp
31
+ if (this.config.timestamps) {
32
+ parts.push(this.formatTimestamp(entry.timestamp));
33
+ }
34
+ // Level with emoji and color
35
+ parts.push(this.formatLevel(entry.level));
36
+ // Context (plugin/module/component)
37
+ if (this.config.showContext) {
38
+ const context = this.formatContext(entry.context);
39
+ if (context) {
40
+ parts.push(context);
41
+ }
42
+ }
43
+ // Message
44
+ parts.push(entry.message);
45
+ // Metadata
46
+ const metadata = this.formatMetadata(entry.metadata);
47
+ if (metadata) {
48
+ parts.push(metadata);
49
+ }
50
+ return parts.join(' ');
51
+ }
52
+ formatBatch(entries) {
53
+ return entries.map(e => this.format(e)).join('\n');
54
+ }
55
+ formatTimestamp(timestamp) {
56
+ const date = new Date(timestamp);
57
+ const time = date.toISOString().split('T')[1].split('.')[0];
58
+ return this.config.colors ? `\x1b[90m${time}\x1b[0m` : time;
59
+ }
60
+ formatLevel(level) {
61
+ const emoji = this.config.emojis ? this.getLevelEmoji(level) : '';
62
+ const label = this.getLevelLabel(level);
63
+ const colored = this.config.colors ? this.colorize(label, level) : label;
64
+ return emoji ? `${emoji} ${colored}` : colored;
65
+ }
66
+ getLevelEmoji(level) {
67
+ switch (level) {
68
+ case 0: return '🔍'; // TRACE
69
+ case 1: return '🐛'; // DEBUG
70
+ case 2: return 'ℹ️ '; // INFO
71
+ case 3: return '⚠️ '; // WARN
72
+ case 4: return '❌'; // ERROR
73
+ case 5: return '💀'; // FATAL
74
+ default: return '';
75
+ }
76
+ }
77
+ getLevelLabel(level) {
78
+ switch (level) {
79
+ case 0: return 'TRACE';
80
+ case 1: return 'DEBUG';
81
+ case 2: return 'INFO ';
82
+ case 3: return 'WARN ';
83
+ case 4: return 'ERROR';
84
+ case 5: return 'FATAL';
85
+ default: return 'UNKNW';
86
+ }
87
+ }
88
+ colorize(text, level) {
89
+ const colors = {
90
+ 0: '\x1b[90m', // TRACE - Gray
91
+ 1: '\x1b[36m', // DEBUG - Cyan
92
+ 2: '\x1b[32m', // INFO - Green
93
+ 3: '\x1b[33m', // WARN - Yellow
94
+ 4: '\x1b[31m', // ERROR - Red
95
+ 5: '\x1b[35m', // FATAL - Magenta
96
+ };
97
+ const color = colors[level] || '\x1b[0m';
98
+ const reset = '\x1b[0m';
99
+ return `${color}${text}${reset}`;
100
+ }
101
+ formatContext(context) {
102
+ const parts = [];
103
+ if (context.plugin) {
104
+ parts.push(this.config.colors
105
+ ? `\x1b[35m[${context.plugin}]\x1b[0m`
106
+ : `[${context.plugin}]`);
107
+ }
108
+ if (context.module) {
109
+ parts.push(this.config.colors
110
+ ? `\x1b[34m{${context.module}}\x1b[0m`
111
+ : `{${context.module}}`);
112
+ }
113
+ if (context.component) {
114
+ parts.push(this.config.colors
115
+ ? `\x1b[36m<${context.component}>\x1b[0m`
116
+ : `<${context.component}>`);
117
+ }
118
+ if (context.operation) {
119
+ parts.push(this.config.colors
120
+ ? `\x1b[90m(${context.operation})\x1b[0m`
121
+ : `(${context.operation})`);
122
+ }
123
+ return parts.join(' ');
124
+ }
125
+ formatMetadata(metadata) {
126
+ if (!metadata || Object.keys(metadata).length === 0) {
127
+ return '';
128
+ }
129
+ const { error, stack, tags, duration } = metadata, rest = __rest(metadata, ["error", "stack", "tags", "duration"]);
130
+ const parts = [];
131
+ // Duration
132
+ if (duration !== undefined) {
133
+ const color = this.config.colors ? '\x1b[33m' : '';
134
+ const reset = this.config.colors ? '\x1b[0m' : '';
135
+ parts.push(`${color}⏱ ${duration}ms${reset}`);
136
+ }
137
+ // Tags
138
+ if (tags && tags.length > 0) {
139
+ const tagString = tags.map(t => `#${t}`).join(' ');
140
+ const color = this.config.colors ? '\x1b[90m' : '';
141
+ const reset = this.config.colors ? '\x1b[0m' : '';
142
+ parts.push(`${color}${tagString}${reset}`);
143
+ }
144
+ // Other metadata
145
+ if (Object.keys(rest).length > 0) {
146
+ const color = this.config.colors ? '\x1b[90m' : '';
147
+ const reset = this.config.colors ? '\x1b[0m' : '';
148
+ parts.push(`${color}${JSON.stringify(rest)}${reset}`);
149
+ }
150
+ return parts.length > 0 ? parts.join(' ') : '';
151
+ }
152
+ }
@@ -0,0 +1,2 @@
1
+ export * from './dev-formatter.js';
2
+ export * from './json-formatter.js';
@@ -0,0 +1,69 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ /**
13
+ * JSON formatter for structured logging
14
+ *
15
+ * Outputs logs as JSON for easy parsing by log aggregation tools.
16
+ */
17
+ export class JsonFormatter {
18
+ constructor(config = {}) {
19
+ var _a, _b;
20
+ this.config = config;
21
+ this.config = Object.assign({ pretty: (_a = config.pretty) !== null && _a !== void 0 ? _a : false, includeStack: (_b = config.includeStack) !== null && _b !== void 0 ? _b : true }, config);
22
+ }
23
+ format(entry) {
24
+ const logObject = this.toObject(entry);
25
+ return this.config.pretty
26
+ ? JSON.stringify(logObject, null, 2)
27
+ : JSON.stringify(logObject);
28
+ }
29
+ formatBatch(entries) {
30
+ const logObjects = entries.map(e => this.toObject(e));
31
+ return this.config.pretty
32
+ ? JSON.stringify(logObjects, null, 2)
33
+ : JSON.stringify(logObjects);
34
+ }
35
+ toObject(entry) {
36
+ const obj = {
37
+ timestamp: entry.timestamp,
38
+ level: this.getLevelName(entry.level),
39
+ message: entry.message,
40
+ };
41
+ // Add context
42
+ if (entry.context && Object.keys(entry.context).length > 0) {
43
+ obj.context = entry.context;
44
+ }
45
+ // Add metadata
46
+ if (entry.metadata) {
47
+ const _a = entry.metadata, { error, stack } = _a, rest = __rest(_a, ["error", "stack"]);
48
+ if (Object.keys(rest).length > 0) {
49
+ obj.metadata = rest;
50
+ }
51
+ // Handle error separately
52
+ if (error) {
53
+ obj.error = Object.assign({ name: error.name, message: error.message }, (this.config.includeStack && stack ? { stack } : {}));
54
+ }
55
+ }
56
+ return obj;
57
+ }
58
+ getLevelName(level) {
59
+ switch (level) {
60
+ case 0: return 'TRACE';
61
+ case 1: return 'DEBUG';
62
+ case 2: return 'INFO';
63
+ case 3: return 'WARN';
64
+ case 4: return 'ERROR';
65
+ case 5: return 'FATAL';
66
+ default: return 'UNKNOWN';
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @hamak/logging-impl
3
+ *
4
+ * Core implementation of the pluggable logging system.
5
+ * Provides LogManager, ContextLogger, transports, and formatters.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ // Export core implementations
10
+ export * from './core/index.js';
11
+ // Export transports
12
+ export * from './transports/index.js';
13
+ // Export formatters
14
+ export * from './formatters/index.js';
15
+ // Export plugin factory
16
+ export * from './plugin/index.js';
17
+ // Export utilities
18
+ export * from './utils/index.js';
19
+ export { LOG_MANAGER_TOKEN, LOGGER_TOKEN, LOG_CONFIG_TOKEN, } from '@hamak/logging-api';
@@ -0,0 +1 @@
1
+ export * from './logging-plugin-factory.js';
@@ -0,0 +1,118 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { LOG_MANAGER_TOKEN, LOGGER_TOKEN, LOG_CONFIG_TOKEN } from '@hamak/logging-api';
11
+ import { LogManager } from '../core/log-manager.js';
12
+ import { ConsoleTransport } from '../transports/console-transport.js';
13
+ import { DevFormatter } from '../formatters/dev-formatter.js';
14
+ import { JsonFormatter } from '../formatters/json-formatter.js';
15
+ import { ConsoleInterceptor } from '../utils/console-interceptor.js';
16
+ /**
17
+ * Create a logging plugin for the microkernel
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { createLoggingPlugin } from '@hamak/logging-impl';
22
+ *
23
+ * const loggingPlugin = createLoggingPlugin({
24
+ * globalLevel: LogLevel.DEBUG,
25
+ * pluginLevels: {
26
+ * 'my-plugin': LogLevel.TRACE
27
+ * }
28
+ * });
29
+ *
30
+ * const host = createHost({
31
+ * plugins: [loggingPlugin, myPlugin]
32
+ * });
33
+ * ```
34
+ */
35
+ export function createLoggingPlugin(config = {}) {
36
+ let logManager;
37
+ let rootLogger;
38
+ let consoleInterceptor;
39
+ // Determine environment
40
+ const isDevelopment = typeof process !== 'undefined'
41
+ ? process.env.NODE_ENV === 'development'
42
+ : true;
43
+ const defaultConfig = Object.assign({ globalLevel: isDevelopment ? 1 : 2, bufferSize: 1000, flushInterval: 5000, devFormatter: isDevelopment, interceptConsole: true, pluginLevels: {}, moduleLevels: {} }, config);
44
+ return {
45
+ initialize(ctx) {
46
+ return __awaiter(this, void 0, void 0, function* () {
47
+ // Create log manager
48
+ logManager = new LogManager(defaultConfig);
49
+ rootLogger = logManager.createLogger({ plugin: 'logging', module: 'plugin' });
50
+ // Register console transport
51
+ const formatter = defaultConfig.devFormatter
52
+ ? new DevFormatter({
53
+ colors: true,
54
+ emojis: true,
55
+ timestamps: true,
56
+ showContext: true,
57
+ })
58
+ : new JsonFormatter({ pretty: isDevelopment });
59
+ logManager.registerTransport(new ConsoleTransport(formatter), {
60
+ id: 'console',
61
+ enabled: true,
62
+ minLevel: defaultConfig.globalLevel,
63
+ });
64
+ // Register services via DI
65
+ ctx.provide({ provide: LOG_MANAGER_TOKEN, useValue: logManager });
66
+ ctx.provide({ provide: LOG_CONFIG_TOKEN, useValue: defaultConfig });
67
+ // Provide logger factory
68
+ ctx.provide({
69
+ provide: LOGGER_TOKEN,
70
+ useFactory: (pluginName) => {
71
+ return logManager.createLogger({ plugin: pluginName });
72
+ },
73
+ deps: [],
74
+ });
75
+ rootLogger.info('Logging plugin initialized', {
76
+ globalLevel: defaultConfig.globalLevel,
77
+ formatter: defaultConfig.devFormatter ? 'dev' : 'json',
78
+ tags: ['initialization'],
79
+ });
80
+ });
81
+ },
82
+ activate(ctx) {
83
+ return __awaiter(this, void 0, void 0, function* () {
84
+ // Bridge microkernel events to logging
85
+ ctx.hooks.on('plugin:error', ({ plugin, error }) => {
86
+ const logger = logManager.createLogger({ plugin });
87
+ logger.error('Plugin error', error);
88
+ });
89
+ ctx.hooks.on('host:activated', () => {
90
+ rootLogger.info('Microkernel host activated', { tags: ['lifecycle'] });
91
+ });
92
+ // Intercept console methods if enabled
93
+ if (defaultConfig.interceptConsole) {
94
+ consoleInterceptor = new ConsoleInterceptor(logManager);
95
+ consoleInterceptor.intercept();
96
+ rootLogger.debug('Console interception enabled', { tags: ['console'] });
97
+ }
98
+ // Emit logging ready event
99
+ ctx.hooks.emit('logging:ready', { logManager });
100
+ rootLogger.info('Logging plugin activated', {
101
+ tags: ['lifecycle'],
102
+ interceptConsole: defaultConfig.interceptConsole,
103
+ });
104
+ });
105
+ },
106
+ deactivate() {
107
+ return __awaiter(this, void 0, void 0, function* () {
108
+ rootLogger.info('Logging plugin deactivating', { tags: ['lifecycle'] });
109
+ // Restore original console methods
110
+ if (consoleInterceptor) {
111
+ consoleInterceptor.restore();
112
+ rootLogger.debug('Console interception disabled', { tags: ['console'] });
113
+ }
114
+ yield logManager.destroy();
115
+ });
116
+ },
117
+ };
118
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Console transport
3
+ *
4
+ * Outputs logs to the browser console or Node.js console.
5
+ * Supports formatting via pluggable formatters.
6
+ */
7
+ export class ConsoleTransport {
8
+ constructor(formatter) {
9
+ this.formatter = formatter;
10
+ this.id = 'console';
11
+ this.name = 'Console Transport';
12
+ }
13
+ log(entry) {
14
+ var _a;
15
+ const formatted = this.formatter.format(entry);
16
+ switch (entry.level) {
17
+ case 0: // TRACE
18
+ case 1: // DEBUG
19
+ console.debug(formatted);
20
+ break;
21
+ case 2: // INFO
22
+ console.info(formatted);
23
+ break;
24
+ case 3: // WARN
25
+ console.warn(formatted);
26
+ break;
27
+ case 4: // ERROR
28
+ case 5: // FATAL
29
+ console.error(formatted);
30
+ if ((_a = entry.metadata) === null || _a === void 0 ? void 0 : _a.error) {
31
+ console.error(entry.metadata.error);
32
+ }
33
+ break;
34
+ default:
35
+ console.log(formatted);
36
+ }
37
+ }
38
+ onError(error) {
39
+ console.error('[ConsoleTransport] Error:', error);
40
+ }
41
+ }
@@ -0,0 +1 @@
1
+ export * from './console-transport.js';