@nm-logger/logger 1.1.2 → 1.1.5

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Virtual Employee
3
+ Copyright (c) 2025
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,236 +1,14 @@
1
1
  # @nm-logger/logger
2
2
 
3
- Daily JSON logger for Node.js / Express APIs with:
4
-
5
- - S3 upload + queue + daily rotation
6
- - Correlation IDs (with `X-Correlation-ID` header)
7
- - External API logging (Axios)
8
- - Sensitive field masking (password, token, otp, etc.)
9
-
10
- ---
11
-
12
- ## Installation
13
-
14
- After you publish the package to npm:
15
-
16
- ```bash
17
- npm install @nm-logger/logger
18
- ```
19
-
20
- ---
21
-
22
- ## Log Format
23
-
24
- Each log line in `daily_logs.json` is a JSON object:
25
-
26
- ```json
27
- {
28
- "url": "/api/v1/attendance/get",
29
- "body": "{\"month\":\"2025-12\"}",
30
- "params": "{\"params\":{},\"query\":{}}",
31
- "type": "get",
32
- "error": "",
33
- "date": "2025-12-05 12:24:00",
34
- "employee_id": "TAKK122",
35
- "correlation_id": "cid-abcd1234-17f5d3c9a"
36
- }
37
- ```
38
-
39
- Fields:
40
-
41
- - `url` – `req.originalUrl`
42
- - `body` – stringified (and masked) `req.body`
43
- - `params` – stringified (and masked) object `{ params: req.params, query: req.query }`
44
- - `type` – last segment of the URL (e.g. `/api/v1/attendance/get` → `"get"`)
45
- - `error` – error message if any
46
- - `date` – `YYYY-MM-DD HH:mm:ss`
47
- - `employee_id` – from argument or `req.user.employee_id / emp_code / id`
48
- - `correlation_id` – unique per request chain (also added as `X-Correlation-ID` header)
49
-
50
- ---
51
-
52
- ## Basic Usage
53
-
54
- ### 1. Create the logger
55
-
56
- ```js
57
- const Logger = require("@nm-logger/logger");
58
-
59
- const logger = new Logger(
60
- {
61
- accessKeyId: process.env.AWS_KEY,
62
- secretAccessKey: process.env.AWS_SECRET,
63
- region: "ap-south-1",
64
- bucket: "your-log-bucket-name"
65
- },
66
- {
67
- baseDir: "logs", // optional, default "logs"
68
- watchIntervalMs: 60000, // optional, default 60s
69
- maskFields: ["aadhaar", "panNumber"] // extra fields to mask
70
- }
71
- );
72
- ```
73
-
74
- ### 2. Log every request + set correlation ID header
75
-
76
- ```js
77
- app.use(logger.requestLoggerMiddleware());
78
- ```
79
-
80
- ### 3. Log errors via Express error middleware
81
-
82
- ```js
83
- // your routes above...
84
-
85
- app.use(logger.expressMiddleware()); // or logger.expressErrorMiddleware()
86
- ```
87
-
88
- ### 4. Manual logging in routes
89
-
90
- ```js
91
- app.post("/api/v1/attendance/get", async (req, res) => {
92
- try {
93
- // ... your logic, external APIs etc ...
94
-
95
- await logger.logRequest(req, req.user?.employee_id);
96
- res.json({ success: true });
97
- } catch (err) {
98
- await logger.logError(err, req, req.user?.employee_id);
99
- res.status(500).json({ error: err.message });
100
- }
101
- });
102
- ```
103
-
104
- ---
105
-
106
- ## External API logging with Axios
107
-
108
- ```js
109
- const axios = require("axios");
110
-
111
- // Attach once at startup
112
- logger.attachAxiosLogger(axios);
113
-
114
- app.get("/api/v1/some-data", async (req, res) => {
115
- try {
116
- const response = await axios.get("https://api.example.com/data", {
117
- headers: {
118
- "X-Correlation-ID": req.correlationId, // propagated
119
- "X-Employee-ID": req.user?.employee_id || "" // optional
120
- },
121
- params: {
122
- id: 123
123
- }
124
- });
125
-
126
- res.json(response.data);
127
- } catch (err) {
128
- await logger.logError(err, req, req.user?.employee_id);
129
- res.status(500).json({ error: err.message });
130
- }
131
- });
132
- ```
133
-
134
- This will produce external log lines like:
135
-
136
- ```json
137
- {
138
- "url": "https://api.example.com/data",
139
- "body": "{}",
140
- "params": "{\"id\":123}",
141
- "type": "external_api",
142
- "error": "",
143
- "date": "2025-12-05 12:24:00",
144
- "employee_id": "TAKK122",
145
- "correlation_id": "cid-abcd1234-17f5d3c9a"
146
- }
147
- ```
148
-
149
- ---
150
-
151
- ## Sensitive Data Masking
152
-
153
- Built-in masked keys (case-insensitive, partial match):
154
-
155
- - password, pass
156
- - token, secret
157
- - otp
158
- - auth, authorization
159
- - apiKey, api_key
160
- - session
161
- - ssn
162
-
163
- Plus anything you pass in `maskFields` option.
164
-
165
- Any object like:
166
-
167
- ```json
168
- {
169
- "password": "MyPass123",
170
- "otp": "111222",
171
- "aadhaar": "9999-8888-7777",
172
- "email": "user@example.com"
173
- }
174
- ```
175
-
176
- will be logged as:
177
-
178
- ```json
179
- {
180
- "password": "*****",
181
- "otp": "*****",
182
- "aadhaar": "*****",
183
- "email": "user@example.com"
184
- }
185
- ```
186
-
187
- ---
188
-
189
- ## S3 Upload Behavior
190
-
191
- - Logs are stored locally under:
192
- - `logs/YYYY/MM/DD/daily_logs.json`
193
- - A watcher runs every `watchIntervalMs` (default 60 seconds)
194
- - When the date changes (e.g., from `2025-12-05` to `2025-12-06`),
195
- - The logger uploads the **previous day's** log file to S3:
196
-
197
- Example S3 key:
198
-
199
- ```txt
200
- 2025/12/05/daily_logs.json
201
- ```
202
-
203
- So final S3 path:
204
-
205
- ```txt
206
- s3://<bucket>/<year>/<month>/<day>/daily_logs.json
207
- ```
208
-
209
- ---
210
-
211
- ## TypeScript Usage
212
-
213
- ```ts
214
- import Logger, { S3Config, LoggerOptions } from "@ve/logger";
215
-
216
- const s3config: S3Config = {
217
- accessKeyId: process.env.AWS_KEY!,
218
- secretAccessKey: process.env.AWS_SECRET!,
219
- region: "ap-south-1",
220
- bucket: "your-log-bucket"
221
- };
222
-
223
- const options: LoggerOptions = {
224
- baseDir: "logs",
225
- watchIntervalMs: 60000,
226
- maskFields: ["aadhaar", "pan"]
227
- };
228
-
229
- const logger = new Logger(s3config, options);
230
- ```
231
-
232
- ---
233
-
234
- ## License
235
-
236
- MIT
3
+ Express JSON logger with:
4
+
5
+ - Per-request logging (success, error, external API)
6
+ - Separate daily files:
7
+ - `daily_logs_success.json`
8
+ - `daily_logs_error.json`
9
+ - `daily_logs_external.json`
10
+ - Periodic S3 upload (and local file deletion)
11
+ - Correlation IDs (`X-Correlation-ID`)
12
+ - Sensitive field masking
13
+
14
+ See source comments for usage.
package/index.d.ts CHANGED
@@ -8,23 +8,9 @@ export interface S3Config {
8
8
  }
