logixia 1.10.2 → 1.10.3

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.
Files changed (40) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/index.d.mts +5 -2
  3. package/dist/index.d.mts.map +1 -1
  4. package/dist/index.d.ts +5 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +75 -33
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +75 -33
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/logitron-logger.module-B8NklSC4.d.mts.map +1 -1
  11. package/dist/{logitron-logger.module-Bt_Jei1V.mjs → logitron-logger.module-BBC9nO5q.mjs} +118 -37
  12. package/dist/logitron-logger.module-BBC9nO5q.mjs.map +1 -0
  13. package/dist/logitron-logger.module-BLT1y5Iq.d.ts.map +1 -1
  14. package/dist/{logitron-logger.module-bJ1hGhaL.js → logitron-logger.module-Dlf5GwJ9.js} +118 -37
  15. package/dist/logitron-logger.module-Dlf5GwJ9.js.map +1 -0
  16. package/dist/middleware.d.mts.map +1 -1
  17. package/dist/middleware.d.ts.map +1 -1
  18. package/dist/middleware.js +4 -3
  19. package/dist/middleware.js.map +1 -1
  20. package/dist/middleware.mjs +4 -3
  21. package/dist/middleware.mjs.map +1 -1
  22. package/dist/nest.d.mts.map +1 -1
  23. package/dist/nest.d.ts.map +1 -1
  24. package/dist/nest.js +2 -2
  25. package/dist/nest.mjs +2 -2
  26. package/dist/{transport.manager-zgEZCJhR.js → transport.manager-B9LF9uDd.js} +130 -56
  27. package/dist/transport.manager-B9LF9uDd.js.map +1 -0
  28. package/dist/{transport.manager-CaL4XuLD.mjs → transport.manager-Cij_sA-b.mjs} +128 -56
  29. package/dist/transport.manager-Cij_sA-b.mjs.map +1 -0
  30. package/dist/transports.d.mts +41 -2
  31. package/dist/transports.d.mts.map +1 -1
  32. package/dist/transports.d.ts +41 -2
  33. package/dist/transports.d.ts.map +1 -1
  34. package/dist/transports.js +1 -1
  35. package/dist/transports.mjs +1 -1
  36. package/package.json +1 -1
  37. package/dist/logitron-logger.module-Bt_Jei1V.mjs.map +0 -1
  38. package/dist/logitron-logger.module-bJ1hGhaL.js.map +0 -1
  39. package/dist/transport.manager-CaL4XuLD.mjs.map +0 -1
  40. package/dist/transport.manager-zgEZCJhR.js.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { p as internalWarn, u as safeToString } from "./transport.manager-CaL4XuLD.mjs";
2
- import { A as redactObject, B as LogLevel, C as setTraceId, D as registerForShutdown, E as flushOnExit, F as isError, G as createExpressContextMiddleware, H as globalPluginRegistry, I as normalizeError, K as createFastifyContextHook, L as serializeError, M as getActiveOtelContext, N as getOtelMetaFields, O as resetShutdownHandlers, P as initOtelBridge, R as DEFAULT_LOG_COLORS, S as runWithTraceId, T as deregisterFromShutdown, U as usePlugin, V as PluginRegistry, W as LogixiaContext, _ as _setActiveContextKey, b as getCurrentTraceId, c as KafkaTraceInterceptor, d as __decorateMetadata, f as LogixiaLogger, g as TraceContext, h as TRACE_CONTEXT_KEY, i as WebSocketTraceInterceptor, j as disableOtelBridge, k as applyRedaction, l as LogixiaLoggerService, m as DEFAULT_TRACE_HEADERS, n as LOGIXIA_LOGGER_PREFIX, o as resolveResponseHeader, p as createLogger$1, r as LogixiaLoggerModule, s as __decorateParam, t as LOGIXIA_LOGGER_CONFIG, u as __decorate, v as createTraceMiddleware, w as traceStorage, x as getTraceContextKey, y as extractTraceId, z as DEFAULT_LOG_LEVELS } from "./logitron-logger.module-Bt_Jei1V.mjs";
1
+ import { p as internalWarn, u as safeToString } from "./transport.manager-Cij_sA-b.mjs";
2
+ import { A as redactObject, B as LogLevel, C as setTraceId, D as registerForShutdown, E as flushOnExit, F as isError, G as createExpressContextMiddleware, H as globalPluginRegistry, I as normalizeError, K as createFastifyContextHook, L as serializeError, M as getActiveOtelContext, N as getOtelMetaFields, O as resetShutdownHandlers, P as initOtelBridge, R as DEFAULT_LOG_COLORS, S as runWithTraceId, T as deregisterFromShutdown, U as usePlugin, V as PluginRegistry, W as LogixiaContext, _ as _setActiveContextKey, b as getCurrentTraceId, c as KafkaTraceInterceptor, d as __decorateMetadata, f as LogixiaLogger, g as TraceContext, h as TRACE_CONTEXT_KEY, i as WebSocketTraceInterceptor, j as disableOtelBridge, k as applyRedaction, l as LogixiaLoggerService, m as DEFAULT_TRACE_HEADERS, n as LOGIXIA_LOGGER_PREFIX, o as resolveResponseHeader, p as createLogger$1, r as LogixiaLoggerModule, s as __decorateParam, t as LOGIXIA_LOGGER_CONFIG, u as __decorate, v as createTraceMiddleware, w as traceStorage, x as getTraceContextKey, y as extractTraceId, z as DEFAULT_LOG_LEVELS } from "./logitron-logger.module-BBC9nO5q.mjs";
3
3
  import "./search-DOvSI-mb.mjs";
