@rawnodes/logger 2.5.0 → 2.6.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/dist/index.mjs CHANGED
@@ -683,6 +683,7 @@ function createFormattedFilterStream(format, level, rules, store, destination) {
683
683
  }
684
684
  function createStreams(config, store) {
685
685
  const streams = [];
686
+ const transports = [];
686
687
  const consoleStream = createFormattedFilterStream(
687
688
  config.console.format,
688
689
  config.console.level,
@@ -730,6 +731,7 @@ function createStreams(config, store) {
730
731
  }
731
732
  for (const discordConfig of toArray(config.discord)) {
732
733
  const transport = new DiscordTransport(discordConfig);
734
+ transports.push(transport);
733
735
  const discordStream = createHttpTransportStream(transport, discordConfig.level, discordConfig.rules, store);
734
736
  streams.push({
735
737
  level: "trace",
@@ -738,6 +740,7 @@ function createStreams(config, store) {
738
740
  }
739
741
  for (const telegramConfig of toArray(config.telegram)) {
740
742
  const transport = new TelegramTransport(telegramConfig);
743
+ transports.push(transport);
741
744
  const telegramStream = createHttpTransportStream(transport, telegramConfig.level, telegramConfig.rules, store);
742
745
  streams.push({
743
746
  level: "trace",
@@ -746,13 +749,17 @@ function createStreams(config, store) {
746
749
  }
747
750
  for (const cloudwatchConfig of toArray(config.cloudwatch)) {
748
751
  const transport = new CloudWatchTransport(cloudwatchConfig, config.hostname);
752
+ transports.push(transport);
749
753
  const cwStream = createHttpTransportStream(transport, cloudwatchConfig.level, cloudwatchConfig.rules, store);
750
754
  streams.push({
751
755
  level: "trace",
752
756
  stream: cwStream
753
757
  });
754
758
  }
755
- return pino.multistream(streams);
759
+ return {
760
+ destination: pino.multistream(streams),
761
+ transports
762
+ };
756
763
  }
757
764
  function toArray(value) {
758
765
  if (!value) return [];
@@ -837,14 +844,14 @@ function createState(config, store) {
837
844
  levelOverrides.set(key, rule);
838
845
  }
839
846
  const { contextIndex, complexRules } = buildIndexes(levelOverrides);
840
- const streams = createStreams(config, loggerStore);
847
+ const { destination, transports } = createStreams(config, loggerStore);
841
848
  const options = {
842
849
  level: "trace",
843
850
  // Accept all, we filter in shouldLog()
844
851
  customLevels: CUSTOM_LEVELS,
845
852
  base: { hostname: config.hostname ?? hostname() }
846
853
  };
847
- const pinoLogger = pino(options, streams);
854
+ const pinoLogger = pino(options, destination);
848
855
  let callerConfig;
849
856
  if (config.caller === true) {
850
857
  callerConfig = {};
@@ -858,7 +865,8 @@ function createState(config, store) {
858
865
  levelOverrides,
859
866
  contextIndex,
860
867
  complexRules,
861
- callerConfig
868
+ callerConfig,
869
+ transports
862
870
  };
863
871
  }
864
872
  function rebuildIndexes(state) {
@@ -1004,6 +1012,10 @@ var CallerConfigSchema = z.object({
1004
1012
  depth: z.number().int().nonnegative().optional(),
1005
1013
  fullPath: z.boolean().optional()
1006
1014
  });
1015
+ var AutoShutdownConfigSchema = z.object({
1016
+ timeout: z.number().int().positive().optional(),
1017
+ signals: z.array(z.string()).optional()
1018
+ });
1007
1019
  var LoggerConfigSchema = z.object({
1008
1020
  level: LevelConfigSchema,
1009
1021
  console: ConsoleConfigSchema,
@@ -1012,7 +1024,8 @@ var LoggerConfigSchema = z.object({
1012
1024
  telegram: z.union([TelegramConfigSchema, z.array(TelegramConfigSchema)]).optional(),
1013
1025
  cloudwatch: z.union([CloudWatchConfigSchema, z.array(CloudWatchConfigSchema)]).optional(),
1014
1026
  caller: z.union([z.boolean(), CallerConfigSchema]).optional(),
1015
- hostname: z.string().optional()
1027
+ hostname: z.string().optional(),
1028
+ autoShutdown: z.union([z.boolean(), AutoShutdownConfigSchema]).optional()
1016
1029
  });
1017
1030
  function validateConfig(config) {
1018
1031
  return LoggerConfigSchema.parse(config);
@@ -1081,6 +1094,53 @@ function formatCallerInfo(info) {
1081
1094
  return location;
1082
1095
  }
1083
1096
 
1097
+ // src/utils/shutdown.ts
1098
+ var DEFAULT_OPTIONS2 = {
1099
+ timeout: 5e3,
1100
+ exitCode: 0,
1101
+ signals: ["SIGTERM", "SIGINT"]
1102
+ };
1103
+ var registered = false;
1104
+ function registerShutdown(logger, options = {}) {
1105
+ const opts = { ...DEFAULT_OPTIONS2, ...options };
1106
+ const shutdown = async (signal) => {
1107
+ if (signal) {
1108
+ console.error(`[Logger] Received ${signal}, shutting down gracefully...`);
1109
+ }
1110
+ try {
1111
+ if (opts.onShutdown) {
1112
+ await opts.onShutdown();
1113
+ }
1114
+ const timeoutPromise = new Promise((_, reject) => {
1115
+ setTimeout(() => {
1116
+ reject(new Error(`Shutdown timed out after ${opts.timeout}ms`));
1117
+ }, opts.timeout);
1118
+ });
1119
+ await Promise.race([
1120
+ logger.shutdown(),
1121
+ timeoutPromise
1122
+ ]);
1123
+ if (signal) {
1124
+ console.error("[Logger] Graceful shutdown completed");
1125
+ process.exit(opts.exitCode);
1126
+ }
1127
+ } catch (error) {
1128
+ console.error("[Logger] Shutdown error:", error instanceof Error ? error.message : error);
1129
+ if (signal) {
1130
+ process.exit(1);
1131
+ }
1132
+ }
1133
+ };
1134
+ if (!registered) {
1135
+ for (const signal of opts.signals) {
1136
+ process.on(signal, () => void shutdown(signal));
1137
+ }
1138
+ process.on("beforeExit", () => void shutdown());
1139
+ registered = true;
1140
+ }
1141
+ return shutdown;
1142
+ }
1143
+
1084
1144
  // src/logger.ts
1085
1145
  var Logger = class _Logger {
1086
1146
  constructor(state, context) {
@@ -1091,7 +1151,12 @@ var Logger = class _Logger {
1091
1151
  static create(config, store) {
1092
1152
  const validatedConfig = validateConfig(config);
1093
1153
  const state = createState(validatedConfig, store);
1094
- return new _Logger(state, "APP");
1154
+ const logger = new _Logger(state, "APP");
1155
+ if (validatedConfig.autoShutdown) {
1156
+ const shutdownConfig = typeof validatedConfig.autoShutdown === "object" ? validatedConfig.autoShutdown : {};
1157
+ registerShutdown(logger, shutdownConfig);
1158
+ }
1159
+ return logger;
1095
1160
  }
1096
1161
  for(context) {
1097
1162
  return new _Logger(this.state, context);
@@ -1133,6 +1198,15 @@ var Logger = class _Logger {
1133
1198
  getLevelOverrides() {
1134
1199
  return Array.from(this.state.levelOverrides.values());
1135
1200
  }
1201
+ // Shutdown
1202
+ /**
1203
+ * Gracefully shutdown the logger, flushing all pending messages.
1204
+ * Should be called before process exit to ensure no logs are lost.
1205
+ */
1206
+ async shutdown() {
1207
+ const closePromises = this.state.transports.map((transport) => transport.close());
1208
+ await Promise.all(closePromises);
1209
+ }
1136
1210
  // Profiling
1137
1211
  profile(id, meta) {
1138
1212
  const existing = this.profileTimers.get(id);
@@ -1399,16 +1473,28 @@ function createMasker(options = {}) {
1399
1473
  }
1400
1474
 
1401
1475
  // src/formatters.ts
1402
- function flattenObject(obj, prefix = "") {
1476
+ var MAX_FLATTEN_DEPTH = 10;
1477
+ var CIRCULAR_REF = "[Circular]";
1478
+ function flattenObject(obj, prefix = "", ancestors = /* @__PURE__ */ new WeakSet(), depth = 0) {
1403
1479
  const result = {};
1480
+ if (depth > MAX_FLATTEN_DEPTH) {
1481
+ result[prefix || "value"] = "[Max depth exceeded]";
1482
+ return result;
1483
+ }
1484
+ ancestors.add(obj);
1404
1485
  for (const [key, value] of Object.entries(obj)) {
1405
1486
  const newKey = prefix ? `${prefix}.${key}` : key;
1406
1487
  if (value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Error)) {
1407
- Object.assign(result, flattenObject(value, newKey));
1488
+ if (ancestors.has(value)) {
1489
+ result[newKey] = CIRCULAR_REF;
1490
+ } else {
1491
+ Object.assign(result, flattenObject(value, newKey, ancestors, depth + 1));
1492
+ }
1408
1493
  } else {
1409
1494
  result[newKey] = value;
1410
1495
  }
1411
1496
  }
1497
+ ancestors.delete(obj);
1412
1498
  return result;
1413
1499
  }
1414
1500
  function formatLogfmtValue(value) {
@@ -1437,6 +1523,6 @@ function formatLogfmt(data) {
1437
1523
  return Object.entries(flattened).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${formatLogfmtValue(value)}`).join(" ");
1438
1524
  }
1439
1525
 
1440
- export { BaseHttpTransport, CallerConfigSchema, CloudWatchConfigSchema, CloudWatchTransport, ConsoleConfigSchema, DiscordConfigSchema, DiscordTransport, FileConfigSchema, HttpTransportBaseConfigSchema, LOG_LEVELS, LevelConfigObjectSchema, LevelConfigSchema, LevelRuleSchema, LogFormatSchema, LogLevelSchema, LogStreamNameSchema, LogStreamPatternConfigSchema, LogStreamPatternSchema, LogStreamTemplateConfigSchema, Logger, LoggerConfigSchema, LoggerStore, MessageBuffer, TelegramConfigSchema, TelegramTransport, assertLogLevel, createMasker, createSingletonLogger, extractRequestId, flattenObject, formatCallerInfo, formatLogfmt, formatLogfmtValue, generateRequestId, getCallerInfo, getOrGenerateRequestId, isValidLogLevel, maskSecrets, matchesContext, measureAsync, measureSync, safeValidateConfig, validateConfig };
1526
+ export { AutoShutdownConfigSchema, BaseHttpTransport, CallerConfigSchema, CloudWatchConfigSchema, CloudWatchTransport, ConsoleConfigSchema, DiscordConfigSchema, DiscordTransport, FileConfigSchema, HttpTransportBaseConfigSchema, LOG_LEVELS, LevelConfigObjectSchema, LevelConfigSchema, LevelRuleSchema, LogFormatSchema, LogLevelSchema, LogStreamNameSchema, LogStreamPatternConfigSchema, LogStreamPatternSchema, LogStreamTemplateConfigSchema, Logger, LoggerConfigSchema, LoggerStore, MessageBuffer, TelegramConfigSchema, TelegramTransport, assertLogLevel, createMasker, createSingletonLogger, extractRequestId, flattenObject, formatCallerInfo, formatLogfmt, formatLogfmtValue, generateRequestId, getCallerInfo, getOrGenerateRequestId, isValidLogLevel, maskSecrets, matchesContext, measureAsync, measureSync, registerShutdown, safeValidateConfig, validateConfig };
1441
1527
  //# sourceMappingURL=index.mjs.map
1442
1528
  //# sourceMappingURL=index.mjs.map