@quartz-labs/logger 1.0.0 → 1.0.2
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/dist/config.d.ts +9 -0
- package/{src/config.ts → dist/config.js} +11 -12
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +11 -0
- package/{src/logger.ts → dist/logger.js} +17 -40
- package/dist/logger.js.map +1 -0
- package/{src/types/ErrorCacheEntry.interface.ts → dist/types/ErrorCacheEntry.interface.d.ts} +1 -1
- package/dist/types/ErrorCacheEntry.interface.js +2 -0
- package/dist/types/ErrorCacheEntry.interface.js.map +1 -0
- package/package.json +13 -2
- package/src/index.ts +0 -1
- package/tsconfig.json +0 -21
package/dist/config.d.ts
ADDED
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
import dotenv from 'dotenv';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
|
|
4
3
|
dotenv.config();
|
|
5
|
-
|
|
6
4
|
const envSchema = z.object({
|
|
7
5
|
EMAIL_TO: z.string()
|
|
8
6
|
.transform((str) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
try {
|
|
8
|
+
const emails = str.split(',').map(email => email.trim());
|
|
9
|
+
if (!emails.every(email => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)))
|
|
10
|
+
throw new Error();
|
|
11
|
+
return emails;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
throw new Error("Invalid email list format: must be comma-separated email addresses");
|
|
15
|
+
}
|
|
16
|
+
}),
|
|
17
17
|
EMAIL_FROM: z.string().email(),
|
|
18
18
|
EMAIL_HOST: z.string(),
|
|
19
19
|
EMAIL_PORT: z.coerce.number().min(0),
|
|
20
20
|
EMAIL_USER: z.string().email(),
|
|
21
21
|
EMAIL_PASSWORD: z.string(),
|
|
22
22
|
});
|
|
23
|
-
|
|
24
23
|
const config = envSchema.parse({
|
|
25
24
|
EMAIL_TO: process.env.EMAIL_TO,
|
|
26
25
|
EMAIL_FROM: process.env.EMAIL_FROM,
|
|
@@ -29,5 +28,5 @@ const config = envSchema.parse({
|
|
|
29
28
|
EMAIL_USER: process.env.EMAIL_USER,
|
|
30
29
|
EMAIL_PASSWORD: process.env.EMAIL_PASSWORD,
|
|
31
30
|
});
|
|
32
|
-
|
|
33
31
|
export default config;
|
|
32
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACvB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;SACf,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;QACf,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACzD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAAE,MAAM,IAAI,KAAK,EAAE,CAAC;YACxF,OAAO,MAAM,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACL,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;QAC1F,CAAC;IACL,CAAC,CAAC;IACN,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;IAC9B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;IAC9B,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;CAC7B,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ;IAC9B,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;IAClC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;IAClC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;IAClC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;IAClC,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;CAC7C,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AppLogger } from "./logger.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Logger } from "winston";
|
|
2
|
+
export interface AppLoggerOptions {
|
|
3
|
+
name: string;
|
|
4
|
+
dailyErrorCacheTimeMs?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class AppLogger {
|
|
7
|
+
protected logger: Logger;
|
|
8
|
+
private dailyErrorCache;
|
|
9
|
+
private dailyErrorCacheTimeMs;
|
|
10
|
+
constructor(options: AppLoggerOptions);
|
|
11
|
+
}
|
|
@@ -1,37 +1,23 @@
|
|
|
1
1
|
import { Writable } from "node:stream";
|
|
2
|
-
import winston, { createLogger,
|
|
2
|
+
import winston, { createLogger, transports } from "winston";
|
|
3
3
|
import nodemailer from "nodemailer";
|
|
4
4
|
import config from "./config.js";
|
|
5
|
-
import type { ErrorCacheEntry } from "./types/ErrorCacheEntry.interface.js";
|
|
6
|
-
|
|
7
|
-
export interface AppLoggerOptions {
|
|
8
|
-
name: string;
|
|
9
|
-
dailyErrorCacheTimeMs: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
5
|
export class AppLogger {
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
logger;
|
|
7
|
+
dailyErrorCache = new Map();
|
|
15
8
|
// TODO: Clear cache once a day
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
const mailFormat = winston.format.combine(
|
|
31
|
-
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
|
32
|
-
winston.format.json({ space: 2})
|
|
33
|
-
)
|
|
34
|
-
|
|
9
|
+
dailyErrorCacheTimeMs;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
if (options.dailyErrorCacheTimeMs === undefined || options.dailyErrorCacheTimeMs < 0) {
|
|
12
|
+
this.dailyErrorCacheTimeMs = 0;
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
this.dailyErrorCacheTimeMs = options.dailyErrorCacheTimeMs;
|
|
16
|
+
}
|
|
17
|
+
const consoleFormat = winston.format.combine(winston.format.colorize(), winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf(({ level, message, timestamp }) => {
|
|
18
|
+
return `[${timestamp}] ${level}: ${message}`;
|
|
19
|
+
}));
|
|
20
|
+
const mailFormat = winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.json({ space: 2 }));
|
|
35
21
|
const mailTransporter = nodemailer.createTransport({
|
|
36
22
|
host: config.EMAIL_HOST,
|
|
37
23
|
port: config.EMAIL_PORT,
|
|
@@ -41,24 +27,20 @@ export class AppLogger {
|
|
|
41
27
|
pass: config.EMAIL_PASSWORD,
|
|
42
28
|
},
|
|
43
29
|
});
|
|
44
|
-
|
|
45
30
|
const dailyErrorCacheTimeMinutes = Math.round(this.dailyErrorCacheTimeMs / 1000 / 60);
|
|
46
31
|
const mailTransportInstance = new winston.transports.Stream({
|
|
47
32
|
stream: new Writable({
|
|
48
33
|
write: (message, _, callback) => {
|
|
49
34
|
const parsedMessage = JSON.parse(message);
|
|
50
35
|
const cacheKey = `${parsedMessage.level}: ${parsedMessage.message}`;
|
|
51
|
-
|
|
52
36
|
const now = Date.now();
|
|
53
37
|
const cacheEntry = this.dailyErrorCache.get(cacheKey) || { count: 0, lastSent: 0 };
|
|
54
38
|
cacheEntry.count++;
|
|
55
|
-
|
|
56
39
|
// Only send email if error has not been sent in the last errorEmailCacheTime seconds
|
|
57
40
|
if (now - cacheEntry.lastSent > this.dailyErrorCacheTimeMs) {
|
|
58
41
|
const emailSubject = this.dailyErrorCacheTimeMs > 0
|
|
59
42
|
? `${options.name} Error (${cacheEntry.count} occurrences in past ${dailyErrorCacheTimeMinutes} minutes)`
|
|
60
43
|
: `${options.name} Error`;
|
|
61
|
-
|
|
62
44
|
for (const admin of config.EMAIL_TO) {
|
|
63
45
|
mailTransporter.sendMail({
|
|
64
46
|
from: config.EMAIL_FROM,
|
|
@@ -69,13 +51,10 @@ export class AppLogger {
|
|
|
69
51
|
console.error("Failed to send error email: ", error);
|
|
70
52
|
});
|
|
71
53
|
}
|
|
72
|
-
|
|
73
54
|
cacheEntry.count = 0;
|
|
74
55
|
cacheEntry.lastSent = now;
|
|
75
56
|
}
|
|
76
|
-
|
|
77
57
|
this.dailyErrorCache.set(cacheKey, cacheEntry);
|
|
78
|
-
|
|
79
58
|
callback();
|
|
80
59
|
return true;
|
|
81
60
|
}
|
|
@@ -83,7 +62,6 @@ export class AppLogger {
|
|
|
83
62
|
level: 'error',
|
|
84
63
|
format: mailFormat,
|
|
85
64
|
});
|
|
86
|
-
|
|
87
65
|
this.logger = createLogger({
|
|
88
66
|
level: 'info',
|
|
89
67
|
transports: [
|
|
@@ -99,13 +77,12 @@ export class AppLogger {
|
|
|
99
77
|
mailTransportInstance
|
|
100
78
|
],
|
|
101
79
|
});
|
|
102
|
-
|
|
103
80
|
process.on("uncaughtException", (error) => {
|
|
104
81
|
this.logger.error(error.message);
|
|
105
82
|
});
|
|
106
|
-
|
|
107
83
|
process.on("unhandledRejection", (reason) => {
|
|
108
84
|
this.logger.error(reason);
|
|
109
85
|
});
|
|
110
86
|
}
|
|
111
|
-
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,OAAO,EAAE,EAAE,YAAY,EAAe,UAAU,EAAE,MAAM,SAAS,CAAC;AACzE,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,MAAM,MAAM,aAAa,CAAC;AAQjC,MAAM,OAAO,SAAS;IACR,MAAM,CAAS;IACjB,eAAe,GAAG,IAAI,GAAG,EAA2B,CAAC;IAC7D,+BAA+B;IACvB,qBAAqB,CAAS;IAEtC,YAAY,OAAyB;QACjC,IAAI,OAAO,CAAC,qBAAqB,KAAK,SAAS,IAAI,OAAO,CAAC,qBAAqB,GAAG,CAAC,EAAE,CAAC;YACnF,IAAI,CAAC,qBAAqB,GAAG,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC;QAC/D,CAAC;QAED,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,EACzB,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,EAC3D,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE;YACpD,OAAO,IAAI,SAAS,KAAK,KAAK,KAAK,OAAO,EAAE,CAAC;QACjD,CAAC,CAAC,CACL,CAAA;QAED,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CACrC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,EAC3D,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAC,CAAC,CACnC,CAAA;QAED,MAAM,eAAe,GAAG,UAAU,CAAC,eAAe,CAAC;YAC/C,IAAI,EAAE,MAAM,CAAC,UAAU;YACvB,IAAI,EAAE,MAAM,CAAC,UAAU;YACvB,MAAM,EAAE,KAAK;YACb,IAAI,EAAE;gBACF,IAAI,EAAE,MAAM,CAAC,UAAU;gBACvB,IAAI,EAAE,MAAM,CAAC,cAAc;aAC9B;SACJ,CAAC,CAAC;QAEH,MAAM,0BAA0B,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC;QACtF,MAAM,qBAAqB,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;YACxD,MAAM,EAAE,IAAI,QAAQ,CAAC;gBACjB,KAAK,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE;oBAC5B,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAC1C,MAAM,QAAQ,GAAG,GAAG,aAAa,CAAC,KAAK,KAAK,aAAa,CAAC,OAAO,EAAE,CAAC;oBAEpE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBACvB,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;oBACnF,UAAU,CAAC,KAAK,EAAE,CAAC;oBAEnB,qFAAqF;oBACrF,IAAI,GAAG,GAAG,UAAU,CAAC,QAAQ,GAAG,IAAI,CAAC,qBAAqB,EAAE,CAAC;wBACzD,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAqB,GAAG,CAAC;4BAC/C,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,WAAW,UAAU,CAAC,KAAK,wBAAwB,0BAA0B,WAAW;4BACzG,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,QAAQ,CAAC;wBAE9B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;4BAClC,eAAe,CAAC,QAAQ,CAAC;gCACrB,IAAI,EAAE,MAAM,CAAC,UAAU;gCACvB,EAAE,EAAE,KAAK;gCACT,OAAO,EAAE,YAAY;gCACrB,IAAI,EAAE,OAAO;6BAChB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gCACf,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;4BACzD,CAAC,CAAC,CAAC;wBACP,CAAC;wBAED,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC;wBACrB,UAAU,CAAC,QAAQ,GAAG,GAAG,CAAC;oBAC9B,CAAC;oBAED,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;oBAE/C,QAAQ,EAAE,CAAC;oBACX,OAAO,IAAI,CAAC;gBAChB,CAAC;aACJ,CAAC;YACF,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,UAAU;SACrB,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC;YACvB,KAAK,EAAE,MAAM;YACb,UAAU,EAAE;gBACR,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;gBACjD,qBAAqB;aACxB;YACD,iBAAiB,EAAE;gBACf,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;gBACjD,qBAAqB;aACxB;YACD,iBAAiB,EAAE;gBACf,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;gBACjD,qBAAqB;aACxB;SACJ,CAAC,CAAC;QAEH,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE;YACtC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;YACxC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACP,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorCacheEntry.interface.js","sourceRoot":"","sources":["../../src/types/ErrorCacheEntry.interface.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quartz-labs/logger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Logger class for outputting logs and emailing any errors to admins",
|
|
5
|
-
"main": "index.js",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
6
17
|
"type": "module",
|
|
7
18
|
"repository": "https://github.com/quartz-labs/logger.git",
|
|
8
19
|
"author": "Quartz Labs",
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { AppLogger } from "./logger.js";
|
package/tsconfig.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"esModuleInterop": true,
|
|
4
|
-
"skipLibCheck": true,
|
|
5
|
-
"target": "es2022",
|
|
6
|
-
"allowJs": true,
|
|
7
|
-
"resolveJsonModule": true,
|
|
8
|
-
"moduleDetection": "force",
|
|
9
|
-
"isolatedModules": true,
|
|
10
|
-
"verbatimModuleSyntax": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"noUncheckedIndexedAccess": true,
|
|
13
|
-
"noImplicitOverride": true,
|
|
14
|
-
"module": "NodeNext",
|
|
15
|
-
"outDir": "dist",
|
|
16
|
-
"rootDir": "src",
|
|
17
|
-
"sourceMap": true,
|
|
18
|
-
"declaration": true,
|
|
19
|
-
"lib": ["es2022"],
|
|
20
|
-
}
|
|
21
|
-
}
|