@mrxsys/mrx-core 2.11.0-1-and-269-20251003 → 2.11.0-1-and-273-20251029
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 +407 -0
- package/dist/{chunk-dzfefxjq.js → chunk-pjv1ekwr.js} +32 -0
- package/dist/chunk-rz5p4j3p.js +13 -0
- package/dist/modules/elysia/crud/index.js +1 -1
- package/dist/modules/elysia/crud/operations/index.js +1 -1
- package/dist/modules/kv-store/bun-redis/bun-redis-store.d.ts +25 -0
- package/dist/modules/kv-store/bun-redis/index.d.ts +1 -0
- package/dist/modules/kv-store/bun-redis/index.js +84 -0
- package/dist/modules/kv-store/ioredis/index.js +10 -16
- package/dist/modules/kv-store/ioredis/ioredis-store.d.ts +0 -82
- package/dist/modules/kv-store/memory/memory-store.d.ts +0 -84
- package/dist/modules/kv-store/types/kv-store.d.ts +2 -2
- package/dist/modules/logger/enums/index.js +1 -1
- package/dist/modules/logger/enums/logger-error-keys.d.ts +6 -3
- package/dist/modules/logger/events/logger-events.d.ts +12 -3
- package/dist/modules/logger/index.js +169 -81
- package/dist/modules/logger/logger.d.ts +115 -133
- package/dist/modules/logger/sinks/console-logger.d.ts +2 -16
- package/dist/modules/logger/sinks/devnull-logger.d.ts +8 -0
- package/dist/modules/logger/sinks/file-logger/enums/file-logger-error-keys.d.ts +3 -0
- package/dist/modules/logger/sinks/file-logger/file-logger.d.ts +25 -0
- package/dist/modules/logger/sinks/index.d.ts +4 -2
- package/dist/modules/logger/sinks/index.js +53 -31
- package/dist/modules/logger/types/index.d.ts +6 -6
- package/dist/modules/logger/types/log-levels.d.ts +1 -4
- package/dist/modules/logger/types/logger-options.d.ts +41 -0
- package/dist/modules/logger/types/logger-sink.d.ts +12 -3
- package/dist/modules/logger/types/sink-bodies-intersection.d.ts +2 -0
- package/dist/modules/logger/types/sink-body.d.ts +1 -1
- package/dist/modules/logger/types/sink-map.d.ts +1 -1
- package/package.json +23 -17
- package/dist/chunk-b96fm9ph.js +0 -10
- package/dist/modules/logger/sinks/file-logger.d.ts +0 -25
- package/dist/modules/logger/types/bodies-intersection.d.ts +0 -2
- package/dist/modules/logger/types/log-stream-chunk.d.ts +0 -15
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
KV_STORE_ERROR_KEYS
|
|
4
|
+
} from "../../../chunk-xhhj1gvj.js";
|
|
5
|
+
import {
|
|
6
|
+
BaseError
|
|
7
|
+
} from "../../../chunk-9cgzhc50.js";
|
|
8
|
+
|
|
9
|
+
// source/modules/kv-store/bun-redis/bun-redis-store.ts
|
|
10
|
+
var {RedisClient } = globalThis.Bun;
|
|
11
|
+
class BunRedisStore {
|
|
12
|
+
_client;
|
|
13
|
+
constructor(url, options) {
|
|
14
|
+
this._client = new RedisClient(url, options);
|
|
15
|
+
}
|
|
16
|
+
async connect() {
|
|
17
|
+
try {
|
|
18
|
+
await this._client.connect();
|
|
19
|
+
} catch (e) {
|
|
20
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.CONNECTION_FAILED, e);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
close() {
|
|
24
|
+
try {
|
|
25
|
+
this._client.close();
|
|
26
|
+
} catch (e) {
|
|
27
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.CLOSING_CONNECTION_FAILED, e);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async get(key) {
|
|
31
|
+
const value = await this._client.get(key);
|
|
32
|
+
if (value === null)
|
|
33
|
+
return null;
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(value);
|
|
36
|
+
} catch {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async set(key, value, ttlSec) {
|
|
41
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
42
|
+
if (ttlSec)
|
|
43
|
+
await this._client.set(key, serialized, "EX", ttlSec);
|
|
44
|
+
else
|
|
45
|
+
await this._client.set(key, serialized);
|
|
46
|
+
}
|
|
47
|
+
async increment(key, amount) {
|
|
48
|
+
try {
|
|
49
|
+
const number = await this._client.incrby(key, amount ?? 1);
|
|
50
|
+
return number;
|
|
51
|
+
} catch (e) {
|
|
52
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.NOT_INTEGER, e);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async decrement(key, amount) {
|
|
56
|
+
try {
|
|
57
|
+
const number = await this._client.decrby(key, amount ?? 1);
|
|
58
|
+
return number;
|
|
59
|
+
} catch (e) {
|
|
60
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.NOT_INTEGER, e);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async del(key) {
|
|
64
|
+
const res = await this._client.del(key);
|
|
65
|
+
return res === 1;
|
|
66
|
+
}
|
|
67
|
+
async expire(key, ttlSec) {
|
|
68
|
+
const res = await this._client.expire(key, ttlSec);
|
|
69
|
+
return res === 1;
|
|
70
|
+
}
|
|
71
|
+
async ttl(key) {
|
|
72
|
+
const res = await this._client.ttl(key);
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
75
|
+
async clean() {
|
|
76
|
+
const keys = await this._client.keys("*");
|
|
77
|
+
if (keys.length === 0)
|
|
78
|
+
return 0;
|
|
79
|
+
return this._client.del(...keys);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
BunRedisStore
|
|
84
|
+
};
|
|
@@ -48,26 +48,20 @@ class IoRedisStore {
|
|
|
48
48
|
await this._client.set(key, serialized);
|
|
49
49
|
}
|
|
50
50
|
async increment(key, amount = 1) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
try {
|
|
52
|
+
const number = await this._client.incrby(key, amount);
|
|
53
|
+
return number;
|
|
54
|
+
} catch (e) {
|
|
55
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.NOT_INTEGER, e);
|
|
56
56
|
}
|
|
57
|
-
if (amount === 1)
|
|
58
|
-
return this._client.incr(key);
|
|
59
|
-
return this._client.incrby(key, amount);
|
|
60
57
|
}
|
|
61
58
|
async decrement(key, amount = 1) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
try {
|
|
60
|
+
const number = await this._client.decrby(key, amount);
|
|
61
|
+
return number;
|
|
62
|
+
} catch (e) {
|
|
63
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.NOT_INTEGER, e);
|
|
67
64
|
}
|
|
68
|
-
if (amount === 1)
|
|
69
|
-
return this._client.decr(key);
|
|
70
|
-
return this._client.decrby(key, amount);
|
|
71
65
|
}
|
|
72
66
|
async del(key) {
|
|
73
67
|
const result = await this._client.del(key);
|
|
@@ -11,97 +11,15 @@ export declare class IoRedisStore implements KvStore {
|
|
|
11
11
|
* Redis client instance.
|
|
12
12
|
*/
|
|
13
13
|
private readonly _client;
|
|
14
|
-
/**
|
|
15
|
-
* Creates an IoRedis store instance.
|
|
16
|
-
*
|
|
17
|
-
* @param options - Redis connection options
|
|
18
|
-
*/
|
|
19
14
|
constructor(options: RedisOptions);
|
|
20
|
-
/**
|
|
21
|
-
* Establishes connection to Redis server.
|
|
22
|
-
*
|
|
23
|
-
* @throws ({@link BaseError}) - When connection fails
|
|
24
|
-
*/
|
|
25
15
|
connect(): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
* Closes the Redis connection gracefully.
|
|
28
|
-
*
|
|
29
|
-
* @throws ({@link BaseError}) - When closing connection fails
|
|
30
|
-
*/
|
|
31
16
|
close(): Promise<void>;
|
|
32
|
-
/**
|
|
33
|
-
* Retrieves a value from Redis by key.
|
|
34
|
-
*
|
|
35
|
-
* @template T - The expected type of the stored value
|
|
36
|
-
*
|
|
37
|
-
* @param key - The key to retrieve
|
|
38
|
-
*
|
|
39
|
-
* @returns The value associated with the key, or null if not found or expired
|
|
40
|
-
*/
|
|
41
17
|
get<T = unknown>(key: string): Promise<T | null>;
|
|
42
|
-
/**
|
|
43
|
-
* Stores a value in Redis with optional TTL.
|
|
44
|
-
*
|
|
45
|
-
* @template T - The type of the value being stored
|
|
46
|
-
*
|
|
47
|
-
* @param key - The key to store the value under
|
|
48
|
-
* @param value - The value to store
|
|
49
|
-
* @param ttlSec - Time to live in seconds (optional)
|
|
50
|
-
*/
|
|
51
18
|
set<T = unknown>(key: string, value: T, ttlSec?: number): Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
* Increments a numeric value stored at key by the specified amount.
|
|
54
|
-
* If the key does not exist, it is set to 0 before performing the operation.
|
|
55
|
-
*
|
|
56
|
-
* @param key - The key containing the numeric value
|
|
57
|
-
* @param amount - The amount to increment by (default: 1)
|
|
58
|
-
*
|
|
59
|
-
* @throws ({@link BaseError}) - When the value is not a valid integer
|
|
60
|
-
*
|
|
61
|
-
* @returns The value after incrementing
|
|
62
|
-
*/
|
|
63
19
|
increment(key: string, amount?: number): Promise<number>;
|
|
64
|
-
/**
|
|
65
|
-
* Decrements a numeric value stored at key by the specified amount.
|
|
66
|
-
* If the key does not exist, it is set to 0 before performing the operation.
|
|
67
|
-
*
|
|
68
|
-
* @param key - The key containing the numeric value
|
|
69
|
-
* @param amount - The amount to decrement by (default: 1)
|
|
70
|
-
*
|
|
71
|
-
* @throws ({@link BaseError}) - When the value is not a valid integer
|
|
72
|
-
*
|
|
73
|
-
* @returns The value after decrementing
|
|
74
|
-
*/
|
|
75
20
|
decrement(key: string, amount?: number): Promise<number>;
|
|
76
|
-
/**
|
|
77
|
-
* Deletes a key from Redis.
|
|
78
|
-
*
|
|
79
|
-
* @param key - The key to delete
|
|
80
|
-
*
|
|
81
|
-
* @returns True if the key was deleted, false if it did not exist
|
|
82
|
-
*/
|
|
83
21
|
del(key: string): Promise<boolean>;
|
|
84
|
-
/**
|
|
85
|
-
* Sets an expiration time for a key.
|
|
86
|
-
*
|
|
87
|
-
* @param key - The key to set expiration for
|
|
88
|
-
* @param ttlSec - Time to live in seconds
|
|
89
|
-
*
|
|
90
|
-
* @returns True if the expiration was set, false if the key does not exist
|
|
91
|
-
*/
|
|
92
22
|
expire(key: string, ttlSec: number): Promise<boolean>;
|
|
93
|
-
/**
|
|
94
|
-
* Gets the remaining time to live for a key.
|
|
95
|
-
*
|
|
96
|
-
* @param key - The key to check
|
|
97
|
-
*
|
|
98
|
-
* @returns Time to live in seconds, -1 if key has no expiration, -2 if key does not exist
|
|
99
|
-
*/
|
|
100
23
|
ttl(key: string): Promise<number>;
|
|
101
|
-
/**
|
|
102
|
-
* Removes all keys from the Redis database.
|
|
103
|
-
*
|
|
104
|
-
* @returns The number of keys that were deleted
|
|
105
|
-
*/
|
|
106
24
|
clean(): Promise<number>;
|
|
107
25
|
}
|
|
@@ -20,100 +20,16 @@ export declare class MemoryStore implements KvStore {
|
|
|
20
20
|
* Timer for cleanup operations.
|
|
21
21
|
*/
|
|
22
22
|
private _cleanupTimer;
|
|
23
|
-
/**
|
|
24
|
-
* Creates instance and starts cleanup process.
|
|
25
|
-
*
|
|
26
|
-
* @param cleanupIntervalMs - Cleanup interval in milliseconds (default: 300000 ms / 5 minutes)
|
|
27
|
-
*/
|
|
28
23
|
constructor(cleanupIntervalMs?: number);
|
|
29
|
-
/**
|
|
30
|
-
* Retrieves a value from the store by key.
|
|
31
|
-
* Automatically removes expired entries during retrieval.
|
|
32
|
-
*
|
|
33
|
-
* @template T - The expected type of the stored value
|
|
34
|
-
*
|
|
35
|
-
* @param key - The key to retrieve
|
|
36
|
-
*
|
|
37
|
-
* @returns The value associated with the key, or null if not found or expired
|
|
38
|
-
*/
|
|
39
24
|
get<T = unknown>(key: string): T | null;
|
|
40
|
-
/**
|
|
41
|
-
* Stores a value in memory with optional TTL.
|
|
42
|
-
*
|
|
43
|
-
* @template T - The type of the value being stored
|
|
44
|
-
*
|
|
45
|
-
* @param key - The key to store the value under
|
|
46
|
-
* @param value - The value to store
|
|
47
|
-
* @param ttlSec - Time to live in seconds (optional)
|
|
48
|
-
*/
|
|
49
25
|
set<T = unknown>(key: string, value: T, ttlSec?: number): void;
|
|
50
|
-
/**
|
|
51
|
-
* Increments a numeric value stored at key by the specified amount.
|
|
52
|
-
* If the key does not exist, it is set to 0 before performing the operation.
|
|
53
|
-
* Preserves existing TTL when incrementing.
|
|
54
|
-
*
|
|
55
|
-
* @param key - The key containing the numeric value
|
|
56
|
-
* @param amount - The amount to increment by (default: 1)
|
|
57
|
-
*
|
|
58
|
-
* @throws ({@link BaseError}) - When the value is not a valid integer
|
|
59
|
-
*
|
|
60
|
-
* @returns The value after incrementing
|
|
61
|
-
*/
|
|
62
26
|
increment(key: string, amount?: number): number;
|
|
63
|
-
/**
|
|
64
|
-
* Decrements a numeric value stored at key by the specified amount.
|
|
65
|
-
* If the key does not exist, it is set to 0 before performing the operation.
|
|
66
|
-
* Preserves existing TTL when decrementing.
|
|
67
|
-
*
|
|
68
|
-
* @param key - The key containing the numeric value
|
|
69
|
-
* @param amount - The amount to decrement by (default: 1)
|
|
70
|
-
*
|
|
71
|
-
* @throws ({@link BaseError}) - When the value is not a valid integer
|
|
72
|
-
*
|
|
73
|
-
* @returns The value after decrementing
|
|
74
|
-
*/
|
|
75
27
|
decrement(key: string, amount?: number): number;
|
|
76
|
-
/**
|
|
77
|
-
* Deletes a key from the store.
|
|
78
|
-
*
|
|
79
|
-
* @param key - The key to delete
|
|
80
|
-
*
|
|
81
|
-
* @returns True if the key was deleted, false if it did not exist
|
|
82
|
-
*/
|
|
83
28
|
del(key: string): boolean;
|
|
84
|
-
/**
|
|
85
|
-
* Sets an expiration time for a key.
|
|
86
|
-
*
|
|
87
|
-
* @param key - The key to set expiration for
|
|
88
|
-
* @param ttlSec - Time to live in seconds
|
|
89
|
-
*
|
|
90
|
-
* @returns True if the expiration was set, false if the key does not exist
|
|
91
|
-
*/
|
|
92
29
|
expire(key: string, ttlSec: number): boolean;
|
|
93
|
-
/**
|
|
94
|
-
* Gets the remaining time to live for a key.
|
|
95
|
-
*
|
|
96
|
-
* @param key - The key to check
|
|
97
|
-
*
|
|
98
|
-
* @returns Time to live in seconds, -1 if key has no expiration or does not exist
|
|
99
|
-
*/
|
|
100
30
|
ttl(key: string): number;
|
|
101
|
-
/**
|
|
102
|
-
* Removes all keys from the store.
|
|
103
|
-
*
|
|
104
|
-
* @returns The number of keys that were deleted
|
|
105
|
-
*/
|
|
106
31
|
clean(): number;
|
|
107
|
-
/**
|
|
108
|
-
* Starts the cleanup process for expired entries.
|
|
109
|
-
*/
|
|
110
32
|
private _startCleanup;
|
|
111
|
-
/**
|
|
112
|
-
* Removes expired entries from the store.
|
|
113
|
-
*/
|
|
114
33
|
private _removeExpiredEntries;
|
|
115
|
-
/**
|
|
116
|
-
* Stops the cleanup process and clears resources.
|
|
117
|
-
*/
|
|
118
34
|
destroy(): void;
|
|
119
35
|
}
|
|
@@ -2,11 +2,11 @@ export interface KvStore {
|
|
|
2
2
|
/**
|
|
3
3
|
* Connect to the store.
|
|
4
4
|
*/
|
|
5
|
-
connect?(): Promise<void
|
|
5
|
+
connect?(): Promise<void> | void;
|
|
6
6
|
/**
|
|
7
7
|
* Close the connection to the store.
|
|
8
8
|
*/
|
|
9
|
-
close?(): Promise<void
|
|
9
|
+
close?(): Promise<void> | void;
|
|
10
10
|
/**
|
|
11
11
|
* Get the value associated with a key.
|
|
12
12
|
*
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export declare const LOGGER_ERROR_KEYS: {
|
|
2
|
-
readonly
|
|
2
|
+
readonly BEFORE_EXIT_CLOSE_ERROR: "mrx-core.logger.error.before_exit_close_error";
|
|
3
|
+
readonly BEFORE_EXIT_FLUSH_ERROR: "mrx-core.logger.error.before_exit_flush_error";
|
|
4
|
+
readonly NO_SINKS_PROVIDED: "mrx-core.logger.error.no_sinks_provided";
|
|
5
|
+
readonly REGISTER_SINK_ERROR: "mrx-core.logger.error.register_sink_error";
|
|
3
6
|
readonly SINK_ALREADY_ADDED: "mrx-core.logger.error.sink_already_added";
|
|
4
|
-
readonly
|
|
5
|
-
readonly
|
|
7
|
+
readonly SINK_CLOSE_ERROR: "mrx-core.logger.error.sink_close_error";
|
|
8
|
+
readonly SINK_LOG_ERROR: "mrx-core.logger.error.sink_log_error";
|
|
6
9
|
};
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import type { BaseError } from '../../../errors/base-error';
|
|
2
2
|
export interface LoggerEvent {
|
|
3
|
-
|
|
3
|
+
onBeforeExitError: [BaseError<{
|
|
4
|
+
error: Error;
|
|
5
|
+
}>];
|
|
6
|
+
registerSinkError: [
|
|
4
7
|
BaseError<{
|
|
5
8
|
sinkName: string;
|
|
6
|
-
object: unknown;
|
|
7
9
|
error: Error;
|
|
8
10
|
}>
|
|
9
11
|
];
|
|
10
|
-
|
|
12
|
+
sinkError: [
|
|
13
|
+
BaseError<{
|
|
14
|
+
sinkName: string;
|
|
15
|
+
object?: unknown;
|
|
16
|
+
error: Error;
|
|
17
|
+
}>
|
|
18
|
+
];
|
|
19
|
+
drained: [];
|
|
11
20
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
LOGGER_ERROR_KEYS
|
|
4
|
-
} from "../../chunk-
|
|
4
|
+
} from "../../chunk-rz5p4j3p.js";
|
|
5
5
|
import {
|
|
6
6
|
TypedEventEmitter
|
|
7
7
|
} from "../../chunk-mvrxngm7.js";
|
|
@@ -10,110 +10,198 @@ import {
|
|
|
10
10
|
} from "../../chunk-9cgzhc50.js";
|
|
11
11
|
|
|
12
12
|
// source/modules/logger/logger.ts
|
|
13
|
-
import { once } from "events";
|
|
14
|
-
import { Transform } from "stream";
|
|
15
13
|
class Logger extends TypedEventEmitter {
|
|
16
14
|
_sinks;
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
_sinkKeys = [];
|
|
16
|
+
_worker;
|
|
19
17
|
_maxPendingLogs;
|
|
18
|
+
_maxMessagesInFlight;
|
|
19
|
+
_batchSize;
|
|
20
|
+
_batchTimeout;
|
|
21
|
+
_autoEnd;
|
|
22
|
+
_flushOnBeforeExit;
|
|
23
|
+
_pendingLogs = [];
|
|
24
|
+
_messagesInFlight = 0;
|
|
25
|
+
_batchTimer = null;
|
|
20
26
|
_isWriting = false;
|
|
21
|
-
|
|
27
|
+
_flushResolvers = [];
|
|
28
|
+
_closeResolver = null;
|
|
29
|
+
_backpressureResolver = null;
|
|
30
|
+
_handleExit = () => {
|
|
31
|
+
this._worker.terminate();
|
|
32
|
+
};
|
|
33
|
+
_handleWorkerClose = () => {
|
|
34
|
+
process.off("beforeExit", this._handleBeforeExit);
|
|
35
|
+
process.off("exit", this._handleExit);
|
|
36
|
+
};
|
|
37
|
+
constructor(options) {
|
|
22
38
|
super();
|
|
23
|
-
|
|
39
|
+
const {
|
|
40
|
+
autoEnd = true,
|
|
41
|
+
batchSize = 50,
|
|
42
|
+
batchTimeout = 0.1,
|
|
43
|
+
flushOnBeforeExit = true,
|
|
44
|
+
maxMessagesInFlight = 100,
|
|
45
|
+
maxPendingLogs = 1e4
|
|
46
|
+
} = options ?? {};
|
|
47
|
+
this._sinks = {};
|
|
24
48
|
this._maxPendingLogs = maxPendingLogs;
|
|
25
|
-
this.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
registerSink(name, sink) {
|
|
36
|
-
if (this._sinks[name])
|
|
37
|
-
throw new BaseError(LOGGER_ERROR_KEYS.SINK_ALREADY_ADDED, { sinkName: name });
|
|
38
|
-
return new Logger({
|
|
39
|
-
...this._sinks,
|
|
40
|
-
[name]: sink
|
|
41
|
-
}, this._maxPendingLogs);
|
|
42
|
-
}
|
|
43
|
-
unregisterSink(name) {
|
|
44
|
-
if (!(name in this._sinks))
|
|
45
|
-
throw new BaseError(LOGGER_ERROR_KEYS.SINK_NOT_FOUND, { sinkName: name });
|
|
46
|
-
const { [name]: _, ...rest } = this._sinks;
|
|
47
|
-
return new Logger(rest, this._maxPendingLogs);
|
|
48
|
-
}
|
|
49
|
-
registerSinks(sinks) {
|
|
50
|
-
return sinks.reduce((logger, [name, sink]) => logger.registerSink(name, sink), this);
|
|
49
|
+
this._maxMessagesInFlight = maxMessagesInFlight;
|
|
50
|
+
this._batchSize = batchSize;
|
|
51
|
+
this._batchTimeout = batchTimeout;
|
|
52
|
+
this._autoEnd = autoEnd;
|
|
53
|
+
this._flushOnBeforeExit = flushOnBeforeExit;
|
|
54
|
+
this._worker = new Worker(new URL("worker-logger.ts", import.meta.url).href, { type: "module" });
|
|
55
|
+
this._setupWorkerMessages();
|
|
56
|
+
if (this._autoEnd)
|
|
57
|
+
this._setupAutoEnd();
|
|
51
58
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
registerSink(sinkName, sinkConstructor, ...sinkArgs) {
|
|
60
|
+
if (this._sinks[sinkName])
|
|
61
|
+
throw new BaseError(LOGGER_ERROR_KEYS.SINK_ALREADY_ADDED);
|
|
62
|
+
this._worker.postMessage({
|
|
63
|
+
type: "REGISTER_SINK",
|
|
64
|
+
sinkName,
|
|
65
|
+
sinkClassName: sinkConstructor.name,
|
|
66
|
+
sinkClassString: sinkConstructor.toString(),
|
|
67
|
+
sinkArgs
|
|
68
|
+
});
|
|
69
|
+
this._sinks[sinkName] = sinkConstructor;
|
|
70
|
+
this._sinkKeys.push(sinkName);
|
|
71
|
+
return this;
|
|
60
72
|
}
|
|
61
|
-
error(object,
|
|
62
|
-
this.
|
|
73
|
+
error(object, sinkNames = this._sinkKeys) {
|
|
74
|
+
this._enqueue("ERROR", object, sinkNames);
|
|
63
75
|
}
|
|
64
|
-
warn(object,
|
|
65
|
-
this.
|
|
76
|
+
warn(object, sinkNames = this._sinkKeys) {
|
|
77
|
+
this._enqueue("WARN", object, sinkNames);
|
|
66
78
|
}
|
|
67
|
-
info(object,
|
|
68
|
-
this.
|
|
79
|
+
info(object, sinkNames = this._sinkKeys) {
|
|
80
|
+
this._enqueue("INFO", object, sinkNames);
|
|
69
81
|
}
|
|
70
|
-
debug(object,
|
|
71
|
-
this.
|
|
82
|
+
debug(object, sinkNames = this._sinkKeys) {
|
|
83
|
+
this._enqueue("DEBUG", object, sinkNames);
|
|
72
84
|
}
|
|
73
|
-
log(object,
|
|
74
|
-
this.
|
|
85
|
+
log(object, sinkNames = this._sinkKeys) {
|
|
86
|
+
this._enqueue("LOG", object, sinkNames);
|
|
75
87
|
}
|
|
76
|
-
async
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
88
|
+
async flush() {
|
|
89
|
+
if (this._pendingLogs.length === 0 && this._messagesInFlight === 0)
|
|
90
|
+
return;
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
this._flushResolvers.push(resolve);
|
|
93
|
+
if (!this._isWriting && this._pendingLogs.length > 0) {
|
|
94
|
+
this._isWriting = true;
|
|
95
|
+
this._processPendingLogs();
|
|
82
96
|
}
|
|
83
|
-
})
|
|
97
|
+
});
|
|
84
98
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
99
|
+
async close() {
|
|
100
|
+
await this.flush();
|
|
101
|
+
return new Promise((resolve) => {
|
|
102
|
+
this._closeResolver = resolve;
|
|
103
|
+
this._worker.postMessage({ type: "CLOSE" });
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
_enqueue(level, object, sinkNames) {
|
|
107
|
+
if (this._sinkKeys.length === 0)
|
|
108
|
+
throw new BaseError(LOGGER_ERROR_KEYS.NO_SINKS_PROVIDED, { level, object });
|
|
89
109
|
if (this._pendingLogs.length >= this._maxPendingLogs)
|
|
90
110
|
return;
|
|
91
|
-
|
|
92
|
-
|
|
111
|
+
this._pendingLogs.push({
|
|
112
|
+
sinkNames: sinkNames ?? this._sinkKeys,
|
|
93
113
|
level,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
};
|
|
97
|
-
this._pendingLogs.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
114
|
+
timestamp: Date.now(),
|
|
115
|
+
object
|
|
116
|
+
});
|
|
117
|
+
if (this._pendingLogs.length >= this._batchSize) {
|
|
118
|
+
if (this._batchTimer !== null) {
|
|
119
|
+
clearTimeout(this._batchTimer);
|
|
120
|
+
this._batchTimer = null;
|
|
121
|
+
}
|
|
122
|
+
this._triggerProcessing();
|
|
123
|
+
} else if (this._batchTimeout > 0 && this._batchTimer === null) {
|
|
124
|
+
this._batchTimer = setTimeout(() => {
|
|
125
|
+
this._batchTimer = null;
|
|
126
|
+
this._triggerProcessing();
|
|
127
|
+
}, this._batchTimeout);
|
|
103
128
|
}
|
|
104
129
|
}
|
|
105
|
-
|
|
130
|
+
_triggerProcessing() {
|
|
131
|
+
if (this._isWriting)
|
|
132
|
+
return;
|
|
133
|
+
this._isWriting = true;
|
|
134
|
+
this._processPendingLogs();
|
|
135
|
+
}
|
|
136
|
+
async _processPendingLogs() {
|
|
106
137
|
while (this._pendingLogs.length > 0) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
138
|
+
if (this._messagesInFlight >= this._maxMessagesInFlight)
|
|
139
|
+
await new Promise((resolve) => {
|
|
140
|
+
this._backpressureResolver = resolve;
|
|
141
|
+
});
|
|
142
|
+
const batch = this._pendingLogs.splice(0, this._batchSize);
|
|
143
|
+
this._messagesInFlight++;
|
|
144
|
+
this._worker.postMessage({
|
|
145
|
+
type: "LOG_BATCH",
|
|
146
|
+
logs: batch
|
|
147
|
+
});
|
|
113
148
|
}
|
|
114
149
|
this._isWriting = false;
|
|
115
|
-
this.emit("
|
|
150
|
+
this.emit("drained");
|
|
151
|
+
}
|
|
152
|
+
_releaseBatch() {
|
|
153
|
+
this._messagesInFlight--;
|
|
154
|
+
if (this._backpressureResolver !== null) {
|
|
155
|
+
this._backpressureResolver();
|
|
156
|
+
this._backpressureResolver = null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
_setupWorkerMessages() {
|
|
160
|
+
this._worker.addEventListener("message", (event) => {
|
|
161
|
+
switch (event.data.type) {
|
|
162
|
+
case "BATCH_COMPLETE":
|
|
163
|
+
this._releaseBatch();
|
|
164
|
+
if (this._messagesInFlight === 0 && this._pendingLogs.length === 0 && this._flushResolvers.length > 0) {
|
|
165
|
+
for (const resolve of this._flushResolvers)
|
|
166
|
+
resolve();
|
|
167
|
+
this._flushResolvers.length = 0;
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
case "SINK_LOG_ERROR":
|
|
171
|
+
this.emit("sinkError", new BaseError(LOGGER_ERROR_KEYS.SINK_LOG_ERROR, event.data));
|
|
172
|
+
this._releaseBatch();
|
|
173
|
+
break;
|
|
174
|
+
case "SINK_CLOSE_ERROR":
|
|
175
|
+
this.emit("sinkError", new BaseError(LOGGER_ERROR_KEYS.SINK_CLOSE_ERROR, event.data));
|
|
176
|
+
break;
|
|
177
|
+
case "REGISTER_SINK_ERROR":
|
|
178
|
+
this.emit("registerSinkError", new BaseError(LOGGER_ERROR_KEYS.REGISTER_SINK_ERROR, event.data));
|
|
179
|
+
break;
|
|
180
|
+
case "CLOSE_COMPLETE":
|
|
181
|
+
this._worker.terminate();
|
|
182
|
+
if (this._closeResolver) {
|
|
183
|
+
this._closeResolver();
|
|
184
|
+
this._closeResolver = null;
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
116
189
|
}
|
|
190
|
+
_setupAutoEnd() {
|
|
191
|
+
process.on("beforeExit", this._handleBeforeExit);
|
|
192
|
+
process.on("exit", this._handleExit);
|
|
193
|
+
this._worker.addEventListener("close", this._handleWorkerClose);
|
|
194
|
+
}
|
|
195
|
+
_handleBeforeExit = () => {
|
|
196
|
+
if (this._flushOnBeforeExit)
|
|
197
|
+
this.flush().then(() => this.close()).catch((error) => {
|
|
198
|
+
this.emit("onBeforeExitError", new BaseError(LOGGER_ERROR_KEYS.BEFORE_EXIT_FLUSH_ERROR, { error }));
|
|
199
|
+
});
|
|
200
|
+
else
|
|
201
|
+
this.close().catch((error) => {
|
|
202
|
+
this.emit("onBeforeExitError", new BaseError(LOGGER_ERROR_KEYS.BEFORE_EXIT_CLOSE_ERROR, { error }));
|
|
203
|
+
});
|
|
204
|
+
};
|
|
117
205
|
}
|
|
118
206
|
export {
|
|
119
207
|
Logger
|