9
9
 
10
10
  export interface LoggerOptions {
11
- /**
12
- * Local base directory where logs are stored.
13
- * Default: "logs"
14
- */
15
11
  baseDir?: string;
16
-
17
- /**
18
- * Interval in milliseconds for the daily watcher to check for date change.
19
- * Default: 60000 (1 minute)
20
- */
21
- watchIntervalMs?: number;
22
-
23
- /**
24
- * Extra field names to mask in logs (in addition to built-in ones like password, token, otp, etc.).
25
- * Matching is case-insensitive and uses "includes".
26
- */
27
12
  maskFields?: string[];
13
+ uploadIntervalMs?: number;
28
14
  }
29
15
 
30
16
  export interface LogEntryShape {
@@ -32,10 +18,12 @@ export interface LogEntryShape {
32
18
  body: string;
33
19
  params: string;
34
20
  type: string;
21
+ method: string;
35
22
  error: string;
36
- date: string;
37
23
  employee_id: string;
38
24
  correlation_id: string;
25
+ date: string;
26
+ category: string;
39
27
  }
40
28
 
41
29
  export interface ExternalApiLogOptions {
@@ -51,32 +39,10 @@ export interface ExternalApiLogOptions {
51
39
  declare class Logger {
52
40
  constructor(s3config?: S3Config, options?: LoggerOptions);
53
41
 
54
- /**
55
- * Log an error for a given request.
56
- * The log will be appended to the daily JSON file.
57
- */
58
- logError(
59
- err: any,
60
- req?: express.Request,
61
- employee_id?: string
62
- ): Promise<void>;
63
-
64
- /**
65
- * Log a normal API request (no error).
66
- */
42
+ logError(err: any, req?: express.Request, employee_id?: string): Promise<void>;
67
43
  logRequest(req: express.Request, employee_id?: string): Promise<void>;
68
-
69
- /**
70
- * Log an external API call (axios, etc.).
71
- * Type will be "external_api".
72
- */
73
44
  logExternalApi(options: ExternalApiLogOptions): Promise<void>;
74
45
 
75
- /**
76
- * Express error-handling middleware.
77
- * Use: app.use(logger.expressMiddleware());
78
- * Also ensures X-Correlation-ID header is present.
79
- */
80
46
  expressMiddleware(): (
81
47
  err: any,
82
48
  req: express.Request,
@@ -84,9 +50,6 @@ declare class Logger {
84
50
  next: express.NextFunction
85
51
  ) => void;
86
52
 
87
- /**
88
- * Alias for expressMiddleware (for clarity).
89
- */
90
53
  expressErrorMiddleware(): (
91
54
  err: any,
92
55
  req: express.Request,
@@ -94,23 +57,12 @@ declare class Logger {
94
57
  next: express.NextFunction
95
58
  ) => void;
96
59
 
97
- /**
98
- * Express request-logging middleware (non-error).
99
- * Also generates/propagates correlation ID and sets X-Correlation-ID header.
100
- * Use near the top of your middleware chain.
101
- */
102
60
  requestLoggerMiddleware(): (
103
61
  req: express.Request,
104
62
  res: express.Response,
105
63
  next: express.NextFunction
106
64
  ) => void;
107
65
 
108
- /**
109
- * Attach axios interceptors to log external API calls.
110
- * Usage:
111
- * const axios = require("axios");
112
- * logger.attachAxiosLogger(axios);
113
- */
114
66
  attachAxiosLogger(axiosInstance: any): void;
115
67
  }
116
68
 
package/index.js CHANGED
@@ -1,4 +1,3 @@
1
1
  const Logger = require("./src/Logger");
2
-
3
2
  module.exports = Logger;
4
3
  module.exports.Logger = Logger;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nm-logger/logger",
3
- "version": "1.1.2",
4
- "description": "Daily JSON logger with S3 upload queue, correlation IDs, external API logging, and sensitive field masking for Express-based APIs.",
3
+ "version": "1.1.5",
4
+ "description": "Express JSON logger with S3 upload, correlation IDs, and separate success/error/external daily logs.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
7
  "scripts": {
@@ -16,11 +16,9 @@
16
16
  "json-logger",
17
17
  "daily-logs",
18
18
  "correlation-id",
19
- "axios",
20
- "masking"
19
+ "axios"
21
20
  ],
22
- "author": "Virtual Employee (https://virtualemployee.com)",
23
- "homepage": "https://virtualemployee.com",
21
+ "author": "nm-logger",
24
22
  "license": "MIT",
25
23
  "dependencies": {
26
24
  "aws-sdk": "^2.1554.0",
@@ -34,4 +32,4 @@
34
32
  "@types/node": "^22.0.0",
35
33
  "typescript": "^5.6.0"
36
34
  }
37
- }
35
+ }
@@ -1,51 +1,56 @@
1
- const { getDatePath } = require("./utils");
2
- const path = require("path");
3
1
  const fs = require("fs-extra");
2
+ const path = require("path");
3
+ const { getDatePath } = require("./utils");
4
+
5
+ const CATEGORY_FILE_MAP = {
6
+ success: "daily_logs_success.json",
7
+ error: "daily_logs_error.json",
8
+ external: "daily_logs_external.json"
9
+ };
4
10
 
5
11
  class DailyWatcher {
6
12
  constructor(baseDir, queue, s3Uploader, options = {}) {
7
13
  this.baseDir = baseDir;
8
14
  this.queue = queue;
9
15
  this.s3Uploader = s3Uploader;
10
- this.intervalMs = options.watchIntervalMs || 60_000; // default: 1 minute
16
+ this.intervalMs = options.uploadIntervalMs || 60_000; // default 1 minute
11
17
 
12
- this.lastDay = null;
13
- this.startWatching();
18
+ console.log(
19
+ "⏱ [@nm-logger/logger] periodic S3 upload every",
20
+ this.intervalMs,
21
+ "ms"
22
+ );
23
+
24
+ this.start();
14
25
  }
15
26
 
16
- startWatching() {
27
+ start() {
17
28
  setInterval(() => {
18
29
  const { Y, M, D } = getDatePath();
19
- const currentDay = `${Y}-${M}-${D}`;
20
-
21
- if (!this.lastDay) {
22
- // First run, just set lastDay
23
- this.lastDay = currentDay;
24
- return;
25
- }
26
30
 
27
- if (this.lastDay !== currentDay) {
28
- // Day changed → upload previous day's log
29
- const lastDayPath = this.lastDay.replace(/-/g, "/");
30
-
31
- const logFile = path.join(
31
+ Object.entries(CATEGORY_FILE_MAP).forEach(([category, fileName]) => {
32
+ const file = path.join(
32
33
  this.baseDir,
33
- lastDayPath,
34
- "daily_logs.json"
34
+ `${Y}/${M}/${D}`,
35
+ fileName
35
36
  );
37
+ const key = `${Y}/${M}/${D}/${fileName}`;
36
38
 
37
- if (fs.existsSync(logFile)) {
38
- const s3Key = `${lastDayPath}/daily_logs.json`; // e.g. 2025/12/05/daily_logs.json
39
-
40
- this.queue.add(async () => {
41
- console.log("📤 Uploading previous day logs →", s3Key);
42
- await this.s3Uploader.upload(logFile, s3Key);
43
- });
39
+ if (!fs.existsSync(file)) {
40
+ return;
44
41
  }
45
42
 
46
- // update lastDay to current
47
- this.lastDay = currentDay;
48
- }
43
+ this.queue.add(async () => {
44
+ try {
45
+ console.log(`📤 Uploading [${category}] logs to S3:`, key);
46
+ await this.s3Uploader.upload(file, key);
47
+ console.log("✅ Uploaded. Deleting local file:", file);
48
+ await fs.remove(file);
49
+ } catch (err) {
50
+ console.error(`❌ Error uploading [${category}] logs to S3:`, err);
51
+ }
52
+ });
53
+ });
49
54
  }, this.intervalMs);
50
55
  }
51
56
  }
package/src/LogWriter.js CHANGED
@@ -2,27 +2,61 @@ const fs = require("fs-extra");
2
2
  const path = require("path");
3
3
  const { getDatePath, formatDate } = require("./utils");
4
4
 
5
+ const CATEGORY_FILE_MAP = {
6
+ success: "daily_logs_success.json",
7
+ error: "daily_logs_error.json",
8
+ external: "daily_logs_external.json"
9
+ };
10
+
5
11
  class LogWriter {
6
12
  constructor(baseDir = "logs") {
7
13
  this.baseDir = baseDir;
8
14
  }
9
15
 
10
- /**
11
- * Writes a single log entry in the required JSON format
12
- * and appends it as one line to daily_logs.json
13
- */
14
- async writeLog(log) {
15
- const { Y, M, D } = getDatePath();
16
- const logDir = path.join(this.baseDir, `${Y}/${M}/${D}`);
17
- const logFile = path.join(logDir, "daily_logs.json");
16
+ async writeLog(log, category = "success") {
17
+ const filePath = this.getFilePath(category);
18
+
19
+ await fs.ensureDir(path.dirname(filePath));
20
+
21
+ let logsWrapper = { logs: [] };
18
22
 
19
- await fs.ensureDir(logDir);
23
+ if (await fs.pathExists(filePath)) {
24
+ try {
25
+ const content = await fs.readFile(filePath, "utf8");
26
+ if (content.trim()) {
27
+ const parsed = JSON.parse(content);
28
+ if (Array.isArray(parsed.logs)) {
29
+ logsWrapper.logs = parsed.logs;
30
+ }
31
+ }
32
+ } catch (e) {
33
+ logsWrapper = { logs: [] };
34
+ }
35
+ }
20
36
 
21
- // Ensure date field is always set in required format
22
- log.date = formatDate(new Date());
37
+ const enriched = {
38
+ url: log.url || "",
39
+ body: log.body || "",
40
+ params: log.params || "",
41
+ type: log.type || "",
42
+ method: log.method || "",
43
+ error: log.error || "",
44
+ employee_id: log.employee_id || "",
45
+ correlation_id: log.correlation_id || "",
46
+ date: log.date || formatDate(new Date()),
47
+ category: category || ""
48
+ };
23
49
 
24
- await fs.appendFile(logFile, JSON.stringify(log) + "\n");
25
- return logFile;
50
+ logsWrapper.logs.push(enriched);
51
+
52
+ await fs.writeFile(filePath, JSON.stringify(logsWrapper, null, 2), "utf8");
53
+ return filePath;
54
+ }
55
+
56
+ getFilePath(category = "success") {
57
+ const { Y, M, D } = getDatePath();
58
+ const fileName = CATEGORY_FILE_MAP[category] || CATEGORY_FILE_MAP.success;
59
+ return path.join(this.baseDir, `${Y}/${M}/${D}/${fileName}`);
26
60
  }
27
61
  }
28
62
 
package/src/Logger.js CHANGED
@@ -16,30 +16,19 @@ class Logger {
16
16
  this.queue = new Queue();
17
17
  this.s3Uploader = new S3Uploader(s3config);
18
18
 
19
- // Extra fields user wants masked (e.g. ["aadhaar", "pan"])
20
19
  this.extraMaskFields = (options.maskFields || []).map((f) =>
21
20
  String(f).toLowerCase()
22
21
  );
23
22
 
24
- // Start daily watcher for S3 uploads
25
23
  new DailyWatcher(this.baseDir, this.queue, this.s3Uploader, {
26
- watchIntervalMs: options.watchIntervalMs
24
+ uploadIntervalMs: options.uploadIntervalMs
27
25
  });
28
26
  }
29
27
 
30
- /**
31
- * Mask any sensitive data using default + custom fields.
32
- */
33
28
  mask(value) {
34
29
  return maskSensitive(value, this.extraMaskFields);
35
30
  }
36
31
 
37
- /**
38
- * Build the base log entry with required shape.
39
- * {
40
- * url, body, params, type, error, date (added by LogWriter), employee_id, correlation_id
41
- * }
42
- */
43
32
  buildBaseLog(req, employee_id = "") {
44
33
  const url = req?.originalUrl || "";
45
34
  const bodySrc = req?.body || {};
@@ -51,18 +40,20 @@ class Logger {
51
40
  const maskedBody = this.mask(bodySrc);
52
41
  const maskedParams = this.mask(paramsObj);
53
42
 
54
- // derive correlation ID from request or headers
55
43
  let correlationId =
56
44
  req?.correlationId ||
57
45
  (req?.headers &&
58
46
  (req.headers["x-correlation-id"] || req.headers["X-Correlation-ID"])) ||
59
47
  "";
60
48
 
49
+ const method = (req?.method || "").toUpperCase();
50
+
61
51
  return {
62
52
  url,
63
53
  body: JSON.stringify(maskedBody || {}),
64
54
  params: JSON.stringify(maskedParams || {}),
65
55
  type: getApiType(url),
56
+ method,
66
57
  error: "",
67
58
  employee_id:
68
59
  employee_id ||
@@ -74,32 +65,20 @@ class Logger {
74
65
  };
75
66
  }
76
67
 
77
- /**
78
- * Log an error (incoming API).
79
- */
80
68
  async logError(err, req, employee_id = "") {
81
69
  const base = this.buildBaseLog(req || {}, employee_id);
82
-
83
70
  const logData = {
84
71
  ...base,
85
72
  error: err && err.message ? err.message : String(err || "")
86
73
  };
87
-
88
- await this.logWriter.writeLog(logData);
74
+ await this.logWriter.writeLog(logData, "error");
89
75
  }
90
76
 
91
- /**
92
- * Log a normal request (incoming API).
93
- */
94
77
  async logRequest(req, employee_id = "") {
95
78
  const logData = this.buildBaseLog(req, employee_id);
96
- await this.logWriter.writeLog(logData);
79
+ await this.logWriter.writeLog(logData, "success");
97
80
  }
98
81
 
99
- /**
100
- * Log an external API call (axios, etc.).
101
- * For external APIs, `type` is always "external_api".
102
- */
103
82
  async logExternalApi({
104
83
  url,
105
84
  method,
@@ -117,20 +96,16 @@ class Logger {
117
96
  body: JSON.stringify(maskedBody || {}),
118
97
  params: JSON.stringify(maskedParams || {}),
119
98
  type: "external_api",
99
+ method: (method || "").toUpperCase(),
120
100
  error: error || "",
121
- date: undefined, // set by LogWriter
122
101
  employee_id: employeeId || "",
123
- correlation_id: correlationId || ""
102
+ correlation_id: correlationId || "",
103
+ date: undefined
124
104
  };
125
105
 
126
- await this.logWriter.writeLog(logData);
106
+ await this.logWriter.writeLog(logData, "external");
127
107
  }
128
108
 
129
- /**
130
- * Express error-handling middleware.
131
- * Use: app.use(logger.expressMiddleware());
132
- * Also ensures correlation ID is present and added to response header.
133
- */
134
109
  expressMiddleware() {
135
110
  return (err, req, res, next) => {
136
111
  try {
@@ -161,22 +136,10 @@ class Logger {
161
136
  };
162
137
  }
163
138
 
164
- /**
165
- * Alias for expressMiddleware (for clarity).
166
- */
167
139
  expressErrorMiddleware() {
168
140
  return this.expressMiddleware();
169
141
  }
170
142
 
171
- /**
172
- * Express request-logging middleware.
173
- * - Generates or reuses correlation ID
174
- * - Sets X-Correlation-ID header on response
175
- * - Logs each incoming request
176
- *
177
- * Use near the top of middleware stack:
178
- * app.use(logger.requestLoggerMiddleware());
179
- */
180
143
  requestLoggerMiddleware() {
181
144
  return (req, res, next) => {
182
145
  try {
@@ -203,25 +166,10 @@ class Logger {
203
166
  };
204
167
  }
205
168
 
206
- /**
207
- * Attach axios interceptors to log EXTERNAL API calls.
208
- *
209
- * Usage:
210
- * const axios = require("axios");
211
- * logger.attachAxiosLogger(axios);
212
- *
213
- * In your route:
214
- * await axios.get("https://api.example.com", {
215
- * headers: {
216
- * "X-Correlation-ID": req.correlationId,
217
- * "X-Employee-ID": req.user?.employee_id
218
- * }
219
- * });
220
- */
221
169
  attachAxiosLogger(axiosInstance) {
222
170
  if (!axiosInstance || !axiosInstance.interceptors) {
223
171
  console.warn(
224
- "[@ve/logger] attachAxiosLogger: provided axios instance is invalid"
172
+ "[@nm-logger/logger] attachAxiosLogger: provided axios instance is invalid"
225
173
  );
226
174
  return;
227
175
  }
package/src/Queue.js CHANGED
@@ -11,7 +11,6 @@ class Queue {
11
11
 
12
12
  async run() {
13
13
  if (this.processing) return;
14
-
15
14
  this.processing = true;
16
15
 
17
16
  while (this.jobs.length) {
@@ -19,9 +18,7 @@ class Queue {
19
18
  try {
20
19
  await job();
21
20
  } catch (err) {
22
- console.error("Queue job failed → re-added to queue:", err);
23
- // Re-add the job for retry (very simple retry mechanism)
24
- this.jobs.push(job);
21
+ console.error("[@nm-logger/logger] Queue job failed:", err);
25
22
  }
26
23
  }
27
24
 
package/src/S3Uploader.js CHANGED
@@ -1,5 +1,5 @@
1
- const AWS = require("aws-sdk");
2
1
  const fs = require("fs");
2
+ const AWS = require("aws-sdk");
3
3
 
4
4
  class S3Uploader {
5
5
  constructor(config) {
@@ -8,7 +8,6 @@ class S3Uploader {
8
8
  secretAccessKey: config.secretAccessKey,
9
9
  region: config.region
10
10
  });
11
-
12
11
  this.bucket = config.bucket;
13
12
  }
14
13
 
package/src/utils.js CHANGED
@@ -1,4 +1,3 @@
1
- // Build path segments for logs: YYYY/MM/DD
2
1
  exports.getDatePath = () => {
3
2
  const now = new Date();
4
3
  const Y = now.getFullYear();
@@ -7,10 +6,8 @@ exports.getDatePath = () => {
7
6
  return { Y, M, D };
8
7
  };
9
8
 
10
- // Format date as: 2025-12-05 12:24:00
11
9
  exports.formatDate = (d) => {
12
10
  const pad = (n) => String(n).padStart(2, "0");
13
-
14
11
  return (
15
12
  d.getFullYear() +
16
13
  "-" +
@@ -26,15 +23,12 @@ exports.formatDate = (d) => {
26
23
  );
27
24
  };
28
25
 
29
- // Extract last segment from URL, used as "type"
30
- // e.g. "/api/v1/attendance/get" → "get"
31
26
  exports.getApiType = (url) => {
32
27
  if (!url) return "";
33
28
  const segments = url.split("/").filter(Boolean);
34
29
  return segments[segments.length - 1] || "";
35
30
  };
36
31
 
37
- // Default keys to mask (case-insensitive, "includes" match)
38
32
  const DEFAULT_MASK_KEYS = [
39
33
  "password",
40
34
  "pass",
@@ -49,12 +43,6 @@ const DEFAULT_MASK_KEYS = [
49
43
  "ssn"
50
44
  ];
51
45
 
52
- /**
53
- * Deep mask of sensitive fields in any object/array.
54
- * - Keys containing any of the mask keys are replaced with "*****"
55
- * - Works recursively
56
- * - If input is string, tries JSON.parse then masks
57
- */
58
46
  exports.maskSensitive = (value, extraFields = []) => {
59
47
  const allKeys = [
60
48
  ...DEFAULT_MASK_KEYS,
@@ -74,13 +62,7 @@ exports.maskSensitive = (value, extraFields = []) => {
74
62
  const out = {};
75
63
  for (const [k, v] of Object.entries(val)) {
76
64
  if (shouldMaskKey(k)) {
77
- if (v === null || v === undefined) {
78
- out[k] = v;
79
- } else if (typeof v === "string" && v.length) {
80
- out[k] = "*****";
81
- } else {
82
- out[k] = "*****";
83
- }
65
+ out[k] = "*****";
84
66
  } else {
85
67
  out[k] = maskAny(v);
86
68
  }
@@ -90,7 +72,6 @@ exports.maskSensitive = (value, extraFields = []) => {
90
72
  return val;
91
73
  };
92
74
 
93
- // If it's a string, try JSON.parse and mask
94
75
  if (typeof value === "string") {
95
76
  try {
96
77
  const parsed = JSON.parse(value);
@@ -103,7 +84,6 @@ exports.maskSensitive = (value, extraFields = []) => {
103
84
  return maskAny(value);
104
85
  };
105
86
 
106
- // Simple correlation ID generator
107
87
  exports.generateCorrelationId = () => {
108
88
  const rand = Math.random().toString(16).slice(2, 10);
109
89
  const ts = Date.now().toString(16);