@rawnodes/logger 2.5.0 → 2.7.0
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/README.md +62 -0
- package/dist/index.d.mts +98 -6
- package/dist/index.d.ts +98 -6
- package/dist/index.js +233 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +231 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -1
package/dist/index.js
CHANGED
|
@@ -689,6 +689,7 @@ function createFormattedFilterStream(format, level, rules, store, destination) {
|
|
|
689
689
|
}
|
|
690
690
|
function createStreams(config, store) {
|
|
691
691
|
const streams = [];
|
|
692
|
+
const transports = [];
|
|
692
693
|
const consoleStream = createFormattedFilterStream(
|
|
693
694
|
config.console.format,
|
|
694
695
|
config.console.level,
|
|
@@ -736,6 +737,7 @@ function createStreams(config, store) {
|
|
|
736
737
|
}
|
|
737
738
|
for (const discordConfig of toArray(config.discord)) {
|
|
738
739
|
const transport = new DiscordTransport(discordConfig);
|
|
740
|
+
transports.push(transport);
|
|
739
741
|
const discordStream = createHttpTransportStream(transport, discordConfig.level, discordConfig.rules, store);
|
|
740
742
|
streams.push({
|
|
741
743
|
level: "trace",
|
|
@@ -744,6 +746,7 @@ function createStreams(config, store) {
|
|
|
744
746
|
}
|
|
745
747
|
for (const telegramConfig of toArray(config.telegram)) {
|
|
746
748
|
const transport = new TelegramTransport(telegramConfig);
|
|
749
|
+
transports.push(transport);
|
|
747
750
|
const telegramStream = createHttpTransportStream(transport, telegramConfig.level, telegramConfig.rules, store);
|
|
748
751
|
streams.push({
|
|
749
752
|
level: "trace",
|
|
@@ -752,13 +755,17 @@ function createStreams(config, store) {
|
|
|
752
755
|
}
|
|
753
756
|
for (const cloudwatchConfig of toArray(config.cloudwatch)) {
|
|
754
757
|
const transport = new CloudWatchTransport(cloudwatchConfig, config.hostname);
|
|
758
|
+
transports.push(transport);
|
|
755
759
|
const cwStream = createHttpTransportStream(transport, cloudwatchConfig.level, cloudwatchConfig.rules, store);
|
|
756
760
|
streams.push({
|
|
757
761
|
level: "trace",
|
|
758
762
|
stream: cwStream
|
|
759
763
|
});
|
|
760
764
|
}
|
|
761
|
-
return
|
|
765
|
+
return {
|
|
766
|
+
destination: pino__default.default.multistream(streams),
|
|
767
|
+
transports
|
|
768
|
+
};
|
|
762
769
|
}
|
|
763
770
|
function toArray(value) {
|
|
764
771
|
if (!value) return [];
|
|
@@ -843,14 +850,14 @@ function createState(config, store) {
|
|
|
843
850
|
levelOverrides.set(key, rule);
|
|
844
851
|
}
|
|
845
852
|
const { contextIndex, complexRules } = buildIndexes(levelOverrides);
|
|
846
|
-
const
|
|
853
|
+
const { destination, transports } = createStreams(config, loggerStore);
|
|
847
854
|
const options = {
|
|
848
855
|
level: "trace",
|
|
849
856
|
// Accept all, we filter in shouldLog()
|
|
850
857
|
customLevels: CUSTOM_LEVELS,
|
|
851
858
|
base: { hostname: config.hostname ?? os.hostname() }
|
|
852
859
|
};
|
|
853
|
-
const pinoLogger = pino__default.default(options,
|
|
860
|
+
const pinoLogger = pino__default.default(options, destination);
|
|
854
861
|
let callerConfig;
|
|
855
862
|
if (config.caller === true) {
|
|
856
863
|
callerConfig = {};
|
|
@@ -864,7 +871,8 @@ function createState(config, store) {
|
|
|
864
871
|
levelOverrides,
|
|
865
872
|
contextIndex,
|
|
866
873
|
complexRules,
|
|
867
|
-
callerConfig
|
|
874
|
+
callerConfig,
|
|
875
|
+
transports
|
|
868
876
|
};
|
|
869
877
|
}
|
|
870
878
|
function rebuildIndexes(state) {
|
|
@@ -1010,6 +1018,10 @@ var CallerConfigSchema = zod.z.object({
|
|
|
1010
1018
|
depth: zod.z.number().int().nonnegative().optional(),
|
|
1011
1019
|
fullPath: zod.z.boolean().optional()
|
|
1012
1020
|
});
|
|
1021
|
+
var AutoShutdownConfigSchema = zod.z.object({
|
|
1022
|
+
timeout: zod.z.number().int().positive().optional(),
|
|
1023
|
+
signals: zod.z.array(zod.z.string()).optional()
|
|
1024
|
+
});
|
|
1013
1025
|
var LoggerConfigSchema = zod.z.object({
|
|
1014
1026
|
level: LevelConfigSchema,
|
|
1015
1027
|
console: ConsoleConfigSchema,
|
|
@@ -1018,7 +1030,8 @@ var LoggerConfigSchema = zod.z.object({
|
|
|
1018
1030
|
telegram: zod.z.union([TelegramConfigSchema, zod.z.array(TelegramConfigSchema)]).optional(),
|
|
1019
1031
|
cloudwatch: zod.z.union([CloudWatchConfigSchema, zod.z.array(CloudWatchConfigSchema)]).optional(),
|
|
1020
1032
|
caller: zod.z.union([zod.z.boolean(), CallerConfigSchema]).optional(),
|
|
1021
|
-
hostname: zod.z.string().optional()
|
|
1033
|
+
hostname: zod.z.string().optional(),
|
|
1034
|
+
autoShutdown: zod.z.union([zod.z.boolean(), AutoShutdownConfigSchema]).optional()
|
|
1022
1035
|
});
|
|
1023
1036
|
function validateConfig(config) {
|
|
1024
1037
|
return LoggerConfigSchema.parse(config);
|
|
@@ -1087,6 +1100,176 @@ function formatCallerInfo(info) {
|
|
|
1087
1100
|
return location;
|
|
1088
1101
|
}
|
|
1089
1102
|
|
|
1103
|
+
// src/utils/shutdown.ts
|
|
1104
|
+
var DEFAULT_OPTIONS2 = {
|
|
1105
|
+
timeout: 5e3,
|
|
1106
|
+
exitCode: 0,
|
|
1107
|
+
signals: ["SIGTERM", "SIGINT"]
|
|
1108
|
+
};
|
|
1109
|
+
var registered = false;
|
|
1110
|
+
function registerShutdown(logger, options = {}) {
|
|
1111
|
+
const opts = { ...DEFAULT_OPTIONS2, ...options };
|
|
1112
|
+
const shutdown = async (signal) => {
|
|
1113
|
+
if (signal) {
|
|
1114
|
+
console.error(`[Logger] Received ${signal}, shutting down gracefully...`);
|
|
1115
|
+
}
|
|
1116
|
+
try {
|
|
1117
|
+
if (opts.onShutdown) {
|
|
1118
|
+
await opts.onShutdown();
|
|
1119
|
+
}
|
|
1120
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1121
|
+
setTimeout(() => {
|
|
1122
|
+
reject(new Error(`Shutdown timed out after ${opts.timeout}ms`));
|
|
1123
|
+
}, opts.timeout);
|
|
1124
|
+
});
|
|
1125
|
+
await Promise.race([
|
|
1126
|
+
logger.shutdown(),
|
|
1127
|
+
timeoutPromise
|
|
1128
|
+
]);
|
|
1129
|
+
if (signal) {
|
|
1130
|
+
console.error("[Logger] Graceful shutdown completed");
|
|
1131
|
+
process.exit(opts.exitCode);
|
|
1132
|
+
}
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
console.error("[Logger] Shutdown error:", error instanceof Error ? error.message : error);
|
|
1135
|
+
if (signal) {
|
|
1136
|
+
process.exit(1);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
if (!registered) {
|
|
1141
|
+
for (const signal of opts.signals) {
|
|
1142
|
+
process.on(signal, () => void shutdown(signal));
|
|
1143
|
+
}
|
|
1144
|
+
process.on("beforeExit", () => void shutdown());
|
|
1145
|
+
registered = true;
|
|
1146
|
+
}
|
|
1147
|
+
return shutdown;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// src/utils/error.ts
|
|
1151
|
+
function isAxiosError(error) {
|
|
1152
|
+
return error !== null && typeof error === "object" && "isAxiosError" in error && error.isAxiosError === true;
|
|
1153
|
+
}
|
|
1154
|
+
function sanitizeResponseData(data, maxStringLength = 1e4) {
|
|
1155
|
+
if (data === null || data === void 0) {
|
|
1156
|
+
return data;
|
|
1157
|
+
}
|
|
1158
|
+
if (typeof data === "string") {
|
|
1159
|
+
return data.length > maxStringLength ? `${data.slice(0, maxStringLength)}...[truncated]` : data;
|
|
1160
|
+
}
|
|
1161
|
+
if (typeof data === "number" || typeof data === "boolean") {
|
|
1162
|
+
return data;
|
|
1163
|
+
}
|
|
1164
|
+
if (Array.isArray(data)) {
|
|
1165
|
+
return data.slice(0, 100).map((item) => sanitizeResponseData(item, maxStringLength));
|
|
1166
|
+
}
|
|
1167
|
+
if (typeof data === "object") {
|
|
1168
|
+
const result = {};
|
|
1169
|
+
const entries = Object.entries(data);
|
|
1170
|
+
for (const [key, value] of entries.slice(0, 50)) {
|
|
1171
|
+
result[key] = sanitizeResponseData(value, maxStringLength);
|
|
1172
|
+
}
|
|
1173
|
+
return result;
|
|
1174
|
+
}
|
|
1175
|
+
return String(data);
|
|
1176
|
+
}
|
|
1177
|
+
function extractAxiosHttpData(error) {
|
|
1178
|
+
const httpData = {};
|
|
1179
|
+
if (error.code) {
|
|
1180
|
+
httpData.code = error.code;
|
|
1181
|
+
}
|
|
1182
|
+
if (error.response) {
|
|
1183
|
+
httpData.status = error.response.status;
|
|
1184
|
+
httpData.statusText = error.response.statusText;
|
|
1185
|
+
if (error.response.data !== void 0) {
|
|
1186
|
+
httpData.responseData = sanitizeResponseData(error.response.data);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
if (error.config) {
|
|
1190
|
+
const { url, baseURL, method } = error.config;
|
|
1191
|
+
if (url) {
|
|
1192
|
+
httpData.url = baseURL && !url.startsWith("http") ? `${baseURL}${url}` : url;
|
|
1193
|
+
}
|
|
1194
|
+
if (method) {
|
|
1195
|
+
httpData.method = method.toUpperCase();
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
return httpData;
|
|
1199
|
+
}
|
|
1200
|
+
function extractGenericHttpData(error) {
|
|
1201
|
+
const httpData = {};
|
|
1202
|
+
let hasData = false;
|
|
1203
|
+
if (typeof error.code === "string") {
|
|
1204
|
+
httpData.code = error.code;
|
|
1205
|
+
hasData = true;
|
|
1206
|
+
}
|
|
1207
|
+
const response = error.response;
|
|
1208
|
+
if (response && typeof response === "object") {
|
|
1209
|
+
if (typeof response.status === "number") {
|
|
1210
|
+
httpData.status = response.status;
|
|
1211
|
+
hasData = true;
|
|
1212
|
+
}
|
|
1213
|
+
if (typeof response.statusText === "string") {
|
|
1214
|
+
httpData.statusText = response.statusText;
|
|
1215
|
+
hasData = true;
|
|
1216
|
+
}
|
|
1217
|
+
if (response.data !== void 0) {
|
|
1218
|
+
httpData.responseData = sanitizeResponseData(response.data);
|
|
1219
|
+
hasData = true;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
const config = error.config;
|
|
1223
|
+
if (config && typeof config === "object") {
|
|
1224
|
+
const url = config.url;
|
|
1225
|
+
const baseURL = config.baseURL;
|
|
1226
|
+
if (typeof url === "string") {
|
|
1227
|
+
httpData.url = baseURL && !url.startsWith("http") ? `${baseURL}${url}` : url;
|
|
1228
|
+
hasData = true;
|
|
1229
|
+
}
|
|
1230
|
+
if (typeof config.method === "string") {
|
|
1231
|
+
httpData.method = config.method.toUpperCase();
|
|
1232
|
+
hasData = true;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
return hasData ? httpData : void 0;
|
|
1236
|
+
}
|
|
1237
|
+
function serializeError(error) {
|
|
1238
|
+
if (!(error instanceof Error)) {
|
|
1239
|
+
if (error === null || error === void 0) {
|
|
1240
|
+
return { errorMessage: "Unknown error" };
|
|
1241
|
+
}
|
|
1242
|
+
if (typeof error === "string") {
|
|
1243
|
+
return { errorMessage: error };
|
|
1244
|
+
}
|
|
1245
|
+
const httpData2 = typeof error === "object" ? extractGenericHttpData(error) : void 0;
|
|
1246
|
+
return {
|
|
1247
|
+
errorMessage: String(error),
|
|
1248
|
+
http: httpData2
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
const serialized = {
|
|
1252
|
+
errorMessage: error.message,
|
|
1253
|
+
stack: error.stack
|
|
1254
|
+
};
|
|
1255
|
+
if (error.name && error.name !== "Error") {
|
|
1256
|
+
serialized.errorName = error.name;
|
|
1257
|
+
}
|
|
1258
|
+
if (isAxiosError(error)) {
|
|
1259
|
+
serialized.http = extractAxiosHttpData(error);
|
|
1260
|
+
return serialized;
|
|
1261
|
+
}
|
|
1262
|
+
const errWithCode = error;
|
|
1263
|
+
if (typeof errWithCode.code === "string") {
|
|
1264
|
+
serialized.code = errWithCode.code;
|
|
1265
|
+
}
|
|
1266
|
+
const httpData = extractGenericHttpData(error);
|
|
1267
|
+
if (httpData) {
|
|
1268
|
+
serialized.http = httpData;
|
|
1269
|
+
}
|
|
1270
|
+
return serialized;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1090
1273
|
// src/logger.ts
|
|
1091
1274
|
var Logger = class _Logger {
|
|
1092
1275
|
constructor(state, context) {
|
|
@@ -1097,7 +1280,12 @@ var Logger = class _Logger {
|
|
|
1097
1280
|
static create(config, store) {
|
|
1098
1281
|
const validatedConfig = validateConfig(config);
|
|
1099
1282
|
const state = createState(validatedConfig, store);
|
|
1100
|
-
|
|
1283
|
+
const logger = new _Logger(state, "APP");
|
|
1284
|
+
if (validatedConfig.autoShutdown) {
|
|
1285
|
+
const shutdownConfig = typeof validatedConfig.autoShutdown === "object" ? validatedConfig.autoShutdown : {};
|
|
1286
|
+
registerShutdown(logger, shutdownConfig);
|
|
1287
|
+
}
|
|
1288
|
+
return logger;
|
|
1101
1289
|
}
|
|
1102
1290
|
for(context) {
|
|
1103
1291
|
return new _Logger(this.state, context);
|
|
@@ -1139,6 +1327,15 @@ var Logger = class _Logger {
|
|
|
1139
1327
|
getLevelOverrides() {
|
|
1140
1328
|
return Array.from(this.state.levelOverrides.values());
|
|
1141
1329
|
}
|
|
1330
|
+
// Shutdown
|
|
1331
|
+
/**
|
|
1332
|
+
* Gracefully shutdown the logger, flushing all pending messages.
|
|
1333
|
+
* Should be called before process exit to ensure no logs are lost.
|
|
1334
|
+
*/
|
|
1335
|
+
async shutdown() {
|
|
1336
|
+
const closePromises = this.state.transports.map((transport) => transport.close());
|
|
1337
|
+
await Promise.all(closePromises);
|
|
1338
|
+
}
|
|
1142
1339
|
// Profiling
|
|
1143
1340
|
profile(id, meta) {
|
|
1144
1341
|
const existing = this.profileTimers.get(id);
|
|
@@ -1201,11 +1398,19 @@ var Logger = class _Logger {
|
|
|
1201
1398
|
logMeta.caller = formatCallerInfo(callerInfo);
|
|
1202
1399
|
}
|
|
1203
1400
|
}
|
|
1204
|
-
if (error
|
|
1205
|
-
|
|
1206
|
-
logMeta.
|
|
1207
|
-
|
|
1208
|
-
|
|
1401
|
+
if (error !== void 0) {
|
|
1402
|
+
const serialized = serializeError(error);
|
|
1403
|
+
logMeta.errorMessage = serialized.errorMessage;
|
|
1404
|
+
logMeta.stack = serialized.stack;
|
|
1405
|
+
if (serialized.errorName) {
|
|
1406
|
+
logMeta.errorName = serialized.errorName;
|
|
1407
|
+
}
|
|
1408
|
+
if (serialized.code) {
|
|
1409
|
+
logMeta.errorCode = serialized.code;
|
|
1410
|
+
}
|
|
1411
|
+
if (serialized.http) {
|
|
1412
|
+
logMeta.http = serialized.http;
|
|
1413
|
+
}
|
|
1209
1414
|
}
|
|
1210
1415
|
const pinoMethod = this.getPinoMethod(level);
|
|
1211
1416
|
pinoMethod.call(this.state.pino, logMeta, message);
|
|
@@ -1405,16 +1610,28 @@ function createMasker(options = {}) {
|
|
|
1405
1610
|
}
|
|
1406
1611
|
|
|
1407
1612
|
// src/formatters.ts
|
|
1408
|
-
|
|
1613
|
+
var MAX_FLATTEN_DEPTH = 10;
|
|
1614
|
+
var CIRCULAR_REF = "[Circular]";
|
|
1615
|
+
function flattenObject(obj, prefix = "", ancestors = /* @__PURE__ */ new WeakSet(), depth = 0) {
|
|
1409
1616
|
const result = {};
|
|
1617
|
+
if (depth > MAX_FLATTEN_DEPTH) {
|
|
1618
|
+
result[prefix || "value"] = "[Max depth exceeded]";
|
|
1619
|
+
return result;
|
|
1620
|
+
}
|
|
1621
|
+
ancestors.add(obj);
|
|
1410
1622
|
for (const [key, value] of Object.entries(obj)) {
|
|
1411
1623
|
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
1412
1624
|
if (value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Error)) {
|
|
1413
|
-
|
|
1625
|
+
if (ancestors.has(value)) {
|
|
1626
|
+
result[newKey] = CIRCULAR_REF;
|
|
1627
|
+
} else {
|
|
1628
|
+
Object.assign(result, flattenObject(value, newKey, ancestors, depth + 1));
|
|
1629
|
+
}
|
|
1414
1630
|
} else {
|
|
1415
1631
|
result[newKey] = value;
|
|
1416
1632
|
}
|
|
1417
1633
|
}
|
|
1634
|
+
ancestors.delete(obj);
|
|
1418
1635
|
return result;
|
|
1419
1636
|
}
|
|
1420
1637
|
function formatLogfmtValue(value) {
|
|
@@ -1443,6 +1660,7 @@ function formatLogfmt(data) {
|
|
|
1443
1660
|
return Object.entries(flattened).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${formatLogfmtValue(value)}`).join(" ");
|
|
1444
1661
|
}
|
|
1445
1662
|
|
|
1663
|
+
exports.AutoShutdownConfigSchema = AutoShutdownConfigSchema;
|
|
1446
1664
|
exports.BaseHttpTransport = BaseHttpTransport;
|
|
1447
1665
|
exports.CallerConfigSchema = CallerConfigSchema;
|
|
1448
1666
|
exports.CloudWatchConfigSchema = CloudWatchConfigSchema;
|
|
@@ -1484,7 +1702,9 @@ exports.maskSecrets = maskSecrets;
|
|
|
1484
1702
|
exports.matchesContext = matchesContext;
|
|
1485
1703
|
exports.measureAsync = measureAsync;
|
|
1486
1704
|
exports.measureSync = measureSync;
|
|
1705
|
+
exports.registerShutdown = registerShutdown;
|
|
1487
1706
|
exports.safeValidateConfig = safeValidateConfig;
|
|
1707
|
+
exports.serializeError = serializeError;
|
|
1488
1708
|
exports.validateConfig = validateConfig;
|
|
1489
1709
|
//# sourceMappingURL=index.js.map
|
|
1490
1710
|
//# sourceMappingURL=index.js.map
|