@hkdigital/lib-sveltekit 0.2.13 → 0.2.15
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/dist/classes/logging/Logger.d.ts +21 -17
- package/dist/classes/logging/Logger.js +59 -40
- package/dist/classes/logging/constants.d.ts +0 -2
- package/dist/classes/logging/constants.js +0 -2
- package/dist/classes/services/ServiceManager.d.ts +3 -3
- package/dist/classes/services/ServiceManager.js +8 -3
- package/dist/classes/services/index.d.ts +4 -0
- package/dist/classes/services/index.js +5 -0
- package/dist/classes/services/service-states.d.ts +5 -0
- package/dist/classes/services/service-states.js +6 -0
- package/dist/classes/services/typedef.d.ts +83 -40
- package/dist/classes/services/typedef.js +24 -11
- package/dist/logging/adapters/console.d.ts +47 -0
- package/dist/logging/adapters/console.js +113 -0
- package/dist/logging/adapters/pino.d.ts +25 -0
- package/dist/logging/adapters/pino.js +60 -0
- package/dist/logging/constants.d.ts +1 -0
- package/dist/logging/constants.js +1 -0
- package/dist/logging/factories/client.d.ts +10 -0
- package/dist/logging/factories/client.js +21 -0
- package/dist/logging/factories/server.d.ts +10 -0
- package/dist/logging/factories/server.js +22 -0
- package/dist/logging/factories/universal.d.ts +9 -0
- package/dist/logging/factories/universal.js +23 -0
- package/dist/logging/index.d.ts +4 -0
- package/dist/logging/index.js +7 -0
- package/package.json +1 -1
@@ -8,28 +8,18 @@ export default class Logger extends EventEmitter {
|
|
8
8
|
*
|
9
9
|
* @param {string} name - Name of the service/component for this logger
|
10
10
|
* @param {string} [defaultLevel=INFO] - Initial log level threshold
|
11
|
+
* @param {Object} [context={}] - Default context data for all logs
|
11
12
|
*/
|
12
|
-
constructor(name: string, defaultLevel?: string);
|
13
|
+
constructor(name: string, defaultLevel?: string, context?: any);
|
13
14
|
name: string;
|
14
15
|
level: string;
|
15
16
|
/**
|
16
17
|
* Set the minimum log level threshold
|
17
18
|
*
|
18
|
-
* @param {string} level - New log level (DEBUG, INFO, WARN, ERROR
|
19
|
-
* or NONE)
|
19
|
+
* @param {string} level - New log level (DEBUG, INFO, WARN, ERROR or NONE)
|
20
20
|
* @returns {boolean} True if level was valid and set, false otherwise
|
21
21
|
*/
|
22
22
|
setLevel(level: string): boolean;
|
23
|
-
/**
|
24
|
-
* Internal logging method
|
25
|
-
*
|
26
|
-
* @param {string} level - Log level
|
27
|
-
* @param {string} message - Log message
|
28
|
-
* @param {*} [details] - Additional details to include in the log
|
29
|
-
* @returns {boolean} True if the log was emitted, false if filtered
|
30
|
-
* @private
|
31
|
-
*/
|
32
|
-
private _log;
|
33
23
|
/**
|
34
24
|
* Log a debug message
|
35
25
|
*
|
@@ -63,12 +53,26 @@ export default class Logger extends EventEmitter {
|
|
63
53
|
*/
|
64
54
|
error(message: string, details?: any): boolean;
|
65
55
|
/**
|
66
|
-
*
|
56
|
+
* Create a child logger with additional context
|
57
|
+
*
|
58
|
+
* @param {string} namespace
|
59
|
+
* Namespace of the context (needed for chaining contexts)
|
60
|
+
*
|
61
|
+
* @param {Object} additionalContext - Additional context data
|
67
62
|
*
|
63
|
+
* @returns {Logger} New logger instance with merged context
|
64
|
+
*/
|
65
|
+
context(namespace: string, additionalContext: any): Logger;
|
66
|
+
/**
|
67
|
+
* Internal logging method
|
68
|
+
*
|
69
|
+
* @param {string} level - Log level
|
68
70
|
* @param {string} message - Log message
|
69
|
-
* @param {*} [details] - Additional details
|
70
|
-
* @returns {boolean} True if the log was emitted
|
71
|
+
* @param {*} [details] - Additional details to include in the log
|
72
|
+
* @returns {boolean} True if the log was emitted, false if filtered
|
73
|
+
* @private
|
71
74
|
*/
|
72
|
-
|
75
|
+
private _log;
|
76
|
+
#private;
|
73
77
|
}
|
74
78
|
import { EventEmitter } from '../events';
|
@@ -34,30 +34,36 @@
|
|
34
34
|
|
35
35
|
import { EventEmitter } from '../events';
|
36
36
|
|
37
|
-
import { DEBUG, INFO, WARN, ERROR,
|
37
|
+
import { DEBUG, INFO, WARN, ERROR, LEVELS } from './constants.js';
|
38
38
|
|
39
39
|
/**
|
40
40
|
* Logger class for consistent logging across services
|
41
41
|
* @extends EventEmitter
|
42
42
|
*/
|
43
43
|
export default class Logger extends EventEmitter {
|
44
|
+
#defaultContext;
|
45
|
+
#hasContext;
|
46
|
+
|
44
47
|
/**
|
45
48
|
* Create a new Logger instance
|
46
49
|
*
|
47
50
|
* @param {string} name - Name of the service/component for this logger
|
48
51
|
* @param {string} [defaultLevel=INFO] - Initial log level threshold
|
52
|
+
* @param {Object} [context={}] - Default context data for all logs
|
49
53
|
*/
|
50
|
-
constructor(name, defaultLevel = INFO) {
|
54
|
+
constructor(name, defaultLevel = INFO, context = {}) {
|
51
55
|
super();
|
52
56
|
this.name = name;
|
53
57
|
this.level = defaultLevel;
|
58
|
+
|
59
|
+
this.#defaultContext = structuredClone(context);
|
60
|
+
this.#hasContext = Object.keys(this.#defaultContext).length > 0;
|
54
61
|
}
|
55
62
|
|
56
63
|
/**
|
57
64
|
* Set the minimum log level threshold
|
58
65
|
*
|
59
|
-
* @param {string} level - New log level (DEBUG, INFO, WARN, ERROR
|
60
|
-
* or NONE)
|
66
|
+
* @param {string} level - New log level (DEBUG, INFO, WARN, ERROR or NONE)
|
61
67
|
* @returns {boolean} True if level was valid and set, false otherwise
|
62
68
|
*/
|
63
69
|
setLevel(level) {
|
@@ -70,37 +76,6 @@ export default class Logger extends EventEmitter {
|
|
70
76
|
return false;
|
71
77
|
}
|
72
78
|
|
73
|
-
/**
|
74
|
-
* Internal logging method
|
75
|
-
*
|
76
|
-
* @param {string} level - Log level
|
77
|
-
* @param {string} message - Log message
|
78
|
-
* @param {*} [details] - Additional details to include in the log
|
79
|
-
* @returns {boolean} True if the log was emitted, false if filtered
|
80
|
-
* @private
|
81
|
-
*/
|
82
|
-
_log(level, message, details) {
|
83
|
-
// Check if this log level should be filtered
|
84
|
-
if (LEVELS[level] < LEVELS[this.level]) {
|
85
|
-
return false; // Below threshold, don't emit
|
86
|
-
}
|
87
|
-
|
88
|
-
const timestamp = new Date();
|
89
|
-
const logEvent = {
|
90
|
-
timestamp,
|
91
|
-
service: this.name,
|
92
|
-
level,
|
93
|
-
message,
|
94
|
-
details
|
95
|
-
};
|
96
|
-
|
97
|
-
// Emit as both specific level event and generic 'log' event
|
98
|
-
this.emit(level, logEvent);
|
99
|
-
this.emit('log', logEvent);
|
100
|
-
|
101
|
-
return true;
|
102
|
-
}
|
103
|
-
|
104
79
|
/**
|
105
80
|
* Log a debug message
|
106
81
|
*
|
@@ -146,13 +121,57 @@ export default class Logger extends EventEmitter {
|
|
146
121
|
}
|
147
122
|
|
148
123
|
/**
|
149
|
-
*
|
124
|
+
* Create a child logger with additional context
|
125
|
+
*
|
126
|
+
* @param {string} namespace
|
127
|
+
* Namespace of the context (needed for chaining contexts)
|
150
128
|
*
|
129
|
+
* @param {Object} additionalContext - Additional context data
|
130
|
+
*
|
131
|
+
* @returns {Logger} New logger instance with merged context
|
132
|
+
*/
|
133
|
+
context(namespace, additionalContext) {
|
134
|
+
if( typeof namespace !== "string" ) {
|
135
|
+
throw new Error('Invalid namespace');
|
136
|
+
}
|
137
|
+
|
138
|
+
const mergedContext = {
|
139
|
+
...this.#defaultContext,
|
140
|
+
[namespace]: additionalContext
|
141
|
+
};
|
142
|
+
|
143
|
+
return new Logger(this.name, this.level, mergedContext);
|
144
|
+
}
|
145
|
+
|
146
|
+
/**
|
147
|
+
* Internal logging method
|
148
|
+
*
|
149
|
+
* @param {string} level - Log level
|
151
150
|
* @param {string} message - Log message
|
152
|
-
* @param {*} [details] - Additional details
|
153
|
-
* @returns {boolean} True if the log was emitted
|
151
|
+
* @param {*} [details] - Additional details to include in the log
|
152
|
+
* @returns {boolean} True if the log was emitted, false if filtered
|
153
|
+
* @private
|
154
154
|
*/
|
155
|
-
|
156
|
-
|
155
|
+
_log(level, message, details) {
|
156
|
+
// Check if this log level should be filtered
|
157
|
+
if (LEVELS[level] < LEVELS[this.level]) {
|
158
|
+
return false; // Below threshold, don't emit
|
159
|
+
}
|
160
|
+
|
161
|
+
const timestamp = new Date();
|
162
|
+
const logEvent = {
|
163
|
+
timestamp,
|
164
|
+
service: this.name,
|
165
|
+
level,
|
166
|
+
message,
|
167
|
+
context: this.#hasContext ? this.#defaultContext : null,
|
168
|
+
details
|
169
|
+
};
|
170
|
+
|
171
|
+
// Emit as both specific level event and generic 'log' event
|
172
|
+
this.emit(level, logEvent);
|
173
|
+
this.emit('log', logEvent);
|
174
|
+
|
175
|
+
return true;
|
157
176
|
}
|
158
177
|
}
|
@@ -2,13 +2,11 @@ export const DEBUG: "debug";
|
|
2
2
|
export const INFO: "info";
|
3
3
|
export const WARN: "warn";
|
4
4
|
export const ERROR: "error";
|
5
|
-
export const FATAL: "fatal";
|
6
5
|
export const NONE: "none";
|
7
6
|
export namespace LEVELS {
|
8
7
|
let debug: number;
|
9
8
|
let info: number;
|
10
9
|
let warn: number;
|
11
10
|
let error: number;
|
12
|
-
let fatal: number;
|
13
11
|
let none: number;
|
14
12
|
}
|
@@ -4,7 +4,6 @@ export const DEBUG = 'debug';
|
|
4
4
|
export const INFO = 'info';
|
5
5
|
export const WARN = 'warn';
|
6
6
|
export const ERROR = 'error';
|
7
|
-
export const FATAL = 'fatal';
|
8
7
|
export const NONE = 'none';
|
9
8
|
|
10
9
|
// Level values for filtering (higher = more important)
|
@@ -13,6 +12,5 @@ export const LEVELS = {
|
|
13
12
|
[INFO]: 2,
|
14
13
|
[WARN]: 3,
|
15
14
|
[ERROR]: 4,
|
16
|
-
[FATAL]: 5,
|
17
15
|
[NONE]: 6
|
18
16
|
};
|
@@ -40,10 +40,10 @@ export class ServiceManager extends EventEmitter {
|
|
40
40
|
*
|
41
41
|
* @param {string} name - Service name
|
42
42
|
*
|
43
|
-
* @returns {import('./typedef.js').
|
43
|
+
* @returns {import('./typedef.js').ServiceInstance|null}
|
44
44
|
* Service instance or null if not found
|
45
45
|
*/
|
46
|
-
get(name: string): import("./typedef.js").
|
46
|
+
get(name: string): import("./typedef.js").ServiceInstance | null;
|
47
47
|
/**
|
48
48
|
* Initialize a service
|
49
49
|
*
|
@@ -153,7 +153,7 @@ export class ServiceManager extends EventEmitter {
|
|
153
153
|
*
|
154
154
|
* @private
|
155
155
|
* @param {string} name - Service name
|
156
|
-
* @param {import('./typedef.js').
|
156
|
+
* @param {import('./typedef.js').ServiceInstance} instance
|
157
157
|
* Service instance
|
158
158
|
*/
|
159
159
|
private _attachServiceEvents;
|
@@ -67,6 +67,7 @@ import { EventEmitter } from '../events';
|
|
67
67
|
import { Logger, DEBUG, INFO, WARN } from '../logging';
|
68
68
|
|
69
69
|
import {
|
70
|
+
NOT_CREATED,
|
70
71
|
CREATED,
|
71
72
|
RUNNING,
|
72
73
|
DESTROYED
|
@@ -147,6 +148,7 @@ export class ServiceManager extends EventEmitter {
|
|
147
148
|
});
|
148
149
|
|
149
150
|
this.services.set(name, entry);
|
151
|
+
|
150
152
|
this.logger.debug(`Registered service '${name}'`, {
|
151
153
|
dependencies: entry.dependencies,
|
152
154
|
tags: entry.tags
|
@@ -158,7 +160,7 @@ export class ServiceManager extends EventEmitter {
|
|
158
160
|
*
|
159
161
|
* @param {string} name - Service name
|
160
162
|
*
|
161
|
-
* @returns {import('./typedef.js').
|
163
|
+
* @returns {import('./typedef.js').ServiceInstance|null}
|
162
164
|
* Service instance or null if not found
|
163
165
|
*/
|
164
166
|
get(name) {
|
@@ -223,7 +225,9 @@ export class ServiceManager extends EventEmitter {
|
|
223
225
|
// Start dependencies first
|
224
226
|
for (const dep of entry.dependencies) {
|
225
227
|
if (!await this.isRunning(dep)) {
|
228
|
+
|
226
229
|
this.logger.debug(`Starting dependency '${dep}' for '${name}'`);
|
230
|
+
|
227
231
|
const started = await this.startService(dep);
|
228
232
|
if (!started) {
|
229
233
|
this.logger.error(
|
@@ -408,6 +412,7 @@ export class ServiceManager extends EventEmitter {
|
|
408
412
|
* @returns {Promise<HealthCheckResult>} Health status for all services
|
409
413
|
*/
|
410
414
|
async checkHealth() {
|
415
|
+
/** @type {HealthCheckResult} */
|
411
416
|
const health = {};
|
412
417
|
|
413
418
|
for (const [name, entry] of this.services) {
|
@@ -416,7 +421,7 @@ export class ServiceManager extends EventEmitter {
|
|
416
421
|
} else {
|
417
422
|
health[name] = {
|
418
423
|
name,
|
419
|
-
state:
|
424
|
+
state: NOT_CREATED,
|
420
425
|
healthy: false
|
421
426
|
};
|
422
427
|
}
|
@@ -540,7 +545,7 @@ export class ServiceManager extends EventEmitter {
|
|
540
545
|
*
|
541
546
|
* @private
|
542
547
|
* @param {string} name - Service name
|
543
|
-
* @param {import('./typedef.js').
|
548
|
+
* @param {import('./typedef.js').ServiceInstance} instance
|
544
549
|
* Service instance
|
545
550
|
*/
|
546
551
|
_attachServiceEvents(name, instance) {
|
@@ -69,6 +69,11 @@ export function isInactive(state: string): boolean;
|
|
69
69
|
* break;
|
70
70
|
* }
|
71
71
|
*/
|
72
|
+
/**
|
73
|
+
* Service has not been created yet
|
74
|
+
* @const {string}
|
75
|
+
*/
|
76
|
+
export const NOT_CREATED: "not-created";
|
72
77
|
/**
|
73
78
|
* Service has been created but not initialized
|
74
79
|
* @const {string}
|
@@ -1,40 +1,12 @@
|
|
1
1
|
/**
|
2
|
-
*
|
2
|
+
* Service configuration object passed to service initialization
|
3
3
|
*/
|
4
|
-
export type ServiceConfig =
|
5
|
-
/**
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
*
|
11
|
-
* async _healthCheck() {
|
12
|
-
* // Return type is HealthStatus
|
13
|
-
* return { latency: 10 };
|
14
|
-
* }
|
15
|
-
* }
|
16
|
-
*/
|
17
|
-
export type HealthStatus = import("./typedef.js").HealthStatus;
|
18
|
-
/**
|
19
|
-
* //
|
20
|
-
*/
|
21
|
-
export type ServiceManagerConfig = import("./typedef.js").ServiceManagerConfig;
|
22
|
-
/**
|
23
|
-
* const config = {
|
24
|
-
* environment: 'development',
|
25
|
-
* stopTimeout: 5000
|
26
|
-
* };
|
27
|
-
*
|
28
|
-
* const manager = new ServiceManager(config);
|
29
|
-
*
|
30
|
-
* const options = {
|
31
|
-
* dependencies: ['database'],
|
32
|
-
* tags: ['critical']
|
33
|
-
* };
|
34
|
-
*
|
35
|
-
* manager.register('auth', AuthService, {}, options);
|
36
|
-
*/
|
37
|
-
export type ServiceRegistrationOptions = import("./typedef.js").ServiceRegistrationOptions;
|
4
|
+
export type ServiceConfig = {
|
5
|
+
/**
|
6
|
+
* - Service-specific configuration properties
|
7
|
+
*/
|
8
|
+
key?: any;
|
9
|
+
};
|
38
10
|
/**
|
39
11
|
* Options for creating a service instance
|
40
12
|
*/
|
@@ -61,6 +33,35 @@ export type StopOptions = {
|
|
61
33
|
*/
|
62
34
|
force?: boolean;
|
63
35
|
};
|
36
|
+
/**
|
37
|
+
* Health status returned by service health checks
|
38
|
+
*/
|
39
|
+
export type HealthStatus = {
|
40
|
+
/**
|
41
|
+
* - Service name
|
42
|
+
*/
|
43
|
+
name: string;
|
44
|
+
/**
|
45
|
+
* - Current service state
|
46
|
+
*/
|
47
|
+
state: string;
|
48
|
+
/**
|
49
|
+
* - Whether the service is healthy
|
50
|
+
*/
|
51
|
+
healthy: boolean;
|
52
|
+
/**
|
53
|
+
* - Error message if unhealthy
|
54
|
+
*/
|
55
|
+
error?: string;
|
56
|
+
/**
|
57
|
+
* - Error from health check itself
|
58
|
+
*/
|
59
|
+
checkError?: string;
|
60
|
+
/**
|
61
|
+
* - Additional health check properties
|
62
|
+
*/
|
63
|
+
key?: any;
|
64
|
+
};
|
64
65
|
/**
|
65
66
|
* Event emitted when service state changes
|
66
67
|
*/
|
@@ -111,7 +112,49 @@ export type ServiceErrorEvent = {
|
|
111
112
|
/**
|
112
113
|
* Service class constructor type
|
113
114
|
*/
|
114
|
-
export type ServiceConstructor = new (name: string, options?: ServiceOptions) =>
|
115
|
+
export type ServiceConstructor = new (name: string, options?: ServiceOptions) => ServiceInstance;
|
116
|
+
/**
|
117
|
+
* Options for registering a service
|
118
|
+
*/
|
119
|
+
export type ServiceRegistrationOptions = {
|
120
|
+
/**
|
121
|
+
* - Services this service depends on
|
122
|
+
*/
|
123
|
+
dependencies?: string[];
|
124
|
+
/**
|
125
|
+
* - Tags for grouping services
|
126
|
+
*/
|
127
|
+
tags?: string[];
|
128
|
+
/**
|
129
|
+
* - Startup priority (higher starts first)
|
130
|
+
*/
|
131
|
+
priority?: number;
|
132
|
+
};
|
133
|
+
/**
|
134
|
+
* Configuration for ServiceManager
|
135
|
+
*/
|
136
|
+
export type ServiceManagerConfig = {
|
137
|
+
/**
|
138
|
+
* - Debug mode switch
|
139
|
+
*/
|
140
|
+
debug?: boolean;
|
141
|
+
/**
|
142
|
+
* - Auto-start services on registration
|
143
|
+
*/
|
144
|
+
autoStart?: boolean;
|
145
|
+
/**
|
146
|
+
* - Default timeout for stopping services
|
147
|
+
*/
|
148
|
+
stopTimeout?: number;
|
149
|
+
/**
|
150
|
+
* - Initial log level for ServiceManager
|
151
|
+
*/
|
152
|
+
logLevel?: string;
|
153
|
+
/**
|
154
|
+
* - Logging configuration
|
155
|
+
*/
|
156
|
+
logConfig?: LogConfig;
|
157
|
+
};
|
115
158
|
/**
|
116
159
|
* Logging configuration
|
117
160
|
*/
|
@@ -142,7 +185,7 @@ export type ServiceEntry = {
|
|
142
185
|
/**
|
143
186
|
* - Service instance (lazy-created)
|
144
187
|
*/
|
145
|
-
instance:
|
188
|
+
instance: ServiceInstance | null;
|
146
189
|
/**
|
147
190
|
* - Service configuration
|
148
191
|
*/
|
@@ -168,12 +211,12 @@ export type ServiceEntry = {
|
|
168
211
|
* Result of health check for all services
|
169
212
|
*/
|
170
213
|
export type HealthCheckResult = {
|
171
|
-
[x: string]:
|
214
|
+
[x: string]: HealthStatus;
|
172
215
|
};
|
173
216
|
/**
|
174
217
|
* Base class interface that services must implement
|
175
218
|
*/
|
176
|
-
export type
|
219
|
+
export type ServiceInstance = {
|
177
220
|
/**
|
178
221
|
* - Service name
|
179
222
|
*/
|
@@ -193,7 +236,7 @@ export type ServiceBase = {
|
|
193
236
|
/**
|
194
237
|
* - Service logger
|
195
238
|
*/
|
196
|
-
logger: Logger;
|
239
|
+
logger: import("../logging").Logger;
|
197
240
|
initialize: (config?: ServiceConfig) => Promise<boolean>;
|
198
241
|
start: () => Promise<boolean>;
|
199
242
|
stop: (options?: StopOptions) => Promise<boolean>;
|
@@ -9,8 +9,8 @@
|
|
9
9
|
* // In your service implementation
|
10
10
|
* import { ServiceBase } from './ServiceBase.js';
|
11
11
|
*
|
12
|
-
* // @typedef {import('./typedef.js').ServiceConfig} ServiceConfig
|
13
|
-
* // @typedef {import('./typedef.js').HealthStatus} HealthStatus
|
12
|
+
* // @ typedef {import('./typedef.js').ServiceConfig} ServiceConfig
|
13
|
+
* // @ typedef {import('./typedef.js').HealthStatus} HealthStatus
|
14
14
|
*
|
15
15
|
* class MyService extends ServiceBase {
|
16
16
|
* async _init(config) {
|
@@ -27,8 +27,8 @@
|
|
27
27
|
* // When using ServiceManager
|
28
28
|
* import { ServiceManager } from './ServiceManager.js';
|
29
29
|
*
|
30
|
-
* // @typedef {import('./typedef.js').ServiceManagerConfig} ServiceManagerConfig
|
31
|
-
* // @typedef {import('./typedef.js').ServiceRegistrationOptions} ServiceRegistrationOptions
|
30
|
+
* // @ typedef {import('./typedef.js').ServiceManagerConfig} ServiceManagerConfig
|
31
|
+
* // @ typedef {import('./typedef.js').ServiceRegistrationOptions} ServiceRegistrationOptions
|
32
32
|
*
|
33
33
|
* const config = {
|
34
34
|
* environment: 'development',
|
@@ -47,12 +47,14 @@
|
|
47
47
|
|
48
48
|
/**
|
49
49
|
* Service configuration object passed to service initialization
|
50
|
+
*
|
50
51
|
* @typedef {Object} ServiceConfig
|
51
|
-
* @property {*} [
|
52
|
+
* @property {*} [key] - Service-specific configuration properties
|
52
53
|
*/
|
53
54
|
|
54
55
|
/**
|
55
56
|
* Options for creating a service instance
|
57
|
+
*
|
56
58
|
* @typedef {Object} ServiceOptions
|
57
59
|
* @property {string} [logLevel] - Initial log level for the service
|
58
60
|
* @property {number} [shutdownTimeout=5000] - Timeout for graceful shutdown
|
@@ -60,6 +62,7 @@
|
|
60
62
|
|
61
63
|
/**
|
62
64
|
* Options for stopping a service
|
65
|
+
*
|
63
66
|
* @typedef {Object} StopOptions
|
64
67
|
* @property {number} [timeout] - Override shutdown timeout
|
65
68
|
* @property {boolean} [force=false] - Force stop even if timeout exceeded
|
@@ -67,17 +70,19 @@
|
|
67
70
|
|
68
71
|
/**
|
69
72
|
* Health status returned by service health checks
|
73
|
+
*
|
70
74
|
* @typedef {Object} HealthStatus
|
71
75
|
* @property {string} name - Service name
|
72
76
|
* @property {string} state - Current service state
|
73
77
|
* @property {boolean} healthy - Whether the service is healthy
|
74
78
|
* @property {string} [error] - Error message if unhealthy
|
75
79
|
* @property {string} [checkError] - Error from health check itself
|
76
|
-
* @property {*} [
|
80
|
+
* @property {*} [key] - Additional health check properties
|
77
81
|
*/
|
78
82
|
|
79
83
|
/**
|
80
84
|
* Event emitted when service state changes
|
85
|
+
*
|
81
86
|
* @typedef {Object} StateChangeEvent
|
82
87
|
* @property {string} service - Service name
|
83
88
|
* @property {string} oldState - Previous state
|
@@ -86,6 +91,7 @@
|
|
86
91
|
|
87
92
|
/**
|
88
93
|
* Event emitted when service health changes
|
94
|
+
*
|
89
95
|
* @typedef {Object} HealthChangeEvent
|
90
96
|
* @property {string} service - Service name
|
91
97
|
* @property {boolean} healthy - New health status
|
@@ -93,6 +99,7 @@
|
|
93
99
|
|
94
100
|
/**
|
95
101
|
* Event emitted when service encounters an error
|
102
|
+
*
|
96
103
|
* @typedef {Object} ServiceErrorEvent
|
97
104
|
* @property {string} service - Service name
|
98
105
|
* @property {string} operation - Operation that failed
|
@@ -101,11 +108,13 @@
|
|
101
108
|
|
102
109
|
/**
|
103
110
|
* Service class constructor type
|
104
|
-
*
|
111
|
+
*
|
112
|
+
* @typedef {new (name: string, options?: ServiceOptions) => ServiceInstance} ServiceConstructor
|
105
113
|
*/
|
106
114
|
|
107
115
|
/**
|
108
116
|
* Options for registering a service
|
117
|
+
*
|
109
118
|
* @typedef {Object} ServiceRegistrationOptions
|
110
119
|
* @property {string[]} [dependencies=[]] - Services this service depends on
|
111
120
|
* @property {string[]} [tags=[]] - Tags for grouping services
|
@@ -114,8 +123,9 @@
|
|
114
123
|
|
115
124
|
/**
|
116
125
|
* Configuration for ServiceManager
|
126
|
+
*
|
117
127
|
* @typedef {Object} ServiceManagerConfig
|
118
|
-
* @property {
|
128
|
+
* @property {boolean} [debug=false] - Debug mode switch
|
119
129
|
* @property {boolean} [autoStart=false] - Auto-start services on registration
|
120
130
|
* @property {number} [stopTimeout=10000] - Default timeout for stopping services
|
121
131
|
* @property {string} [logLevel] - Initial log level for ServiceManager
|
@@ -124,6 +134,7 @@
|
|
124
134
|
|
125
135
|
/**
|
126
136
|
* Logging configuration
|
137
|
+
*
|
127
138
|
* @typedef {Object} LogConfig
|
128
139
|
* @property {string} [defaultLevel] - Default log level for services
|
129
140
|
* @property {string} [globalLevel] - Override level for all services
|
@@ -132,9 +143,10 @@
|
|
132
143
|
|
133
144
|
/**
|
134
145
|
* Internal service registry entry
|
146
|
+
*
|
135
147
|
* @typedef {Object} ServiceEntry
|
136
148
|
* @property {ServiceConstructor} ServiceClass - Service class constructor
|
137
|
-
* @property {
|
149
|
+
* @property {ServiceInstance|null} instance - Service instance (lazy-created)
|
138
150
|
* @property {ServiceConfig} config - Service configuration
|
139
151
|
* @property {string[]} dependencies - Service dependencies
|
140
152
|
* @property {Set<string>} dependents - Services that depend on this one
|
@@ -149,12 +161,13 @@
|
|
149
161
|
|
150
162
|
/**
|
151
163
|
* Base class interface that services must implement
|
152
|
-
*
|
164
|
+
*
|
165
|
+
* @typedef {Object} ServiceInstance
|
153
166
|
* @property {string} name - Service name
|
154
167
|
* @property {string} state - Current state
|
155
168
|
* @property {boolean} healthy - Health status
|
156
169
|
* @property {Error|null} error - Last error
|
157
|
-
* @property {Logger} logger - Service logger
|
170
|
+
* @property {import('../logging').Logger} logger - Service logger
|
158
171
|
* @property {(config?: ServiceConfig) => Promise<boolean>} initialize
|
159
172
|
* @property {() => Promise<boolean>} start
|
160
173
|
* @property {(options?: StopOptions) => Promise<boolean>} stop
|
@@ -0,0 +1,47 @@
|
|
1
|
+
/**
|
2
|
+
* (Browser) console adapter that uses native DevTools styling
|
3
|
+
*/
|
4
|
+
export class ConsoleAdapter {
|
5
|
+
/**
|
6
|
+
* Create a new ConsoleAdapter
|
7
|
+
*
|
8
|
+
* @param {Object} [options] - Browser configuration options
|
9
|
+
* @param {string} [options.level] - Minimum log level
|
10
|
+
* @param {Object} [options.context] - Additional context data to include with all logs
|
11
|
+
*/
|
12
|
+
constructor(options?: {
|
13
|
+
level?: string;
|
14
|
+
context?: any;
|
15
|
+
});
|
16
|
+
level: string;
|
17
|
+
context: any;
|
18
|
+
/**
|
19
|
+
* Handle log events from Logger
|
20
|
+
*
|
21
|
+
* @param {Object} logEvent - Log event from Logger
|
22
|
+
*/
|
23
|
+
handleLog(logEvent: any): void;
|
24
|
+
/**
|
25
|
+
* Get CSS styles for browser console
|
26
|
+
*
|
27
|
+
* @param {string} level - Log level
|
28
|
+
* @returns {string} CSS styles
|
29
|
+
* @private
|
30
|
+
*/
|
31
|
+
private _getStyles;
|
32
|
+
/**
|
33
|
+
* Get appropriate console method for log level
|
34
|
+
*
|
35
|
+
* @param {string} level - Log level
|
36
|
+
* @returns {string} Console method name
|
37
|
+
* @private
|
38
|
+
*/
|
39
|
+
private _getConsoleMethod;
|
40
|
+
/**
|
41
|
+
* Create a child logger with additional context
|
42
|
+
*
|
43
|
+
* @param {Object} context - Additional context data
|
44
|
+
* @returns {ConsoleAdapter} New adapter instance with context
|
45
|
+
*/
|
46
|
+
child(context: any): ConsoleAdapter;
|
47
|
+
}
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import { LEVELS } from '../constants.js';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* (Browser) console adapter that uses native DevTools styling
|
5
|
+
*/
|
6
|
+
export class ConsoleAdapter {
|
7
|
+
/**
|
8
|
+
* Create a new ConsoleAdapter
|
9
|
+
*
|
10
|
+
* @param {Object} [options] - Browser configuration options
|
11
|
+
* @param {string} [options.level] - Minimum log level
|
12
|
+
* @param {Object} [options.context] - Additional context data to include with all logs
|
13
|
+
*/
|
14
|
+
constructor(options = {}) {
|
15
|
+
this.level = options.level || 'info';
|
16
|
+
this.context = options.context || {};
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Handle log events from Logger
|
21
|
+
*
|
22
|
+
* @param {Object} logEvent - Log event from Logger
|
23
|
+
*/
|
24
|
+
handleLog(logEvent) {
|
25
|
+
// eslint-disable-next-line no-unused-vars
|
26
|
+
const { level, message, details, service, timestamp } = logEvent;
|
27
|
+
|
28
|
+
// Filter by level
|
29
|
+
if (LEVELS[level] < LEVELS[this.level]) {
|
30
|
+
return;
|
31
|
+
}
|
32
|
+
|
33
|
+
// Use browser console styling
|
34
|
+
const styles = this._getStyles(level);
|
35
|
+
const prefix = `%c[${service}]`;
|
36
|
+
|
37
|
+
// Merge context with details
|
38
|
+
const logData = details
|
39
|
+
? { ...this.context, ...details }
|
40
|
+
: Object.keys(this.context).length > 0
|
41
|
+
? this.context
|
42
|
+
: undefined;
|
43
|
+
|
44
|
+
if (logData) {
|
45
|
+
console[this._getConsoleMethod(level)](prefix, styles, message, logData);
|
46
|
+
} else {
|
47
|
+
console[this._getConsoleMethod(level)](prefix, styles, message);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Get CSS styles for browser console
|
53
|
+
*
|
54
|
+
* @param {string} level - Log level
|
55
|
+
* @returns {string} CSS styles
|
56
|
+
* @private
|
57
|
+
*/
|
58
|
+
_getStyles(level) {
|
59
|
+
const baseStyle =
|
60
|
+
'padding: 2px 4px; border-radius: 2px; font-weight: bold;';
|
61
|
+
|
62
|
+
switch (level) {
|
63
|
+
case 'debug':
|
64
|
+
return `${baseStyle} background: #e3f2fd; color: #1976d2;`;
|
65
|
+
case 'info':
|
66
|
+
return `${baseStyle} background: #e8f5e8; color: #2e7d32;`;
|
67
|
+
case 'warn':
|
68
|
+
return `${baseStyle} background: #fff3e0; color: #f57c00;`;
|
69
|
+
case 'error':
|
70
|
+
return `${baseStyle} background: #ffebee; color: #d32f2f;`;
|
71
|
+
case 'fatal':
|
72
|
+
return `${baseStyle} background: #d32f2f; color: white;`;
|
73
|
+
default:
|
74
|
+
return baseStyle;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
/**
|
79
|
+
* Get appropriate console method for log level
|
80
|
+
*
|
81
|
+
* @param {string} level - Log level
|
82
|
+
* @returns {string} Console method name
|
83
|
+
* @private
|
84
|
+
*/
|
85
|
+
_getConsoleMethod(level) {
|
86
|
+
switch (level) {
|
87
|
+
case 'debug':
|
88
|
+
return 'debug';
|
89
|
+
case 'info':
|
90
|
+
return 'info';
|
91
|
+
case 'warn':
|
92
|
+
return 'warn';
|
93
|
+
case 'error':
|
94
|
+
case 'fatal':
|
95
|
+
return 'error';
|
96
|
+
default:
|
97
|
+
return 'log';
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
/**
|
102
|
+
* Create a child logger with additional context
|
103
|
+
*
|
104
|
+
* @param {Object} context - Additional context data
|
105
|
+
* @returns {ConsoleAdapter} New adapter instance with context
|
106
|
+
*/
|
107
|
+
child(context) {
|
108
|
+
return new ConsoleAdapter({
|
109
|
+
level: this.level,
|
110
|
+
context: { ...this.context, ...context }
|
111
|
+
});
|
112
|
+
}
|
113
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/**
|
2
|
+
* Pino adapter that bridges Logger events to pino
|
3
|
+
*/
|
4
|
+
export class PinoAdapter {
|
5
|
+
/**
|
6
|
+
* Create a new PinoAdapter
|
7
|
+
*
|
8
|
+
* @param {Object} [options] - Pino configuration options
|
9
|
+
*/
|
10
|
+
constructor(options?: any);
|
11
|
+
pino: import("pino").Logger<never, boolean>;
|
12
|
+
/**
|
13
|
+
* Handle log events from Logger
|
14
|
+
*
|
15
|
+
* @param {Object} logEvent - Log event from Logger
|
16
|
+
*/
|
17
|
+
handleLog(logEvent: any): void;
|
18
|
+
/**
|
19
|
+
* Create a child logger with additional context
|
20
|
+
*
|
21
|
+
* @param {Object} context - Additional context data
|
22
|
+
* @returns {PinoAdapter} New adapter instance with context
|
23
|
+
*/
|
24
|
+
child(context: any): PinoAdapter;
|
25
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
/**
|
2
|
+
* Pino adapter for server-side logging
|
3
|
+
*/
|
4
|
+
|
5
|
+
import pino from 'pino';
|
6
|
+
import { dev } from '$app/environment';
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Pino adapter that bridges Logger events to pino
|
10
|
+
*/
|
11
|
+
export class PinoAdapter {
|
12
|
+
/**
|
13
|
+
* Create a new PinoAdapter
|
14
|
+
*
|
15
|
+
* @param {Object} [options] - Pino configuration options
|
16
|
+
*/
|
17
|
+
constructor(options = {}) {
|
18
|
+
const defaultOptions = dev ? {
|
19
|
+
level: 'debug',
|
20
|
+
transport: {
|
21
|
+
target: 'pino-pretty',
|
22
|
+
options: {
|
23
|
+
colorize: true
|
24
|
+
}
|
25
|
+
}
|
26
|
+
} : {};
|
27
|
+
|
28
|
+
this.pino = pino({ ...defaultOptions, ...options });
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Handle log events from Logger
|
33
|
+
*
|
34
|
+
* @param {Object} logEvent - Log event from Logger
|
35
|
+
*/
|
36
|
+
handleLog(logEvent) {
|
37
|
+
const { level, message, details, service, timestamp } = logEvent;
|
38
|
+
|
39
|
+
const logData = {
|
40
|
+
service,
|
41
|
+
timestamp,
|
42
|
+
...(details && { details })
|
43
|
+
};
|
44
|
+
|
45
|
+
this.pino[level](logData, message);
|
46
|
+
}
|
47
|
+
|
48
|
+
/**
|
49
|
+
* Create a child logger with additional context
|
50
|
+
*
|
51
|
+
* @param {Object} context - Additional context data
|
52
|
+
* @returns {PinoAdapter} New adapter instance with context
|
53
|
+
*/
|
54
|
+
child(context) {
|
55
|
+
const childPino = this.pino.child(context);
|
56
|
+
const adapter = new PinoAdapter();
|
57
|
+
adapter.pino = childPino;
|
58
|
+
return adapter;
|
59
|
+
}
|
60
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from "../classes/logging/constants.js";
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from '../classes/logging/constants.js';
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
* Create a client-side logger with console adapter
|
3
|
+
*
|
4
|
+
* @param {string} serviceName - Name of the service
|
5
|
+
* @param {string} [level=INFO] - Initial log level
|
6
|
+
* @param {Object} [consoleOptions] - Additional console options
|
7
|
+
* @returns {Logger} Configured logger instance
|
8
|
+
*/
|
9
|
+
export function createClientLogger(serviceName: string, level?: string, consoleOptions?: any): Logger;
|
10
|
+
import { Logger } from '../../classes/logging';
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { Logger } from '../../classes/logging';
|
2
|
+
import { ConsoleAdapter } from '../adapters/console.js';
|
3
|
+
import { INFO } from '../constants.js';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Create a client-side logger with console adapter
|
7
|
+
*
|
8
|
+
* @param {string} serviceName - Name of the service
|
9
|
+
* @param {string} [level=INFO] - Initial log level
|
10
|
+
* @param {Object} [consoleOptions] - Additional console options
|
11
|
+
* @returns {Logger} Configured logger instance
|
12
|
+
*/
|
13
|
+
export function createClientLogger(serviceName, level = INFO, consoleOptions = {}) {
|
14
|
+
const logger = new Logger(serviceName, level);
|
15
|
+
const adapter = new ConsoleAdapter({ ...consoleOptions, level });
|
16
|
+
|
17
|
+
// Connect adapter to logger events
|
18
|
+
logger.on('log', (logEvent) => adapter.handleLog(logEvent));
|
19
|
+
|
20
|
+
return logger;
|
21
|
+
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
* Create a server-side logger with pino adapter
|
3
|
+
*
|
4
|
+
* @param {string} serviceName - Name of the service
|
5
|
+
* @param {string} [level=INFO] - Initial log level
|
6
|
+
* @param {Object} [pinoOptions] - Additional pino options
|
7
|
+
* @returns {Logger} Configured logger instance
|
8
|
+
*/
|
9
|
+
export function createServerLogger(serviceName: string, level?: string, pinoOptions?: any): Logger;
|
10
|
+
import { Logger } from '../../classes/logging';
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { Logger } from '../../classes/logging';
|
2
|
+
|
3
|
+
import { PinoAdapter } from '../adapters/pino.js';
|
4
|
+
import { INFO } from '../constants.js';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Create a server-side logger with pino adapter
|
8
|
+
*
|
9
|
+
* @param {string} serviceName - Name of the service
|
10
|
+
* @param {string} [level=INFO] - Initial log level
|
11
|
+
* @param {Object} [pinoOptions] - Additional pino options
|
12
|
+
* @returns {Logger} Configured logger instance
|
13
|
+
*/
|
14
|
+
export function createServerLogger(serviceName, level = INFO, pinoOptions = {}) {
|
15
|
+
const logger = new Logger(serviceName, level);
|
16
|
+
const adapter = new PinoAdapter(pinoOptions);
|
17
|
+
|
18
|
+
// Connect adapter to logger events
|
19
|
+
logger.on('log', (logEvent) => adapter.handleLog(logEvent));
|
20
|
+
|
21
|
+
return logger;
|
22
|
+
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
/**
|
2
|
+
* Create a logger that works in both server and client environments
|
3
|
+
*
|
4
|
+
* @param {string} serviceName - Name of the service
|
5
|
+
* @param {string} [level] - Initial log level
|
6
|
+
* @param {Object} [options] - Additional options
|
7
|
+
* @returns {Logger} Configured logger instance
|
8
|
+
*/
|
9
|
+
export function createLogger(serviceName: string, level?: string, options?: any): Logger;
|
@@ -0,0 +1,23 @@
|
|
1
|
+
/**
|
2
|
+
* Universal logger factory that auto-detects environment
|
3
|
+
*/
|
4
|
+
|
5
|
+
import { browser } from '$app/environment';
|
6
|
+
import { createServerLogger } from './server.js';
|
7
|
+
import { createClientLogger } from './client.js';
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Create a logger that works in both server and client environments
|
11
|
+
*
|
12
|
+
* @param {string} serviceName - Name of the service
|
13
|
+
* @param {string} [level] - Initial log level
|
14
|
+
* @param {Object} [options] - Additional options
|
15
|
+
* @returns {Logger} Configured logger instance
|
16
|
+
*/
|
17
|
+
export function createLogger(serviceName, level, options = {}) {
|
18
|
+
if (browser) {
|
19
|
+
return createClientLogger(serviceName, level, options);
|
20
|
+
} else {
|
21
|
+
return createServerLogger(serviceName, level, options);
|
22
|
+
}
|
23
|
+
}
|
@@ -0,0 +1,7 @@
|
|
1
|
+
export { DEBUG, INFO, WARN, ERROR, NONE, LEVELS } from './constants.js';
|
2
|
+
|
3
|
+
// Factories
|
4
|
+
export { createServerLogger } from './factories/server.js';
|
5
|
+
export { createClientLogger } from './factories/client.js';
|
6
|
+
export { createLogger } from './factories/universal.js';
|
7
|
+
|