analogger 2.3.5 → 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/README.md CHANGED
@@ -245,6 +245,43 @@ anaLogger.log({lid: 1236, symbol: "scissors"}, `I'am some log with some scissors
245
245
 
246
246
  <br/>
247
247
 
248
+ #### Example 6: The "only" filter
249
+
250
+ ###### You can filter logs globally so that only specific identifiers are displayed. This supports exact strings, partial matches, or regular expressions.
251
+
252
+ ```javascript
253
+ // Only show logs where the LID or context contains "API"
254
+ anaLogger.setOptions({ only: "API" });
255
+
256
+ anaLogger.log({ lid: "API_123" }, "This matches and will be seen");
257
+ anaLogger.log({ lid: "WEB_456" }, "This is blocked and hidden");
258
+ ```
259
+
260
+
261
+ ---
262
+
263
+ #### Example 7: The "order" option
264
+
265
+ ###### Enforce a call sequence by assigning an `order` number to each log entry. If a log with a lower order value appears after one with a higher value, AnaLogger emits a console warning. Calls without an `order` are transparent and do not affect the sequence.
266
+
267
+ ```javascript
268
+ anaLogger.log({lid: "API", order: 1}, "This matches");
269
+ anaLogger.log({lid: "API_123", order: 2}, "This shows API_123");
270
+ anaLogger.log({lid: "WEB_456", order: 35}, "This is blocked");
271
+ ```
272
+
273
+ If the calls arrive out of sequence — for example, `API_123` (order 2) appearing after `WEB_456` (order 35) — the following warning is printed to the console:
274
+
275
+ ```
276
+ ! Order mismatch: [API_123| order: 2] appeared after [WEB_456| order: 35]
277
+ ```
278
+
279
+ > **Notes:**
280
+ > - The check is per-instance, so different AnaLogger instances track their own sequences independently.
281
+ > - Calls filtered out by `only`, targets, or log levels are not counted toward the sequence.
282
+ > - Equal order values (non-decreasing) are always allowed; only strictly lower values trigger the warning.
283
+
284
+
248
285
  ---
249
286
 
250
287
  ### listSymbols()
@@ -312,6 +349,8 @@ Display the browser native message box if run from it; otherwise, it displays th
312
349
  | compressionLevel | 1 | number | _Gzip compression level (0-9)_ |
313
350
  | addArchiveTimestamp | true | boolean | _Appends a consistent timestamp to rotated files_ |
314
351
  | forceLidOn | false | boolean | _Automatically generates a short hash LID if one isn't provided_ |
352
+ | only | undefined | string/Regex/Array | Filter logs to show only those matching specific IDs or patterns |
353
+ | order | undefined | number | _Enforce call order — emits a console warning if a log with a lower order value appears after one with a higher value_ |
315
354
 
316
355
  <br/>
317
356
 
@@ -1333,6 +1372,7 @@ anaLogger.log("lid: USR_LOGIN, color: purple", "User logged in");
1333
1372
  * Add an option to show the date and time in logs
1334
1373
  * Make the alert method display the lid when detected
1335
1374
  * Keep format when displaying multiple lines for one entry
1375
+ * Add `order` option to detect and warn on out-of-sequence log calls
1336
1376
 
1337
1377
 
1338
1378
  ##### 1.23.2:
package/ana-logger.d.cts CHANGED
@@ -75,6 +75,12 @@ declare class ____AnaLogger {
75
75
  NODE: string;
76
76
  OTHER: string;
77
77
  };
78
+ _localOnlyFilter: any;
79
+ _localOnlyLabel: string;
80
+ _lastOrderEntry: {
81
+ lid: any;
82
+ order: any;
83
+ };
78
84
  getName(): string;
79
85
  getId(): string;
80
86
  /**
@@ -123,7 +129,7 @@ declare class ____AnaLogger {
123
129
  resetLogger(): void;
124
130
  remoteWaitCount: any;
125
131
  resetOptions(): void;
126
- setOptions({ timeLenMax, contextLenMax, idLenMax, lidLenMax, symbolLenMax, enableTrace, messageLenMax, hideLog, hideError, hideHookMessage, hidePassingTests, logToDom, logToFile, logMaxSize, logMaxArchives, logIndexArchive, addArchiveTimestamp, addArchiveIndex, compressArchives, compressionLevel, logToRemote, logToRemoteUrl, logToRemoteBinaryUrl, loopback, requiredLogLevel, oneConsolePerContext, silent, enableDate, enableMillisec, logToLocalStorage, logToLocalStorageMax, logToLocalStorageSize, logToRemoteMaxEntries, logToRemoteDebounce, logToRemoteMaxSize, logToRemoteMinSize, logUidToRemote, protocol, host, port, pathname, binarypathname, loadHtmlToImage }?: any): void;
132
+ setOptions({ timeLenMax, contextLenMax, idLenMax, lidLenMax, only, symbolLenMax, enableTrace, messageLenMax, hideLog, hideError, hideHookMessage, hidePassingTests, logToDom, logToFile, logMaxSize, logMaxArchives, logIndexArchive, addArchiveTimestamp, addArchiveIndex, compressArchives, compressionLevel, logToRemote, logToRemoteUrl, logToRemoteBinaryUrl, loopback, requiredLogLevel, oneConsolePerContext, silent, enableDate, enableMillisec, logToLocalStorage, logToLocalStorageMax, logToLocalStorageSize, logToRemoteMaxEntries, logToRemoteDebounce, logToRemoteMaxSize, logToRemoteMinSize, logUidToRemote, protocol, host, port, pathname, binarypathname, loadHtmlToImage }?: any): void;
127
133
  EOL: string;
128
134
  updateOptions(options: any): void;
129
135
  getOptions(): {
@@ -721,6 +721,15 @@ class ____AnaLogger
721
721
  this.#initialiseDefault();
722
722
 
723
723
  this.resetLogHistory();
724
+
725
+ // Tracks the active local "only" filter across calls.
726
+ // _localOnlyFilter holds the raw value (for matching),
727
+ // _localOnlyLabel holds the stringified form (for change-detection and separator text).
728
+ this._localOnlyFilter = undefined;
729
+ this._localOnlyLabel = undefined;
730
+
731
+ // Tracks the last seen "order" entry { lid, order } for order-mismatch detection.
732
+ this._lastOrderEntry = null;
724
733
  }
725
734
 
726
735
  getName()
@@ -932,6 +941,7 @@ class ____AnaLogger
932
941
  this.options.contextLenMax = 10;
933
942
  this.options.idLenMax = 5;
934
943
  this.options.lidLenMax = 6;
944
+ this.options.only = undefined;
935
945
  this.options.messageLenMax = undefined;
936
946
  this.options.symbolLenMax = 60;
937
947
  this.options.hideHookMessage = undefined;
@@ -981,6 +991,7 @@ class ____AnaLogger
981
991
  contextLenMax = 10,
982
992
  idLenMax = 5,
983
993
  lidLenMax = 6,
994
+ only = undefined,
984
995
  symbolLenMax = 2,
985
996
  enableTrace = true,
986
997
  messageLenMax = undefined,
@@ -1026,6 +1037,7 @@ class ____AnaLogger
1026
1037
  this.options.contextLenMax = contextLenMax;
1027
1038
  this.options.idLenMax = idLenMax;
1028
1039
  this.options.lidLenMax = lidLenMax;
1040
+ this.options.only = only;
1029
1041
  this.options.messageLenMax = messageLenMax;
1030
1042
  this.options.symbolLenMax = symbolLenMax;
1031
1043
 
@@ -2276,6 +2288,7 @@ class ____AnaLogger
2276
2288
  const {context, args} = entry;
2277
2289
  if (context) {
2278
2290
  context.symbol = "floppy_disk";
2291
+ delete context.order;
2279
2292
  }
2280
2293
  this.processOutput(context, ...args);
2281
2294
  });
@@ -2582,6 +2595,146 @@ class ____AnaLogger
2582
2595
  return result;
2583
2596
  }
2584
2597
 
2598
+ /**
2599
+ * Check that log calls with an "order" property arrive in non-decreasing order.
2600
+ * When a call with a lower order value appears after one with a higher order value,
2601
+ * a warning is printed:
2602
+ * ! Order mismatch: [API_123| order: 2] appeared after [WEB_456| order: 35]
2603
+ *
2604
+ * @param {object} context
2605
+ */
2606
+ #checkOrder(context)
2607
+ {
2608
+ if (context.order === undefined || context.order === null)
2609
+ {
2610
+ return;
2611
+ }
2612
+
2613
+ const currentOrder = context.order;
2614
+ const currentLid = context.lid || "";
2615
+
2616
+ if (this._lastOrderEntry !== null)
2617
+ {
2618
+ const {lid: prevLid, order: prevOrder} = this._lastOrderEntry;
2619
+
2620
+ if (currentOrder < prevOrder)
2621
+ {
2622
+ const msg = `! Order mismatch: [${currentLid}| order: ${currentOrder}] appeared after [${prevLid}| order: ${prevOrder}]`;
2623
+ ____AnaLogger.Console.warn(msg);
2624
+ }
2625
+ }
2626
+
2627
+ this._lastOrderEntry = {lid: currentLid, order: currentOrder};
2628
+ }
2629
+
2630
+ /**
2631
+ * Handle the local "only" option on a log context.
2632
+ *
2633
+ * Rules:
2634
+ * - If context.only is not set, do nothing.
2635
+ * - If context.only does NOT match context.lid (using the same partial-string /
2636
+ * regex logic as the global filter), the call is suppressed (returns false).
2637
+ * - On the very first matching call, the output channel is cleared:
2638
+ * • Browser → console.clear()
2639
+ * • Node → writes the terminal-reset sequence (\x1bc) to stdout
2640
+ * - On a subsequent matching call whose only value differs from the last seen
2641
+ * value, a separator line is printed instead of clearing.
2642
+ *
2643
+ * Returns false when the log entry should be suppressed, true otherwise.
2644
+ *
2645
+ * @param {object} context
2646
+ * @returns {boolean}
2647
+ */
2648
+ #handleLocalOnly(context)
2649
+ {
2650
+ const localOnly = context.only;
2651
+
2652
+ // Helper: test a lid string against a single filter entry.
2653
+ const lidMatchesFilter = (filter, lid) =>
2654
+ {
2655
+ if (filter instanceof RegExp)
2656
+ {
2657
+ return filter.test(lid);
2658
+ }
2659
+ if (typeof filter === "string" || filter instanceof String)
2660
+ {
2661
+ return lid.includes(filter);
2662
+ }
2663
+ return filter === lid;
2664
+ };
2665
+
2666
+ // Helper: test a lid against a filter that may be a single value or an array.
2667
+ const lidMatchesAny = (filter, lid) => Array.isArray(filter)
2668
+ ? filter.some((f) => lidMatchesFilter(f, lid))
2669
+ : lidMatchesFilter(filter, lid);
2670
+
2671
+ // Stable string label for a filter value (used for change-detection and separator text).
2672
+ const toLabel = (filter) => Array.isArray(filter)
2673
+ ? filter.map((f) => (f instanceof RegExp ? f.toString() : String(f))).join(", ")
2674
+ : (filter instanceof RegExp ? filter.toString() : String(filter));
2675
+
2676
+ const lid = context.lid || "";
2677
+
2678
+ if (localOnly === undefined || localOnly === null)
2679
+ {
2680
+ // No local only on this call. If a filter is already active, enforce it.
2681
+ if (this._localOnlyFilter !== undefined)
2682
+ {
2683
+ return lidMatchesAny(this._localOnlyFilter, lid);
2684
+ }
2685
+
2686
+ // No active filter at all – let the call through.
2687
+ return true;
2688
+ }
2689
+
2690
+ // --- This call explicitly sets context.only ---
2691
+
2692
+ if (!lidMatchesAny(localOnly, lid))
2693
+ {
2694
+ // The lid doesn't match – suppress without clearing or printing a separator,
2695
+ // since the filter hasn't been "activated" by an accepted call yet.
2696
+ return false;
2697
+ }
2698
+
2699
+ const onlyLabel = toLabel(localOnly);
2700
+
2701
+ if (this._localOnlyFilter === undefined)
2702
+ {
2703
+ // First ever match – clear the output channel.
2704
+ if (this.isBrowser())
2705
+ {
2706
+ /* istanbul ignore next */
2707
+ ____AnaLogger.Console.clear
2708
+ ? ____AnaLogger.Console.clear()
2709
+ : (typeof console !== "undefined" && console.clear && console.clear());
2710
+ }
2711
+ else
2712
+ {
2713
+ // ANSI terminal reset: clears the screen and moves cursor to top.
2714
+ process.stdout.write("\x1bc");
2715
+ }
2716
+ }
2717
+ else if (this._localOnlyLabel !== onlyLabel)
2718
+ {
2719
+ // Filter has changed – print a separator, no clear.
2720
+ const separator = `─── only switched to ${onlyLabel} ───`;
2721
+ if (this.isBrowser())
2722
+ {
2723
+ /* istanbul ignore next */
2724
+ ____AnaLogger.Console.log(`%c${separator}`, "color: #888; font-style: italic");
2725
+ }
2726
+ else
2727
+ {
2728
+ // Use the raw console so the separator bypasses all AnaLogger formatting.
2729
+ ____AnaLogger.Console.log(separator);
2730
+ }
2731
+ }
2732
+
2733
+ this._localOnlyFilter = localOnly; // raw value – used for matching
2734
+ this._localOnlyLabel = onlyLabel; // string – used for change detection
2735
+ return true;
2736
+ }
2737
+
2585
2738
  /**
2586
2739
  * Display log following template
2587
2740
  * @param context
@@ -2612,7 +2765,7 @@ class ____AnaLogger
2612
2765
  lid: context.lid,
2613
2766
  callCount: 1,
2614
2767
  callTimes: [Date.now()]
2615
- }
2768
+ };
2616
2769
  }
2617
2770
  }
2618
2771
 
@@ -2648,6 +2801,40 @@ class ____AnaLogger
2648
2801
  return;
2649
2802
  }
2650
2803
 
2804
+ // Check if global "only" filter is active
2805
+ if (this.options.only !== undefined && this.options.only !== null) {
2806
+ const onlyFilters = Array.isArray(this.options.only) ? this.options.only : [this.options.only];
2807
+ // Check if current log matches one of the filters
2808
+ const matchesFilter = onlyFilters.some((filter) => {
2809
+ const targetLid = context.lid || "";
2810
+ const targetOnly = context.only || "";
2811
+
2812
+ if (filter instanceof RegExp) {
2813
+ return filter.test(targetLid) || filter.test(targetOnly);
2814
+ }
2815
+
2816
+ // String partial match (e.g., "API" matches "API_123")
2817
+ if (typeof filter === "string") {
2818
+ return targetLid.includes(filter) || targetOnly.includes(filter);
2819
+ }
2820
+
2821
+ return filter === targetLid || filter === targetOnly;
2822
+ });
2823
+
2824
+ if (!matchesFilter) {
2825
+ return;
2826
+ }
2827
+ }
2828
+
2829
+ // Handle the per-call local "only" option.
2830
+ if (!this.#handleLocalOnly(context))
2831
+ {
2832
+ return;
2833
+ }
2834
+
2835
+ // Check that "order" values are non-decreasing across calls.
2836
+ this.#checkOrder(context);
2837
+
2651
2838
  const newMessages = this.checkOnLogging(context, argsWithoutContext[0], arguments,"onMessage");
2652
2839
  if (newMessages !== undefined) {
2653
2840
  arguments[1] = newMessages;
@@ -2770,6 +2957,7 @@ class ____AnaLogger
2770
2957
  options.hasOwnProperty("color") ||
2771
2958
  options.hasOwnProperty("contextName") ||
2772
2959
  options.hasOwnProperty("raw") ||
2960
+ options.hasOwnProperty("only") ||
2773
2961
  options.hasOwnProperty("lid");
2774
2962
  }
2775
2963