@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/Logger.js +268 -12
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@nm-logger/logger","version":"1.2.0","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"}}
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=require("./LogWriter");const Queue=require("./Queue");const S3Uploader=require("./S3Uploader");const DailyWatcher=require("./DailyWatcher");const{getApiType,maskSensitive}=require("./utils");
2
- class Logger{constructor(s3cfg={},opt={}){this.baseDir=opt.baseDir||"logs";this.logWriter=new LogWriter(this.baseDir);this.queue=new Queue();this.s3=new S3Uploader(s3cfg);this.maskFields=(opt.maskFields||[]).map(x=>String(x).toLowerCase());new DailyWatcher(this.baseDir,this.queue,this.s3,{uploadIntervalMs:opt.uploadIntervalMs});}
3
- mask(v){return maskSensitive(v,this.maskFields);}
4
- buildBaseLog(req,employee_id=""){const url=req&&req.originalUrl||"";const body=req&&req.body||{};const params={params:req&&req.params||{},query:req&&req.query||{}};const mBody=this.mask(body);const mParams=this.mask(params);const method=(req&&req.method||"").toUpperCase();const emp=employee_id||(req&&req.user&&(req.user.employee_id||req.user.emp_code||req.user.id))||"";return{url,body:JSON.stringify(mBody||{}),params:JSON.stringify(mParams||{}),type:getApiType(url),method,error:"",employee_id:emp};}
5
- async logError(err,req,employee_id=""){const base=this.buildBaseLog(req||{},employee_id);const d={...base,error:err&&err.message?err.message:String(err||"")};await this.logWriter.writeLog(d,"error");}
6
- async logRequest(req,employee_id=""){const d=this.buildBaseLog(req,employee_id);await this.logWriter.writeLog(d,"success");}
7
- async logExternalApi({url,method,data,params,error,employeeId}){const mb=this.mask(data||{});const mp=this.mask(params||{});const d={url:url||"",body:JSON.stringify(mb||{}),params:JSON.stringify(mp||{}),type:"external_api",method:(method||"").toUpperCase(),error:error||"",employee_id:employeeId||""};await this.logWriter.writeLog(d,"external");}
8
- expressMiddleware(){return(err,req,res,next)=>{try{this.logError(err,req).catch(e=>console.error("logger express error",e));}catch(e){console.error("logger express outer",e);}next(err);};}
9
- expressErrorMiddleware(){return this.expressMiddleware();}
10
- requestLoggerMiddleware(){return(req,res,next)=>{try{if(req.__nm_logger_logged)return next();req.__nm_logger_logged=true;this.logRequest(req).catch(e=>console.error("logger request error",e));}catch(e){console.error("logger request outer",e);}next();};}
11
- attachAxiosLogger(ax){if(!ax||!ax.interceptors)return;ax.interceptors.response.use(r=>{try{const c=r.config||{};this.logExternalApi({url:c.url,method:c.method,data:c.data,params:c.params,error:null,employeeId:c.employee_id}).catch(e=>console.error("logger axios ok",e));}catch(e){console.error("logger axios ok outer",e);}return r;},err=>{try{const c=err.config||{};this.logExternalApi({url:c&&c.url,method:c&&c.method,data:c&&c.data,params:c&&c.params,error:err&&err.message,employeeId:c&&c.employee_id}).catch(e=>console.error("logger axios err",e));}catch(e){console.error("logger axios err outer",e);}return Promise.reject(err);});}}
12
- module.exports=Logger;
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;