4
4
  import { Catch, Inject, Optional } from "@nestjs/common";
5
5
 
@@ -227,8 +227,11 @@ const InjectLogger = () => Inject(`${LOGIXIA_LOGGER_PREFIX}SERVICE`);
227
227
  /**
228
228
  * Method decorator that auto-logs entry, exit, duration, and errors.
229
229
  *
230
- * Works on both async and sync methods. Attaches to the logger found on the
231
- * class instance via a `logger` property (the conventional NestJS name).
230
+ * Preserves the original method's sync/async contract: a synchronous method
231
+ * stays synchronous (returns its value directly, with logs emitted
232
+ * fire-and-forget), and an async method is awaited so exit/error logs reflect
233
+ * the resolved result. Attaches to the logger found on the class instance via a
234
+ * `logger` property (the conventional NestJS name).
232
235
  *
233
236
  * @example
234
237
  * ```ts
@@ -246,7 +249,23 @@ function LogMethod(options = {}) {
246
249
  const className = ((_constructor = target.constructor) === null || _constructor === void 0 ? void 0 : _constructor.name) ?? "Unknown";
247
250
  const label = options.label ?? `${className}.${methodName}`;
248
251
  let _warnedNoLogger = false;
249
- descriptor.value = async function(...args) {
252
+ const reportLogFailure = (phase, err) => {
253
+ process.stderr.write(`[logixia] @LogMethod(${label}) ${phase} log failed: ${String(err)}\n`);
254
+ };
255
+ const emit = (logger$1, phase, message, data) => {
256
+ const logFnRaw = logger$1[level];
257
+ const p = (typeof logFnRaw === "function" ? logFnRaw : logger$1.debug).bind(logger$1)(message, data);
258
+ if (p && typeof p.catch === "function") p.catch((e) => reportLogFailure(phase, e));
259
+ };
260
+ const emitError = (logger$1, error, start) => {
261
+ const err = error instanceof Error ? error : new Error(String(error));
262
+ const errLog = logger$1.error(err, {
263
+ method: label,
264
+ durationMs: Date.now() - start
265
+ });
266
+ if (errLog && typeof errLog.catch === "function") errLog.catch((e) => reportLogFailure("error", e));
267
+ };
268
+ descriptor.value = function(...args) {
250
269
  const logger$1 = this.logger ?? LogixiaLoggerModule._globalLogger ?? void 0;
251
270
  if (!logger$1 && !_warnedNoLogger) {
252
271
  _warnedNoLogger = true;
@@ -255,36 +274,31 @@ function LogMethod(options = {}) {
255
274
  const start = Date.now();
256
275
  const entry = { method: label };
257
276
  if (logArgs && args.length > 0) entry["args"] = args;
258
- const reportLogFailure = (phase, err) => {
259
- process.stderr.write(`[logixia] @LogMethod(${label}) ${phase} log failed: ${String(err)}\n`);
260
- };
261
- if (logger$1) {
262
- const logFnRaw = logger$1[level];
263
- await (typeof logFnRaw === "function" ? logFnRaw : logger$1.debug).bind(logger$1)(`→ ${label}`, entry).catch((e) => reportLogFailure("entry", e));
264
- }
265
- try {
266
- const result = await originalMethod.apply(this, args);
277
+ if (logger$1) emit(logger$1, "entry", `→ ${label}`, entry);
278
+ const buildExit = (result$1) => {
267
279
  const exit = {
268
280
  method: label,
269
281
  durationMs: Date.now() - start
270
282
  };
271
- if (logResult) exit["result"] = result;
272
- if (logger$1) {
273
- const logFnRaw = logger$1[level];
274
- await (typeof logFnRaw === "function" ? logFnRaw : logger$1.debug).bind(logger$1)(`← ${label}`, exit).catch((e) => reportLogFailure("exit", e));
275
- }
276
- return result;
283
+ if (logResult) exit["result"] = result$1;
284
+ return exit;
285
+ };
286
+ let result;
287
+ try {
288
+ result = originalMethod.apply(this, args);
277
289
  } catch (error) {
278
- if (logger$1 && logErrors) {
279
- const err = error instanceof Error ? error : new Error(String(error));
280
- const errLog = logger$1.error(err, {
281
- method: label,
282
- durationMs: Date.now() - start
283
- });
284
- if (errLog !== void 0 && errLog !== null && typeof errLog.catch === "function") errLog.catch((e) => reportLogFailure("error", e));
285
- }
290
+ if (logger$1 && logErrors) emitError(logger$1, error, start);
286
291
  throw error;
287
292
  }
293
+ if (result && typeof result.then === "function") return result.then((resolved) => {
294
+ if (logger$1) emit(logger$1, "exit", `← ${label}`, buildExit(resolved));
295
+ return resolved;
296
+ }, (error) => {
297
+ if (logger$1 && logErrors) emitError(logger$1, error, start);
298
+ throw error;
299
+ });
300
+ if (logger$1) emit(logger$1, "exit", `← ${label}`, buildExit(result));
301
+ return result;
288
302
  };
289
303
  return descriptor;
290
304
  };
@@ -344,6 +358,21 @@ LogixiaExceptionFilter = __decorate([
344
358
 
345
359
  //#endregion
346
360
  //#region src/formatters/json.formatter.ts
361
+ /**
362
+ * Build a JSON.stringify replacer that replaces circular references with the
363
+ * string '[Circular]' instead of throwing. A fresh replacer must be created per
364
+ * stringify call because it holds per-serialization state (the seen set).
365
+ */
366
+ function createCircularReplacer() {
367
+ const seen = /* @__PURE__ */ new WeakSet();
368
+ return function(_key, value) {
369
+ if (typeof value === "object" && value !== null) {
370
+ if (seen.has(value)) return "[Circular]";
371
+ seen.add(value);
372
+ }
373
+ return value;
374
+ };
375
+ }
347
376
  var JsonFormatter = class {
348
377
  constructor(options = {}) {
349
378
  this.includeTimestamp = options.includeTimestamp ?? true;
@@ -371,7 +400,8 @@ var JsonFormatter = class {
371
400
  hostname: process.env.HOSTNAME || "unknown",
372
401
  version: process.version
373
402
  };
374
- return this.prettyPrint ? JSON.stringify(formatted, null, 2) : JSON.stringify(formatted);
403
+ const replacer = createCircularReplacer();
404
+ return this.prettyPrint ? JSON.stringify(formatted, replacer, 2) : JSON.stringify(formatted, replacer);
375
405
  }
376
406
  serializePayload(payload) {
377
407
  const serialized = {};
@@ -474,11 +504,11 @@ var TextFormatter = class TextFormatter {
474
504
  if (typeof value === "string") return `${key}="${value}"`;
475
505
  if (typeof value === "number" || typeof value === "boolean") return `${key}=${value}`;
476
506
  if (value instanceof Date) return `${key}=${value.toISOString()}`;
477
- if (typeof value === "object") return `${key}=${JSON.stringify(value)}`;
507
+ if (typeof value === "object") return `${key}=${stripControls(safeToString(value))}`;
478
508
  return `${key}=${String(value)}`;
479
509
  }).join(" ");
480
510
  } catch {
481
- return JSON.stringify(payload);
511
+ return stripControls(safeToString(payload));
482
512
  }
