lupine.api 1.1.58 → 1.1.59
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/README.md +3 -3
- package/admin/admin-about.tsx +12 -16
- package/admin/admin-config.tsx +47 -44
- package/admin/admin-css.tsx +3 -3
- package/admin/admin-db.tsx +75 -75
- package/admin/admin-frame-helper.tsx +364 -364
- package/admin/admin-frame.tsx +164 -164
- package/admin/admin-index.tsx +65 -65
- package/admin/admin-login.tsx +111 -111
- package/admin/admin-menu-edit.tsx +637 -637
- package/admin/admin-menu-list.tsx +87 -87
- package/admin/admin-page-edit.tsx +564 -564
- package/admin/admin-page-list.tsx +83 -83
- package/admin/admin-performance.tsx +28 -28
- package/admin/admin-release.tsx +427 -426
- package/admin/admin-resources.tsx +382 -382
- package/admin/admin-shell.tsx +89 -89
- package/admin/admin-table-data.tsx +146 -146
- package/admin/admin-table-list.tsx +230 -230
- package/admin/admin-test-animations.tsx +395 -395
- package/admin/admin-test-component.tsx +823 -808
- package/admin/admin-test-edit.tsx +319 -319
- package/admin/admin-test-themes.tsx +56 -56
- package/admin/admin-tokens.tsx +338 -338
- package/admin/design/admin-design.tsx +174 -174
- package/admin/design/block-grid.tsx +36 -36
- package/admin/design/block-grid1.tsx +21 -21
- package/admin/design/block-paragraph.tsx +19 -19
- package/admin/design/block-title.tsx +19 -19
- package/admin/design/design-block-box.tsx +140 -140
- package/admin/design/drag-data.tsx +24 -24
- package/admin/index.ts +9 -9
- package/admin/package.json +15 -15
- package/admin/tsconfig.json +127 -127
- package/dev/copy-folder.js +32 -32
- package/dev/cp-index-html.js +69 -69
- package/dev/file-utils.js +12 -12
- package/dev/index.js +18 -19
- package/dev/package.json +12 -12
- package/dev/plugin-ifelse.js +168 -168
- package/dev/plugin-ifelse.test.js +37 -37
- package/dev/run-cmd.js +14 -14
- package/dev/send-request.js +12 -12
- package/package.json +55 -55
- package/src/admin-api/admin-api-helper.ts +210 -205
- package/src/admin-api/admin-api.ts +65 -65
- package/src/admin-api/admin-auth.ts +152 -146
- package/src/admin-api/admin-config.ts +94 -84
- package/src/admin-api/admin-csv.ts +94 -94
- package/src/admin-api/admin-db.ts +269 -269
- package/src/admin-api/admin-menu.ts +135 -135
- package/src/admin-api/admin-page.ts +135 -135
- package/src/admin-api/admin-performance.ts +128 -128
- package/src/admin-api/admin-release.ts +703 -700
- package/src/admin-api/admin-resources.ts +318 -318
- package/src/admin-api/admin-token-helper.ts +82 -79
- package/src/admin-api/admin-tokens.ts +90 -90
- package/src/admin-api/index.ts +2 -2
- package/src/admin-api/web-config-api.ts +19 -19
- package/src/api/api-cache.ts +103 -103
- package/src/api/api-helper.ts +44 -44
- package/src/api/api-module.ts +67 -60
- package/src/api/api-router.ts +177 -177
- package/src/api/api-shared-storage.ts +64 -64
- package/src/api/async-storage.ts +5 -5
- package/src/api/debug-service.ts +56 -56
- package/src/api/encode-html.ts +27 -27
- package/src/api/handle-status.ts +75 -75
- package/src/api/index.ts +15 -16
- package/src/api/mini-web-socket.ts +270 -270
- package/src/api/server-content-type.ts +82 -82
- package/src/api/server-render.ts +235 -215
- package/src/api/shell-service.ts +74 -74
- package/src/api/simple-storage.ts +80 -80
- package/src/api/static-server.ts +128 -125
- package/src/api/to-client-delivery.ts +26 -26
- package/src/app/app-cache.ts +55 -55
- package/src/app/app-helper.ts +62 -62
- package/src/app/app-message.ts +109 -109
- package/src/app/app-shared-storage.ts +363 -363
- package/src/app/app-start.ts +136 -136
- package/src/app/cleanup-exit.ts +16 -16
- package/src/app/host-to-path.ts +38 -38
- package/src/app/index.ts +11 -11
- package/src/app/process-dev-requests.ts +130 -130
- package/src/app/web-listener.ts +294 -294
- package/src/app/web-processor.ts +47 -42
- package/src/app/web-server.ts +100 -100
- package/src/common-js/web-env.js +104 -104
- package/src/index.ts +7 -7
- package/src/lang/api-lang-en.ts +26 -26
- package/src/lang/api-lang-zh-cn.ts +27 -27
- package/src/lang/index.ts +2 -2
- package/src/lang/lang-helper.ts +76 -76
- package/src/lang/lang-props.ts +6 -6
- package/src/lib/db/db-helper.ts +23 -23
- package/src/lib/db/db-mysql.ts +249 -250
- package/src/lib/db/db-sqlite.ts +101 -101
- package/src/lib/db/db.spec.ts +28 -28
- package/src/lib/db/db.ts +325 -325
- package/src/lib/db/index.ts +5 -5
- package/src/lib/index.ts +3 -3
- package/src/lib/logger.spec.ts +214 -214
- package/src/lib/logger.ts +281 -281
- package/src/lib/runtime-require.ts +37 -37
- package/src/lib/utils/cookie-util.ts +34 -34
- package/src/lib/utils/crypto.ts +58 -58
- package/src/lib/utils/date-utils.ts +317 -317
- package/src/lib/utils/deep-merge.ts +37 -37
- package/src/lib/utils/delay.ts +12 -12
- package/src/lib/utils/file-setting.ts +55 -55
- package/src/lib/utils/format-bytes.ts +11 -11
- package/src/lib/utils/fs-utils.ts +158 -158
- package/src/lib/utils/get-env.ts +27 -27
- package/src/lib/utils/index.ts +12 -12
- package/src/lib/utils/is-type.ts +48 -48
- package/src/lib/utils/load-env.ts +14 -14
- package/src/lib/utils/pad.ts +6 -6
- package/src/models/api-base.ts +5 -5
- package/src/models/api-module-props.ts +10 -11
- package/src/models/api-router-props.ts +26 -26
- package/src/models/app-cache-props.ts +33 -33
- package/src/models/app-data-props.ts +10 -10
- package/src/models/app-helper-props.ts +6 -6
- package/src/models/app-shared-storage-props.ts +38 -38
- package/src/models/app-start-props.ts +18 -18
- package/src/models/async-storage-props.ts +13 -13
- package/src/models/db-config.ts +30 -30
- package/src/models/host-to-path-props.ts +12 -12
- package/src/models/index.ts +16 -16
- package/src/models/json-object.ts +8 -8
- package/src/models/locals-props.ts +36 -36
- package/src/models/logger-props.ts +84 -84
- package/src/models/simple-storage-props.ts +13 -14
- package/src/models/to-client-delivery-props.ts +6 -6
- package/tsconfig.json +115 -115
- package/dev/plugin-gen-versions.js +0 -20
package/src/lib/logger.ts
CHANGED
|
@@ -1,281 +1,281 @@
|
|
|
1
|
-
// here it must import from async-storage but not from api!
|
|
2
|
-
import { asyncLocalStorage } from '../api/async-storage';
|
|
3
|
-
import {
|
|
4
|
-
LogConfig,
|
|
5
|
-
LogLevels,
|
|
6
|
-
LogMessageFromSubProcess,
|
|
7
|
-
LoggerColors,
|
|
8
|
-
getDefaultLogConfig,
|
|
9
|
-
} from '../models/logger-props';
|
|
10
|
-
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const util = require('util');
|
|
13
|
-
const cluster = require('cluster');
|
|
14
|
-
const path = require('path');
|
|
15
|
-
|
|
16
|
-
export const LogWriterMessageId = 'LogWriter';
|
|
17
|
-
/*
|
|
18
|
-
%O Pretty-print an Object on multiple lines.
|
|
19
|
-
%o Pretty-print an Object all on a single line.
|
|
20
|
-
%s String.
|
|
21
|
-
%d Number (both integer and float).
|
|
22
|
-
%j JSON. Replaced with the string '[Circular]' if the argument contains circular references.
|
|
23
|
-
%% Single percent sign ('%'). This does not consume an argument.
|
|
24
|
-
|
|
25
|
-
logger.info('log test. numer: %d, string: %s, json: %j', 11, 'p2', {key: 'value', n: 22});
|
|
26
|
-
*/
|
|
27
|
-
export class LogWriter {
|
|
28
|
-
static instance?: LogWriter;
|
|
29
|
-
|
|
30
|
-
private constructor() {}
|
|
31
|
-
|
|
32
|
-
public static getInstance(): LogWriter {
|
|
33
|
-
if (!LogWriter.instance) {
|
|
34
|
-
LogWriter.instance = new LogWriter();
|
|
35
|
-
}
|
|
36
|
-
return LogWriter.instance;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
private _config: LogConfig | undefined;
|
|
40
|
-
getConfig = (): LogConfig => {
|
|
41
|
-
return this._config || getDefaultLogConfig();
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
savedSize = -1; // -1 for needing initialize
|
|
45
|
-
fileHandle = 0;
|
|
46
|
-
level = Object.keys(LogLevels).findIndex((item) => item === this.getConfig().level);
|
|
47
|
-
|
|
48
|
-
private _init(config: LogConfig) {
|
|
49
|
-
console.debug(`init Log: ${config.level}`);
|
|
50
|
-
if (!cluster.isPrimary) {
|
|
51
|
-
console.error('Logger cannot be initialised in sub process.');
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
this._config = {
|
|
56
|
-
...getDefaultLogConfig(),
|
|
57
|
-
...config,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
this.level = Object.keys(LogLevels).findIndex((item) => item === this.getConfig().level);
|
|
61
|
-
if (this.fileHandle > 0) {
|
|
62
|
-
fs.closeSync(this.fileHandle);
|
|
63
|
-
this.fileHandle = 0;
|
|
64
|
-
}
|
|
65
|
-
if (this.getConfig().outToFile) {
|
|
66
|
-
if (!fs.existsSync(this.getConfig().folder)) {
|
|
67
|
-
fs.mkdirSync(this.getConfig().folder, { recursive: true });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const filename = path.join(this.getConfig().folder, this.getConfig().filename.replace('%index%', '0'));
|
|
71
|
-
this.fileHandle = fs.openSync(filename, 'a+');
|
|
72
|
-
if (this.fileHandle <= 0) {
|
|
73
|
-
this.savedSize = 0;
|
|
74
|
-
console.error(`Open log error, descriptor: ${this.fileHandle}, file: ${filename}`);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
this.checkSize();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
checkSize() {
|
|
82
|
-
if (this.fileHandle <= 0) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const stats = fs.fstatSync(this.fileHandle);
|
|
87
|
-
this.savedSize = stats['size'];
|
|
88
|
-
if (this.savedSize >= this.getConfig().maxSize) {
|
|
89
|
-
fs.closeSync(this.fileHandle);
|
|
90
|
-
const filename = this.getConfig().filename;
|
|
91
|
-
if (filename.indexOf('%index%') >= 0) {
|
|
92
|
-
const maxCount = this.getConfig().maxCount || 5;
|
|
93
|
-
for (let i = maxCount - 1; i >= 1; i--) {
|
|
94
|
-
const nameFrom = path.join(this.getConfig().folder, filename.replace('%index%', (i - 1).toString()));
|
|
95
|
-
const nameTo = path.join(this.getConfig().folder, filename.replace('%index%', i.toString()));
|
|
96
|
-
if (fs.existsSync(nameFrom)) {
|
|
97
|
-
// rename can cause errors if the file is being used on windows
|
|
98
|
-
// fs.renameSync(nameFrom, nameTo);
|
|
99
|
-
try {
|
|
100
|
-
fs.copyFileSync(nameFrom, nameTo);
|
|
101
|
-
fs.unlinkSync(nameFrom);
|
|
102
|
-
} catch (err: any) {
|
|
103
|
-
console.log('Rename log error: ', err.message);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
} else if (fs.existsSync(filename)) {
|
|
108
|
-
fs.unlinkSync(filename);
|
|
109
|
-
}
|
|
110
|
-
const nameCurrent = path.join(this.getConfig().folder, filename.replace('%index%', '0'));
|
|
111
|
-
this.fileHandle = fs.openSync(nameCurrent, 'a+');
|
|
112
|
-
this.savedSize = 0;
|
|
113
|
-
if (this.fileHandle <= 0) {
|
|
114
|
-
console.error(`Open log error, descriptor: ${this.fileHandle}, file: ${nameCurrent}`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
timestamp(date?: Date) {
|
|
120
|
-
return (date || new Date()).toJSON();
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/*
|
|
124
|
-
messageFromSubProcess should be called from worker process.
|
|
125
|
-
|
|
126
|
-
// must be let!
|
|
127
|
-
let worker = cluster.fork();
|
|
128
|
-
|
|
129
|
-
worker.on('message', (msgObject) => {
|
|
130
|
-
if (!msgObject || !msgObject.id) {
|
|
131
|
-
logger.warn(`Unknown message from work: ${worker.id}`);
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (msgObject.id == LogWriterMessageId) {
|
|
136
|
-
logger.messageFromSubProcess(msgObject);
|
|
137
|
-
}
|
|
138
|
-
...
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
*/
|
|
142
|
-
// this is primary, msg is from a client. LogWriter only writes to a file in primary
|
|
143
|
-
static messageFromSubProcess(msgObject: LogMessageFromSubProcess) {
|
|
144
|
-
if (!cluster.isPrimary || !msgObject.level || !msgObject.messageList) {
|
|
145
|
-
console.error('Logger got wrong message: ', msgObject);
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
LogWriter.getInstance()._log(
|
|
149
|
-
msgObject.level,
|
|
150
|
-
msgObject.namespace,
|
|
151
|
-
msgObject.color,
|
|
152
|
-
msgObject.messageList,
|
|
153
|
-
msgObject.pid,
|
|
154
|
-
msgObject.uuid
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
_log(
|
|
159
|
-
level: string,
|
|
160
|
-
namespace: string,
|
|
161
|
-
color: LoggerColors | undefined,
|
|
162
|
-
messageList: (string | object | number)[],
|
|
163
|
-
pid?: number,
|
|
164
|
-
uuid?: string
|
|
165
|
-
) {
|
|
166
|
-
const store = asyncLocalStorage.getStore();
|
|
167
|
-
uuid = !uuid && store && store.uuid ? ':' + store.uuid : '';
|
|
168
|
-
if (!cluster.isPrimary) {
|
|
169
|
-
if (process && process.send) {
|
|
170
|
-
const obj: LogMessageFromSubProcess = {
|
|
171
|
-
id: LogWriterMessageId,
|
|
172
|
-
pid: pid || process.pid,
|
|
173
|
-
level,
|
|
174
|
-
namespace,
|
|
175
|
-
color,
|
|
176
|
-
messageList,
|
|
177
|
-
uuid,
|
|
178
|
-
};
|
|
179
|
-
process.send(obj);
|
|
180
|
-
} else {
|
|
181
|
-
console.error('Logger is not in Master but also not in sub process!');
|
|
182
|
-
}
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
if (!this.getConfig().outToFile && !this.getConfig().outToConsole) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
if (this.savedSize == -1) {
|
|
189
|
-
// all config must be in process.env
|
|
190
|
-
this._init(getDefaultLogConfig());
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const s = util.format(...messageList);
|
|
194
|
-
pid = pid ? pid : process.pid;
|
|
195
|
-
const ns = !namespace ? '' : '[' + namespace + '] ';
|
|
196
|
-
// Safety check, cut it if the string is too long
|
|
197
|
-
if (s.length > 1024) {
|
|
198
|
-
console.warn('Log string is too long: ' + s.length);
|
|
199
|
-
}
|
|
200
|
-
const msg = `${this.timestamp()} ${level} [${pid}${uuid}] ${ns}${s.length > 1024 ? s.substring(0, 1024) : s}`;
|
|
201
|
-
if (this.getConfig().outToFile) {
|
|
202
|
-
if (this.savedSize >= this.getConfig().maxSize) {
|
|
203
|
-
this.checkSize();
|
|
204
|
-
}
|
|
205
|
-
if (this.fileHandle <= 0) {
|
|
206
|
-
console.error(`Log to file error, msg: ${msg}`);
|
|
207
|
-
} else {
|
|
208
|
-
const msgBuf = Buffer.from(msg + '\r\n');
|
|
209
|
-
const options = { flag: 'a+', encoding: 'utf8', mode: '0777' };
|
|
210
|
-
fs.writeFileSync(this.fileHandle, msgBuf, options);
|
|
211
|
-
this.savedSize += msgBuf.byteLength;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
if (this.getConfig().outToConsole) {
|
|
215
|
-
// background color on Chrome's console, error: 250 230 230, warn: 255 241 212
|
|
216
|
-
if (typeof color === 'undefined' && level !== 'ERROR' && level !== 'WARN') {
|
|
217
|
-
console.log(msg);
|
|
218
|
-
} else {
|
|
219
|
-
const printColor = level === 'ERROR' ? 196 : level === 'WARN' ? 199 : color;
|
|
220
|
-
console.log(`\u001B[38:5:${printColor};1m${msg}\u001B[0m`);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export class Logger {
|
|
227
|
-
namespace = '';
|
|
228
|
-
color: LoggerColors | undefined = undefined;
|
|
229
|
-
constructor(namespace: string, color?: LoggerColors) {
|
|
230
|
-
this.namespace = namespace;
|
|
231
|
-
this.color = color;
|
|
232
|
-
// if (this.isDebug()) {
|
|
233
|
-
// if (typeof color === 'undefined') {
|
|
234
|
-
// console.log(`[Logger] namespace: ${namespace}, color: undefined`);
|
|
235
|
-
// } else {
|
|
236
|
-
// console.log(
|
|
237
|
-
// `\u001B[38:5:${this.color};1m[Logger] namespace: ${namespace}, color: ${this.color}\u001B[0m`
|
|
238
|
-
// );
|
|
239
|
-
// }
|
|
240
|
-
// }
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
isDebug(): boolean {
|
|
244
|
-
return LogWriter.getInstance().level <= 4;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
debug(...message: (string | object | number)[]) {
|
|
248
|
-
if (LogWriter.getInstance().level < 4) {
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
LogWriter.getInstance()._log('DEBUG', this.namespace, this.color, message);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
info(...message: (string | object | number)[]) {
|
|
255
|
-
if (LogWriter.getInstance().level < 3) {
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
LogWriter.getInstance()._log('INFO', this.namespace, this.color, message);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
warn(...message: (string | object | number)[]) {
|
|
262
|
-
if (LogWriter.getInstance().level < 2) {
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
LogWriter.getInstance()._log('WARN', this.namespace, this.color, message);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
error(...message: (string | object | number)[]) {
|
|
269
|
-
if (LogWriter.getInstance().level < 1) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
LogWriter.getInstance()._log('ERROR', this.namespace, this.color, message);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
fatal(...message: (string | object | number)[]) {
|
|
276
|
-
if (LogWriter.getInstance().level < 0) {
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
LogWriter.getInstance()._log('FATAL', this.namespace, this.color, message);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
1
|
+
// here it must import from async-storage but not from api!
|
|
2
|
+
import { asyncLocalStorage } from '../api/async-storage';
|
|
3
|
+
import {
|
|
4
|
+
LogConfig,
|
|
5
|
+
LogLevels,
|
|
6
|
+
LogMessageFromSubProcess,
|
|
7
|
+
LoggerColors,
|
|
8
|
+
getDefaultLogConfig,
|
|
9
|
+
} from '../models/logger-props';
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const util = require('util');
|
|
13
|
+
const cluster = require('cluster');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
export const LogWriterMessageId = 'LogWriter';
|
|
17
|
+
/*
|
|
18
|
+
%O Pretty-print an Object on multiple lines.
|
|
19
|
+
%o Pretty-print an Object all on a single line.
|
|
20
|
+
%s String.
|
|
21
|
+
%d Number (both integer and float).
|
|
22
|
+
%j JSON. Replaced with the string '[Circular]' if the argument contains circular references.
|
|
23
|
+
%% Single percent sign ('%'). This does not consume an argument.
|
|
24
|
+
|
|
25
|
+
logger.info('log test. numer: %d, string: %s, json: %j', 11, 'p2', {key: 'value', n: 22});
|
|
26
|
+
*/
|
|
27
|
+
export class LogWriter {
|
|
28
|
+
static instance?: LogWriter;
|
|
29
|
+
|
|
30
|
+
private constructor() {}
|
|
31
|
+
|
|
32
|
+
public static getInstance(): LogWriter {
|
|
33
|
+
if (!LogWriter.instance) {
|
|
34
|
+
LogWriter.instance = new LogWriter();
|
|
35
|
+
}
|
|
36
|
+
return LogWriter.instance;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private _config: LogConfig | undefined;
|
|
40
|
+
getConfig = (): LogConfig => {
|
|
41
|
+
return this._config || getDefaultLogConfig();
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
savedSize = -1; // -1 for needing initialize
|
|
45
|
+
fileHandle = 0;
|
|
46
|
+
level = Object.keys(LogLevels).findIndex((item) => item === this.getConfig().level);
|
|
47
|
+
|
|
48
|
+
private _init(config: LogConfig) {
|
|
49
|
+
console.debug(`init Log: ${config.level}`);
|
|
50
|
+
if (!cluster.isPrimary) {
|
|
51
|
+
console.error('Logger cannot be initialised in sub process.');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this._config = {
|
|
56
|
+
...getDefaultLogConfig(),
|
|
57
|
+
...config,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
this.level = Object.keys(LogLevels).findIndex((item) => item === this.getConfig().level);
|
|
61
|
+
if (this.fileHandle > 0) {
|
|
62
|
+
fs.closeSync(this.fileHandle);
|
|
63
|
+
this.fileHandle = 0;
|
|
64
|
+
}
|
|
65
|
+
if (this.getConfig().outToFile) {
|
|
66
|
+
if (!fs.existsSync(this.getConfig().folder)) {
|
|
67
|
+
fs.mkdirSync(this.getConfig().folder, { recursive: true });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const filename = path.join(this.getConfig().folder, this.getConfig().filename.replace('%index%', '0'));
|
|
71
|
+
this.fileHandle = fs.openSync(filename, 'a+');
|
|
72
|
+
if (this.fileHandle <= 0) {
|
|
73
|
+
this.savedSize = 0;
|
|
74
|
+
console.error(`Open log error, descriptor: ${this.fileHandle}, file: ${filename}`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.checkSize();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
checkSize() {
|
|
82
|
+
if (this.fileHandle <= 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const stats = fs.fstatSync(this.fileHandle);
|
|
87
|
+
this.savedSize = stats['size'];
|
|
88
|
+
if (this.savedSize >= this.getConfig().maxSize) {
|
|
89
|
+
fs.closeSync(this.fileHandle);
|
|
90
|
+
const filename = this.getConfig().filename;
|
|
91
|
+
if (filename.indexOf('%index%') >= 0) {
|
|
92
|
+
const maxCount = this.getConfig().maxCount || 5;
|
|
93
|
+
for (let i = maxCount - 1; i >= 1; i--) {
|
|
94
|
+
const nameFrom = path.join(this.getConfig().folder, filename.replace('%index%', (i - 1).toString()));
|
|
95
|
+
const nameTo = path.join(this.getConfig().folder, filename.replace('%index%', i.toString()));
|
|
96
|
+
if (fs.existsSync(nameFrom)) {
|
|
97
|
+
// rename can cause errors if the file is being used on windows
|
|
98
|
+
// fs.renameSync(nameFrom, nameTo);
|
|
99
|
+
try {
|
|
100
|
+
fs.copyFileSync(nameFrom, nameTo);
|
|
101
|
+
fs.unlinkSync(nameFrom);
|
|
102
|
+
} catch (err: any) {
|
|
103
|
+
console.log('Rename log error: ', err.message);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} else if (fs.existsSync(filename)) {
|
|
108
|
+
fs.unlinkSync(filename);
|
|
109
|
+
}
|
|
110
|
+
const nameCurrent = path.join(this.getConfig().folder, filename.replace('%index%', '0'));
|
|
111
|
+
this.fileHandle = fs.openSync(nameCurrent, 'a+');
|
|
112
|
+
this.savedSize = 0;
|
|
113
|
+
if (this.fileHandle <= 0) {
|
|
114
|
+
console.error(`Open log error, descriptor: ${this.fileHandle}, file: ${nameCurrent}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
timestamp(date?: Date) {
|
|
120
|
+
return (date || new Date()).toJSON();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/*
|
|
124
|
+
messageFromSubProcess should be called from worker process.
|
|
125
|
+
|
|
126
|
+
// must be let!
|
|
127
|
+
let worker = cluster.fork();
|
|
128
|
+
|
|
129
|
+
worker.on('message', (msgObject) => {
|
|
130
|
+
if (!msgObject || !msgObject.id) {
|
|
131
|
+
logger.warn(`Unknown message from work: ${worker.id}`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (msgObject.id == LogWriterMessageId) {
|
|
136
|
+
logger.messageFromSubProcess(msgObject);
|
|
137
|
+
}
|
|
138
|
+
...
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
*/
|
|
142
|
+
// this is primary, msg is from a client. LogWriter only writes to a file in primary
|
|
143
|
+
static messageFromSubProcess(msgObject: LogMessageFromSubProcess) {
|
|
144
|
+
if (!cluster.isPrimary || !msgObject.level || !msgObject.messageList) {
|
|
145
|
+
console.error('Logger got wrong message: ', msgObject);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
LogWriter.getInstance()._log(
|
|
149
|
+
msgObject.level,
|
|
150
|
+
msgObject.namespace,
|
|
151
|
+
msgObject.color,
|
|
152
|
+
msgObject.messageList,
|
|
153
|
+
msgObject.pid,
|
|
154
|
+
msgObject.uuid
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
_log(
|
|
159
|
+
level: string,
|
|
160
|
+
namespace: string,
|
|
161
|
+
color: LoggerColors | undefined,
|
|
162
|
+
messageList: (string | object | number)[],
|
|
163
|
+
pid?: number,
|
|
164
|
+
uuid?: string
|
|
165
|
+
) {
|
|
166
|
+
const store = asyncLocalStorage.getStore();
|
|
167
|
+
uuid = !uuid && store && store.uuid ? ':' + store.uuid : '';
|
|
168
|
+
if (!cluster.isPrimary) {
|
|
169
|
+
if (process && process.send) {
|
|
170
|
+
const obj: LogMessageFromSubProcess = {
|
|
171
|
+
id: LogWriterMessageId,
|
|
172
|
+
pid: pid || process.pid,
|
|
173
|
+
level,
|
|
174
|
+
namespace,
|
|
175
|
+
color,
|
|
176
|
+
messageList,
|
|
177
|
+
uuid,
|
|
178
|
+
};
|
|
179
|
+
process.send(obj);
|
|
180
|
+
} else {
|
|
181
|
+
console.error('Logger is not in Master but also not in sub process!');
|
|
182
|
+
}
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (!this.getConfig().outToFile && !this.getConfig().outToConsole) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (this.savedSize == -1) {
|
|
189
|
+
// all config must be in process.env
|
|
190
|
+
this._init(getDefaultLogConfig());
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const s = util.format(...messageList);
|
|
194
|
+
pid = pid ? pid : process.pid;
|
|
195
|
+
const ns = !namespace ? '' : '[' + namespace + '] ';
|
|
196
|
+
// Safety check, cut it if the string is too long
|
|
197
|
+
if (s.length > 1024) {
|
|
198
|
+
console.warn('Log string is too long: ' + s.length);
|
|
199
|
+
}
|
|
200
|
+
const msg = `${this.timestamp()} ${level} [${pid}${uuid}] ${ns}${s.length > 1024 ? s.substring(0, 1024) : s}`;
|
|
201
|
+
if (this.getConfig().outToFile) {
|
|
202
|
+
if (this.savedSize >= this.getConfig().maxSize) {
|
|
203
|
+
this.checkSize();
|
|
204
|
+
}
|
|
205
|
+
if (this.fileHandle <= 0) {
|
|
206
|
+
console.error(`Log to file error, msg: ${msg}`);
|
|
207
|
+
} else {
|
|
208
|
+
const msgBuf = Buffer.from(msg + '\r\n');
|
|
209
|
+
const options = { flag: 'a+', encoding: 'utf8', mode: '0777' };
|
|
210
|
+
fs.writeFileSync(this.fileHandle, msgBuf, options);
|
|
211
|
+
this.savedSize += msgBuf.byteLength;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (this.getConfig().outToConsole) {
|
|
215
|
+
// background color on Chrome's console, error: 250 230 230, warn: 255 241 212
|
|
216
|
+
if (typeof color === 'undefined' && level !== 'ERROR' && level !== 'WARN') {
|
|
217
|
+
console.log(msg);
|
|
218
|
+
} else {
|
|
219
|
+
const printColor = level === 'ERROR' ? 196 : level === 'WARN' ? 199 : color;
|
|
220
|
+
console.log(`\u001B[38:5:${printColor};1m${msg}\u001B[0m`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export class Logger {
|
|
227
|
+
namespace = '';
|
|
228
|
+
color: LoggerColors | undefined = undefined;
|
|
229
|
+
constructor(namespace: string, color?: LoggerColors) {
|
|
230
|
+
this.namespace = namespace;
|
|
231
|
+
this.color = color;
|
|
232
|
+
// if (this.isDebug()) {
|
|
233
|
+
// if (typeof color === 'undefined') {
|
|
234
|
+
// console.log(`[Logger] namespace: ${namespace}, color: undefined`);
|
|
235
|
+
// } else {
|
|
236
|
+
// console.log(
|
|
237
|
+
// `\u001B[38:5:${this.color};1m[Logger] namespace: ${namespace}, color: ${this.color}\u001B[0m`
|
|
238
|
+
// );
|
|
239
|
+
// }
|
|
240
|
+
// }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
isDebug(): boolean {
|
|
244
|
+
return LogWriter.getInstance().level <= 4;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
debug(...message: (string | object | number)[]) {
|
|
248
|
+
if (LogWriter.getInstance().level < 4) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
LogWriter.getInstance()._log('DEBUG', this.namespace, this.color, message);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
info(...message: (string | object | number)[]) {
|
|
255
|
+
if (LogWriter.getInstance().level < 3) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
LogWriter.getInstance()._log('INFO', this.namespace, this.color, message);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
warn(...message: (string | object | number)[]) {
|
|
262
|
+
if (LogWriter.getInstance().level < 2) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
LogWriter.getInstance()._log('WARN', this.namespace, this.color, message);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
error(...message: (string | object | number)[]) {
|
|
269
|
+
if (LogWriter.getInstance().level < 1) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
LogWriter.getInstance()._log('ERROR', this.namespace, this.color, message);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
fatal(...message: (string | object | number)[]) {
|
|
276
|
+
if (LogWriter.getInstance().level < 0) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
LogWriter.getInstance()._log('FATAL', this.namespace, this.color, message);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import { Logger } from './logger';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs/promises');
|
|
4
|
-
const vm = require('vm');
|
|
5
|
-
|
|
6
|
-
export class RuntimeRequire {
|
|
7
|
-
logger: Logger;
|
|
8
|
-
constructor() {
|
|
9
|
-
this.logger = new Logger('RuntimeRequire');
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// static require(p: string) {
|
|
13
|
-
// logger.debug('require: ' + p);
|
|
14
|
-
// return eval('require')(p);
|
|
15
|
-
// }
|
|
16
|
-
|
|
17
|
-
// static requireRelative(rootPath: string, relativePath: string) {
|
|
18
|
-
// const p = path.resolve(rootPath, relativePath);
|
|
19
|
-
// logger.debug('require: ' + p);
|
|
20
|
-
// return eval('require')(p);
|
|
21
|
-
// }
|
|
22
|
-
|
|
23
|
-
static async loadModuleIsolated(path: string, globalThis?: any): Promise<any> {
|
|
24
|
-
const code = await fs.readFile(path, 'utf-8');
|
|
25
|
-
const context = {
|
|
26
|
-
globalThis: globalThis || {},
|
|
27
|
-
};
|
|
28
|
-
vm.createContext(context);
|
|
29
|
-
// for debug in Javascript Debug Terminal
|
|
30
|
-
const script = new vm.Script(code, {
|
|
31
|
-
filename: path,
|
|
32
|
-
lineOffset: 0,
|
|
33
|
-
});
|
|
34
|
-
script.runInContext(context);
|
|
35
|
-
return context.globalThis;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
1
|
+
import { Logger } from './logger';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs/promises');
|
|
4
|
+
const vm = require('vm');
|
|
5
|
+
|
|
6
|
+
export class RuntimeRequire {
|
|
7
|
+
logger: Logger;
|
|
8
|
+
constructor() {
|
|
9
|
+
this.logger = new Logger('RuntimeRequire');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// static require(p: string) {
|
|
13
|
+
// logger.debug('require: ' + p);
|
|
14
|
+
// return eval('require')(p);
|
|
15
|
+
// }
|
|
16
|
+
|
|
17
|
+
// static requireRelative(rootPath: string, relativePath: string) {
|
|
18
|
+
// const p = path.resolve(rootPath, relativePath);
|
|
19
|
+
// logger.debug('require: ' + p);
|
|
20
|
+
// return eval('require')(p);
|
|
21
|
+
// }
|
|
22
|
+
|
|
23
|
+
static async loadModuleIsolated(path: string, globalThis?: any): Promise<any> {
|
|
24
|
+
const code = await fs.readFile(path, 'utf-8');
|
|
25
|
+
const context = {
|
|
26
|
+
globalThis: globalThis || {},
|
|
27
|
+
};
|
|
28
|
+
vm.createContext(context);
|
|
29
|
+
// for debug in Javascript Debug Terminal
|
|
30
|
+
const script = new vm.Script(code, {
|
|
31
|
+
filename: path,
|
|
32
|
+
lineOffset: 0,
|
|
33
|
+
});
|
|
34
|
+
script.runInContext(context);
|
|
35
|
+
return context.globalThis;
|
|
36
|
+
}
|
|
37
|
+
}
|