-
Notifications
You must be signed in to change notification settings - Fork 0
/
logger.js
108 lines (97 loc) · 2.82 KB
/
logger.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
const winston = require("winston");
const Sequelize = require("sequelize");
const EventEmitter = require("events");
function safeStringify(obj, space = 2) {
const seen = new WeakSet();
const replacer = (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return "[Circular]";
}
seen.add(value);
if (value instanceof Sequelize.Model) {
return value.get({ plain: true });
}
if (value.isJoi) {
return `Joi Schema for ${value.type}`;
}
if (value instanceof Map) {
return Array.from(value.entries());
}
if (value instanceof Set) {
return Array.from(value);
}
if (value instanceof Date) {
return value.toISOString();
}
if (value instanceof Error) {
const errorDetails = {};
Object.getOwnPropertyNames(value).forEach((prop) => {
errorDetails[prop] = value[prop];
});
return errorDetails;
}
if (value.constructor === Object) {
const sortedObj = {};
Object.keys(value)
.sort()
.forEach((key) => {
sortedObj[key] = value[key];
});
return sortedObj;
}
} else if (typeof value === "bigint") {
return value.toString();
}
return value;
};
return JSON.stringify(obj, replacer, space);
}
const customFormatter = winston.format((info) => {
const formattedInfo = { ...info };
Object.keys(formattedInfo).forEach((key) => {
if (formattedInfo[key] instanceof Date) {
formattedInfo[key] = formattedInfo[key].toISOString();
}
});
return formattedInfo;
});
let transports = [
new winston.transports.File({ filename: "error.log", level: "error" }),
new winston.transports.File({ filename: "combined.log" }),
];
if (process.env.USE_WINSTON_TRANSPORTS_CONSOLE === '1') {
transports.push(
new winston.transports.Console({
format: winston.format.simple(),
})
)
}
const logger = winston.createLogger({
level: "info",
format: winston.format.combine(
customFormatter(),
winston.format.timestamp(),
winston.format.json()
),
transports,
});
const logEmitter = new EventEmitter();
const logBuffer = [];
const MAX_LOG_ENTRIES = 100;
logger.on("data", (logEntry) => {
const logEntryString = safeStringify(logEntry);
logBuffer.push(logEntryString);
if (logBuffer.length > MAX_LOG_ENTRIES) {
logBuffer.shift();
}
logEmitter.emit("newLog", logEntryString);
});
// Intercept logs and emit events
const originalLog = logger.log.bind(logger);
logger.log = (level, msg, meta) => {
originalLog(level, msg, meta);
const logEntry = { level, msg, meta, timestamp: new Date().toISOString() };
logEmitter.emit("newLog", safeStringify(logEntry));
};
module.exports = { logger, logEmitter, logBuffer, safeStringify };