483
513
  }
484
514
  /**
@@ -598,7 +628,7 @@ function buildLabelKey(config, entry) {
598
628
  const payload = entry.payload ?? {};
599
629
  for (const name of labelNames) {
600
630
  const raw = name === "level" ? entry.level : payload[name];
601
- pairs[name] = raw !== void 0 && raw !== null ? String(raw) : "";
631
+ pairs[sanitizePromName(name)] = raw !== void 0 && raw !== null ? String(raw) : "";
602
632
  }
603
633
  return JSON.stringify(pairs);
604
634
  }
@@ -611,6 +641,18 @@ function escapeLabel(value) {
611
641
  return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
612
642
  }
613
643
  /**
644
+ * Coerce an arbitrary string into a valid Prometheus metric or label name
645
+ * (`[a-zA-Z_][a-zA-Z0-9_]*`). Invalid characters become underscores and a
646
+ * leading digit is prefixed with `_`. Without this, a user-supplied name like
647
+ * `my-metric` or a label like `status code` would emit output Prometheus cannot
648
+ * parse, breaking the ENTIRE scrape endpoint, not just that metric.
649
+ */
650
+ function sanitizePromName(name) {
651
+ let safe = name.replace(/\W/g, "_");
652
+ if (safe.length > 0 && /\d/.test(safe[0])) safe = `_${safe}`;
653
+ return safe.length > 0 ? safe : "_";
654
+ }
655
+ /**
614
656
  * A logixia plugin that extracts Prometheus-compatible metrics from log entries.
615
657
  *
616
658
  * Implements `LogixiaPlugin` — pass directly to `logger.use()`:
@@ -684,7 +726,7 @@ var MetricsPlugin = class {
684
726
  render() {
685
727
  const lines = [];
686
728
  for (const [rawName, config] of Object.entries(this.map)) {
687
- const metricName = `logixia_${rawName}`;
729
+ const metricName = `logixia_${sanitizePromName(rawName)}`;
688
730
  const state = this.metricState.get(rawName);
689
731
  if (!state) continue;
690
732
  const helpText = config.help ?? rawName.replace(/_/g, " ");