@nm-logger/logger 1.2.0 → 1.2.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.
- package/package.json +1 -1
- package/src/Logger.js +268 -12
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@nm-logger/logger","version":"1.2.
|
|
1
|
+
{"name":"@nm-logger/logger","version":"1.2.1","description":"Express JSON logger with daily success/error/external logs and S3 append uploads.","main":"index.js","types":"index.d.ts","license":"MIT","dependencies":{"@aws-sdk/client-s3":"^3.600.0","fs-extra":"^11.1.1"}}
|
package/src/Logger.js
CHANGED
|
@@ -1,12 +1,268 @@
|
|
|
1
|
-
const LogWriter
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
const LogWriter = require("./LogWriter");
|
|
2
|
+
const Queue = require("./Queue");
|
|
3
|
+
const S3Uploader = require("./S3Uploader");
|
|
4
|
+
const DailyWatcher = require("./DailyWatcher");
|
|
5
|
+
const {
|
|
6
|
+
getApiType,
|
|
7
|
+
maskSensitive,
|
|
8
|
+
generateCorrelationId
|
|
9
|
+
} = require("./utils");
|
|
10
|
+
|
|
11
|
+
const fs = require("fs-extra");
|
|
12
|
+
const path = require("path");
|
|
13
|
+
|
|
14
|
+
let dir = "logs";
|
|
15
|
+
|
|
16
|
+
class Logger {
|
|
17
|
+
constructor(s3config = {}, options = {}) {
|
|
18
|
+
try {
|
|
19
|
+
if (opt.baseDir) {
|
|
20
|
+
const cleanPath = path.resolve(opt.baseDir); // absolute path
|
|
21
|
+
|
|
22
|
+
// Create folder safely if not exists
|
|
23
|
+
fs.ensureDirSync(cleanPath);
|
|
24
|
+
|
|
25
|
+
dir = cleanPath;
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.error("[@nm-logger/logger] Invalid baseDir path, using default:", e.message);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.baseDir = dir;
|
|
32
|
+
|
|
33
|
+
this.logWriter = new LogWriter(this.baseDir);
|
|
34
|
+
this.queue = new Queue();
|
|
35
|
+
this.s3Uploader = new S3Uploader(s3config);
|
|
36
|
+
|
|
37
|
+
this.extraMaskFields = (options.maskFields || []).map((f) =>
|
|
38
|
+
String(f).toLowerCase()
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
new DailyWatcher(this.baseDir, this.queue, this.s3Uploader, {
|
|
42
|
+
uploadIntervalMs: options.uploadIntervalMs
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
mask(value) {
|
|
47
|
+
return maskSensitive(value, this.extraMaskFields);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
buildBaseLog(req, employee_id = "") {
|
|
51
|
+
const url = req?.originalUrl || "";
|
|
52
|
+
const bodySrc = req?.body || {};
|
|
53
|
+
const paramsObj = {
|
|
54
|
+
params: req?.params || {},
|
|
55
|
+
query: req?.query || {}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const maskedBody = this.mask(bodySrc);
|
|
59
|
+
const maskedParams = this.mask(paramsObj);
|
|
60
|
+
|
|
61
|
+
let correlationId =
|
|
62
|
+
req?.correlationId ||
|
|
63
|
+
(req?.headers &&
|
|
64
|
+
(req.headers["x-correlation-id"] || req.headers["X-Correlation-ID"])) ||
|
|
65
|
+
"";
|
|
66
|
+
|
|
67
|
+
const method = (req?.method || "").toUpperCase();
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
url,
|
|
71
|
+
body: JSON.stringify(maskedBody || {}),
|
|
72
|
+
params: JSON.stringify(maskedParams || {}),
|
|
73
|
+
type: getApiType(url),
|
|
74
|
+
method,
|
|
75
|
+
error: "",
|
|
76
|
+
employee_id:
|
|
77
|
+
employee_id ||
|
|
78
|
+
(req &&
|
|
79
|
+
req.user &&
|
|
80
|
+
(req.user.employee_id || req.user.emp_code || req.user.id)) ||
|
|
81
|
+
"",
|
|
82
|
+
correlation_id: correlationId
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async logError(err, req, employee_id = "") {
|
|
87
|
+
const base = this.buildBaseLog(req || {}, employee_id);
|
|
88
|
+
const logData = {
|
|
89
|
+
...base,
|
|
90
|
+
error: err && err.message ? err.message : String(err || "")
|
|
91
|
+
};
|
|
92
|
+
await this.logWriter.writeLog(logData, "error");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async logRequest(req, employee_id = "") {
|
|
96
|
+
const logData = this.buildBaseLog(req, employee_id);
|
|
97
|
+
await this.logWriter.writeLog(logData, "success");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async logExternalApi({
|
|
101
|
+
url,
|
|
102
|
+
method,
|
|
103
|
+
data,
|
|
104
|
+
params,
|
|
105
|
+
error,
|
|
106
|
+
correlationId,
|
|
107
|
+
employeeId
|
|
108
|
+
}) {
|
|
109
|
+
const maskedBody = this.mask(data || {});
|
|
110
|
+
const maskedParams = this.mask(params || {});
|
|
111
|
+
|
|
112
|
+
const logData = {
|
|
113
|
+
url: url || "",
|
|
114
|
+
body: JSON.stringify(maskedBody || {}),
|
|
115
|
+
params: JSON.stringify(maskedParams || {}),
|
|
116
|
+
type: "external_api",
|
|
117
|
+
method: (method || "").toUpperCase(),
|
|
118
|
+
error: error || "",
|
|
119
|
+
employee_id: employeeId || "",
|
|
120
|
+
correlation_id: correlationId || "",
|
|
121
|
+
date: undefined
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
await this.logWriter.writeLog(logData, "external");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
expressMiddleware() {
|
|
128
|
+
return (err, req, res, next) => {
|
|
129
|
+
try {
|
|
130
|
+
let correlationId =
|
|
131
|
+
req.correlationId ||
|
|
132
|
+
(req.headers &&
|
|
133
|
+
(req.headers["x-correlation-id"] ||
|
|
134
|
+
req.headers["X-Correlation-ID"])) ||
|
|
135
|
+
"";
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
if (res && !res.headersSent) {
|
|
140
|
+
res.setHeader("X-Correlation-ID", correlationId);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
this.logError(err, req).catch((e) =>
|
|
144
|
+
console.error("Logger expressMiddleware error:", e)
|
|
145
|
+
);
|
|
146
|
+
} catch (e) {
|
|
147
|
+
console.error("Logger expressMiddleware outer error:", e);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
next(err);
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
expressErrorMiddleware() {
|
|
155
|
+
return this.expressMiddleware();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
requestLoggerMiddleware() {
|
|
159
|
+
return (req, res, next) => {
|
|
160
|
+
try {
|
|
161
|
+
console.log
|
|
162
|
+
if (req.__nm_logger_logged) return next();
|
|
163
|
+
req.__nm_logger_logged = true;
|
|
164
|
+
|
|
165
|
+
// correlation ID (no-crash)
|
|
166
|
+
const correlationId =
|
|
167
|
+
req.headers["x-correlation-id"] ||
|
|
168
|
+
req.headers["X-Correlation-ID"] ||
|
|
169
|
+
req.correlationId ||
|
|
170
|
+
''
|
|
171
|
+
|
|
172
|
+
req.correlationId = correlationId;
|
|
173
|
+
res.setHeader("X-Correlation-ID", correlationId);
|
|
174
|
+
|
|
175
|
+
// safe logging
|
|
176
|
+
try {
|
|
177
|
+
this.logRequest(req).catch(err => {
|
|
178
|
+
console.error("🔥 Error inside logRequest:", err);
|
|
179
|
+
});
|
|
180
|
+
} catch (inner) {
|
|
181
|
+
console.error("🔥 UNEXPECTED error inside requestLoggerMiddleware:", inner);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
} catch (outer) {
|
|
185
|
+
console.error("🔥 requestLoggerMiddleware FATAL error:", outer);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
next();
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
attachAxiosLogger(axiosInstance) {
|
|
193
|
+
if (!axiosInstance || !axiosInstance.interceptors) {
|
|
194
|
+
console.warn(
|
|
195
|
+
"[@nm-logger/logger] attachAxiosLogger: provided axios instance is invalid"
|
|
196
|
+
);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
axiosInstance.interceptors.response.use(
|
|
201
|
+
(response) => {
|
|
202
|
+
try {
|
|
203
|
+
const cfg = response.config || {};
|
|
204
|
+
const headers = cfg.headers || {};
|
|
205
|
+
|
|
206
|
+
const correlationId =
|
|
207
|
+
headers["X-Correlation-ID"] ||
|
|
208
|
+
headers["x-correlation-id"] ||
|
|
209
|
+
"";
|
|
210
|
+
|
|
211
|
+
const employeeId =
|
|
212
|
+
headers["X-Employee-ID"] ||
|
|
213
|
+
headers["x-employee-id"] ||
|
|
214
|
+
"";
|
|
215
|
+
|
|
216
|
+
this.logExternalApi({
|
|
217
|
+
url: cfg.url,
|
|
218
|
+
method: cfg.method,
|
|
219
|
+
data: cfg.data,
|
|
220
|
+
params: cfg.params,
|
|
221
|
+
error: null,
|
|
222
|
+
correlationId,
|
|
223
|
+
employeeId
|
|
224
|
+
}).catch((e) =>
|
|
225
|
+
console.error("Logger axios success logExternalApi error:", e)
|
|
226
|
+
);
|
|
227
|
+
} catch (e) {
|
|
228
|
+
console.error("Logger axios response interceptor error:", e);
|
|
229
|
+
}
|
|
230
|
+
return response;
|
|
231
|
+
},
|
|
232
|
+
(error) => {
|
|
233
|
+
try {
|
|
234
|
+
const cfg = error.config || {};
|
|
235
|
+
const headers = cfg ? cfg.headers || {} : {};
|
|
236
|
+
|
|
237
|
+
const correlationId =
|
|
238
|
+
headers["X-Correlation-ID"] ||
|
|
239
|
+
headers["x-correlation-id"] ||
|
|
240
|
+
"";
|
|
241
|
+
|
|
242
|
+
const employeeId =
|
|
243
|
+
headers["X-Employee-ID"] ||
|
|
244
|
+
headers["x-employee-id"] ||
|
|
245
|
+
"";
|
|
246
|
+
|
|
247
|
+
this.logExternalApi({
|
|
248
|
+
url: cfg && cfg.url,
|
|
249
|
+
method: cfg && cfg.method,
|
|
250
|
+
data: cfg && cfg.data,
|
|
251
|
+
params: cfg && cfg.params,
|
|
252
|
+
error: error && error.message,
|
|
253
|
+
correlationId,
|
|
254
|
+
employeeId
|
|
255
|
+
}).catch((e) =>
|
|
256
|
+
console.error("Logger axios error logExternalApi error:", e)
|
|
257
|
+
);
|
|
258
|
+
} catch (e) {
|
|
259
|
+
console.error("Logger axios error interceptor outer error:", e);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return Promise.reject(error);
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
module.exports = Logger;
|