analogger 1.37.0 → 2.0.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 +168 -1
- package/ana-logger.d.cts +29 -4
- package/browser/ana-logger.mjs +342 -28
- package/demo.cjs +53 -1
- package/dist/analogger-browser.min.mjs +8 -5
- package/dist/html-to-image-plugin.min.mjs +8 -5
- package/esm/ana-logger.mjs +342 -28
- package/package.json +1 -1
- package/src/ana-logger.cjs +345 -28
package/esm/ana-logger.mjs
CHANGED
|
@@ -158,6 +158,7 @@ const symbolNames = {
|
|
|
158
158
|
lock : "🔒",
|
|
159
159
|
male_sign : "♂",
|
|
160
160
|
minus_sign : "➖",
|
|
161
|
+
money_bag : "💰",
|
|
161
162
|
no_entry : "⛔",
|
|
162
163
|
old_key : "🗝️",
|
|
163
164
|
partly_sunny : "⛅",
|
|
@@ -411,6 +412,153 @@ function createTarGzArchiveSync(inputFile, archivePath, compressionLevel = 1) {
|
|
|
411
412
|
}
|
|
412
413
|
}
|
|
413
414
|
|
|
415
|
+
function getInvocationLine()
|
|
416
|
+
{
|
|
417
|
+
try
|
|
418
|
+
{
|
|
419
|
+
const error = new Error();
|
|
420
|
+
const stack = error.stack;
|
|
421
|
+
let anaLoggerPossibleFileName = "ana-logger";
|
|
422
|
+
let isMinified = false;
|
|
423
|
+
let result = null;
|
|
424
|
+
let strippedOutStackTrace;
|
|
425
|
+
let errorText = [];
|
|
426
|
+
|
|
427
|
+
if (stack) {
|
|
428
|
+
const lines = stack.split('\n');
|
|
429
|
+
let fileName = null;
|
|
430
|
+
if (lines.length >= 3) {
|
|
431
|
+
let index = 0;
|
|
432
|
+
// Look for the reference of this line
|
|
433
|
+
for (let i = 0, l = lines.length; i < l; i++) {
|
|
434
|
+
const line = lines[i];
|
|
435
|
+
|
|
436
|
+
// We can't use the name if it's minified
|
|
437
|
+
const parts = line.split(':');
|
|
438
|
+
if (parts.length < 3) {
|
|
439
|
+
errorText.push(line);
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
index = i;
|
|
444
|
+
|
|
445
|
+
fileName = parts[parts.length - 3];
|
|
446
|
+
|
|
447
|
+
if (line.indexOf(anaLoggerPossibleFileName)=== -1) {
|
|
448
|
+
// We're sure we can use this stacktrace
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (line.indexOf("getInvocationLine")=== -1) {
|
|
453
|
+
// The file is minified
|
|
454
|
+
// We're only partially sure we can use this stacktrace
|
|
455
|
+
isMinified = true;
|
|
456
|
+
// We try to extract the file name
|
|
457
|
+
anaLoggerPossibleFileName = fileName.split(/[\\/]/).pop();
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// We have no idea if the stacktrace will help us, but we leave the search
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Look for when the call was done exactly
|
|
466
|
+
for (let i = index + 1, l = lines.length; i < l; i++) {
|
|
467
|
+
const lineStr = lines[i];
|
|
468
|
+
if (lineStr.indexOf(fileName) > -1) {
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const parts = lineStr.split(':');
|
|
473
|
+
if (parts.length < 3) {
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
strippedOutStackTrace = errorText.join("\n") + lines.slice(i).join('\n');
|
|
478
|
+
|
|
479
|
+
const col = parseInt(parts.pop());
|
|
480
|
+
const line = parseInt(parts.pop());
|
|
481
|
+
const file = parts.pop();
|
|
482
|
+
let infoStr = parts.pop();
|
|
483
|
+
let infoArr = infoStr.split(" ");
|
|
484
|
+
|
|
485
|
+
let method = null;
|
|
486
|
+
for (let j = 0; j < infoArr.length; j++) {
|
|
487
|
+
const element = infoArr[j];
|
|
488
|
+
if (!element) {
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (element.indexOf("at")===0) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
method = element;
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
result = {
|
|
501
|
+
file,
|
|
502
|
+
line,
|
|
503
|
+
col,
|
|
504
|
+
method,
|
|
505
|
+
isMinified,
|
|
506
|
+
stack: strippedOutStackTrace
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return result;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
catch(err)
|
|
517
|
+
{
|
|
518
|
+
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function generateLid(maxChars = 8)
|
|
525
|
+
{
|
|
526
|
+
try
|
|
527
|
+
{
|
|
528
|
+
const line = getInvocationLine();
|
|
529
|
+
if (!line) {
|
|
530
|
+
return `LID${Date.now()}`;
|
|
531
|
+
}
|
|
532
|
+
const fun = line.method.split(".");
|
|
533
|
+
const id = fun[0].toUpperCase().substring(0, 3);
|
|
534
|
+
if (id.length >= maxChars) {
|
|
535
|
+
return id.substring(0, maxChars);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
let combined1 = `${id}:${line.line}`;
|
|
539
|
+
if (combined1.length >= maxChars) {
|
|
540
|
+
combined1 = combined1.replaceAll(":", "");
|
|
541
|
+
return combined1.substring(0, maxChars);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
let combined2 = `${id}:${line.line}:${line.col}`;
|
|
545
|
+
if (combined2.length > maxChars) {
|
|
546
|
+
const combined3 = combined2.substring(0, maxChars);
|
|
547
|
+
if (combined3.endsWith(":")) {
|
|
548
|
+
return `${id}${line.line}:${line.col}`.substring(0, maxChars);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return combined2.substring(0, maxChars);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return `${id}${line.line}:${line.col}`.substring(0, maxChars);
|
|
555
|
+
}
|
|
556
|
+
catch (e) {
|
|
557
|
+
return `ERR_LID${Date.now()}`;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
|
|
414
562
|
/**
|
|
415
563
|
* https://stackoverflow.com/questions/17575790/environment-detection-node-js-or-browser
|
|
416
564
|
* @returns {string}
|
|
@@ -528,6 +676,12 @@ class ____AnaLogger
|
|
|
528
676
|
|
|
529
677
|
originalFormatFunction;
|
|
530
678
|
|
|
679
|
+
static lidTable = {};
|
|
680
|
+
static lidTableOn = false;
|
|
681
|
+
|
|
682
|
+
forceLidOn = false;
|
|
683
|
+
resolveLineCall = false;
|
|
684
|
+
resolveErrorLineCall = false;
|
|
531
685
|
|
|
532
686
|
constructor({name = "default"} = {})
|
|
533
687
|
{
|
|
@@ -581,6 +735,79 @@ class ____AnaLogger
|
|
|
581
735
|
return this.instanceId;
|
|
582
736
|
}
|
|
583
737
|
|
|
738
|
+
/**
|
|
739
|
+
* For the logger to generate a lid when none is specified
|
|
740
|
+
* @param lidOn
|
|
741
|
+
*/
|
|
742
|
+
forceLid(lidOn = true)
|
|
743
|
+
{
|
|
744
|
+
this.forceLidOn = !!lidOn;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
forceResolveLineCall(resolveLineCall = true)
|
|
748
|
+
{
|
|
749
|
+
this.resolveLineCall = !!resolveLineCall;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
forceResolveErrorLineCall(resolveErrorLineCall = true)
|
|
753
|
+
{
|
|
754
|
+
this.resolveErrorLineCall = !!resolveErrorLineCall;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
importLids(lids)
|
|
758
|
+
{
|
|
759
|
+
for (let lid in lids)
|
|
760
|
+
{
|
|
761
|
+
const lidObj = lids[lid] || {};
|
|
762
|
+
lidObj.lid = lid;
|
|
763
|
+
lidObj.callCount = 0;
|
|
764
|
+
lidObj.callTimes = [];
|
|
765
|
+
____AnaLogger.lidTable[lid] = lidObj;
|
|
766
|
+
}
|
|
767
|
+
____AnaLogger.lidTableOn = true;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
loadLids(lids)
|
|
771
|
+
{
|
|
772
|
+
lids = lids || {};
|
|
773
|
+
this.importLids(lids);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
convertTimestampToDate(timestamp)
|
|
777
|
+
{
|
|
778
|
+
const date = new Date(timestamp); // Create a Date object from the timestamp
|
|
779
|
+
|
|
780
|
+
const year = date.getFullYear();
|
|
781
|
+
const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
|
|
782
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
783
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
784
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
785
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
786
|
+
const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
|
|
787
|
+
|
|
788
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
getLids()
|
|
792
|
+
{
|
|
793
|
+
const clone = {...__AnaLogger.lidTable };
|
|
794
|
+
for (let lid in clone)
|
|
795
|
+
{
|
|
796
|
+
const lidObj = clone[lid] || {};
|
|
797
|
+
if (lidObj.callTimes.length)
|
|
798
|
+
{
|
|
799
|
+
lidObj.dates = [];
|
|
800
|
+
for (let j = 0; j < lidObj.callTimes.length; ++j)
|
|
801
|
+
{
|
|
802
|
+
const callTime = lidObj.callTimes[j];
|
|
803
|
+
const readableTime = this.convertTimestampToDate(callTime);
|
|
804
|
+
lidObj.dates.push(readableTime);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
return clone;
|
|
809
|
+
}
|
|
810
|
+
|
|
584
811
|
keepLogHistory()
|
|
585
812
|
{
|
|
586
813
|
this.keepLog = true;
|
|
@@ -2018,18 +2245,74 @@ class ____AnaLogger
|
|
|
2018
2245
|
}
|
|
2019
2246
|
}
|
|
2020
2247
|
|
|
2248
|
+
isContextMessagePattern(str) {
|
|
2249
|
+
return /\{\{[^}]+}}/.test(str);
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
transformContextMessage(template, data)
|
|
2253
|
+
{
|
|
2254
|
+
let result = template;
|
|
2255
|
+
for (const key in data)
|
|
2256
|
+
{
|
|
2257
|
+
const placeholder = `{{${key}}}`;
|
|
2258
|
+
const value = data[key];
|
|
2259
|
+
// Replace all occurrences of the placeholder with the value
|
|
2260
|
+
result = result.replaceAll(placeholder, value);
|
|
2261
|
+
}
|
|
2262
|
+
return result;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2021
2265
|
/**
|
|
2022
2266
|
* Display log following template
|
|
2023
2267
|
* @param context
|
|
2268
|
+
* @param argsWithoutContext
|
|
2024
2269
|
*/
|
|
2025
|
-
processOutput(context = {})
|
|
2270
|
+
processOutput(context = {}, ...argsWithoutContext)
|
|
2026
2271
|
{
|
|
2027
2272
|
try
|
|
2028
2273
|
{
|
|
2029
2274
|
let message = "";
|
|
2275
|
+
|
|
2276
|
+
if (____AnaLogger.lidTableOn && context.lid) {
|
|
2277
|
+
const lidObj = ____AnaLogger.lidTable[context.lid];
|
|
2278
|
+
|
|
2279
|
+
// If the lid is already in the table, we set the message if not existing
|
|
2280
|
+
if (lidObj)
|
|
2281
|
+
{
|
|
2282
|
+
context.message = context.message || lidObj.message;
|
|
2283
|
+
lidObj.callCount = lidObj.callCount || 0;
|
|
2284
|
+
++lidObj.callCount;
|
|
2285
|
+
lidObj.callTimes.push(Date.now());
|
|
2286
|
+
}
|
|
2287
|
+
// If the lid is not already in the table, we register it
|
|
2288
|
+
else {
|
|
2289
|
+
____AnaLogger.lidTable[context.lid] = {
|
|
2290
|
+
...context,
|
|
2291
|
+
message: argsWithoutContext[0],
|
|
2292
|
+
lid: context.lid,
|
|
2293
|
+
callCount: 1,
|
|
2294
|
+
callTimes: [Date.now()]
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
if (context.message) {
|
|
2300
|
+
// If the context message is a template
|
|
2301
|
+
if (this.isContextMessagePattern(context.message)) {
|
|
2302
|
+
// The context message second parameter should be an object that we will use to perform the replacement
|
|
2303
|
+
if (argsWithoutContext.length >= 1 && typeof argsWithoutContext[0] === "object") {
|
|
2304
|
+
context.message = this.transformContextMessage(context.message, argsWithoutContext[0]);
|
|
2305
|
+
// We remove the second parameter from the arguments
|
|
2306
|
+
argsWithoutContext.shift();
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
// We add the context message as an arguments
|
|
2311
|
+
argsWithoutContext.unshift(context.message);
|
|
2312
|
+
}
|
|
2030
2313
|
this.applySymbolByName(context);
|
|
2031
2314
|
|
|
2032
|
-
this.checkOnLogging(context, context,
|
|
2315
|
+
this.checkOnLogging(context, context, argsWithoutContext, "onContext");
|
|
2033
2316
|
if (!this.isTargetAllowed(context.target))
|
|
2034
2317
|
{
|
|
2035
2318
|
return;
|
|
@@ -2045,12 +2328,12 @@ class ____AnaLogger
|
|
|
2045
2328
|
return;
|
|
2046
2329
|
}
|
|
2047
2330
|
|
|
2048
|
-
|
|
2049
|
-
const newMessages = this.checkOnLogging(context, arguments && arguments.length > 1? arguments[1] : arguments, arguments,"onMessage");
|
|
2331
|
+
const newMessages = this.checkOnLogging(context, argsWithoutContext[0], arguments,"onMessage");
|
|
2050
2332
|
if (newMessages !== undefined) {
|
|
2051
2333
|
arguments[1] = newMessages;
|
|
2052
2334
|
}
|
|
2053
|
-
|
|
2335
|
+
|
|
2336
|
+
let args = argsWithoutContext;
|
|
2054
2337
|
|
|
2055
2338
|
message = this.convertArgumentsToText(args);
|
|
2056
2339
|
|
|
@@ -2157,6 +2440,12 @@ class ____AnaLogger
|
|
|
2157
2440
|
options.hasOwnProperty("lid");
|
|
2158
2441
|
}
|
|
2159
2442
|
|
|
2443
|
+
/**
|
|
2444
|
+
* Convert a string to an object by parsing the string
|
|
2445
|
+
* and identifying key-value pairs
|
|
2446
|
+
* @param str
|
|
2447
|
+
* @returns {{}|null}
|
|
2448
|
+
*/
|
|
2160
2449
|
stringToObject(str) {
|
|
2161
2450
|
try {
|
|
2162
2451
|
str = str.trim();
|
|
@@ -2221,39 +2510,39 @@ class ____AnaLogger
|
|
|
2221
2510
|
/**
|
|
2222
2511
|
* Convert a string into a Context object if possible
|
|
2223
2512
|
* TODO: To implement in next version
|
|
2224
|
-
* @param str
|
|
2225
2513
|
* @returns {string}
|
|
2514
|
+
* @param input
|
|
2226
2515
|
*/
|
|
2227
|
-
extractContextFromInput(
|
|
2516
|
+
extractContextFromInput(input)
|
|
2228
2517
|
{
|
|
2229
|
-
if (typeof
|
|
2518
|
+
if (typeof input === "string" || input instanceof String)
|
|
2230
2519
|
{
|
|
2231
|
-
if (
|
|
2520
|
+
if (input.toLowerCase().indexOf("lid:") !== 0)
|
|
2232
2521
|
{
|
|
2233
|
-
return
|
|
2522
|
+
return input;
|
|
2234
2523
|
}
|
|
2235
2524
|
|
|
2236
|
-
const obj = this.stringToObject(
|
|
2525
|
+
const obj = this.stringToObject(input);
|
|
2237
2526
|
if (obj) {
|
|
2238
|
-
|
|
2527
|
+
input = obj;
|
|
2239
2528
|
}
|
|
2240
2529
|
}
|
|
2241
2530
|
|
|
2242
|
-
if (typeof
|
|
2243
|
-
if (this.isExtendedOptionsPassed(
|
|
2244
|
-
if (
|
|
2245
|
-
const obj = this.#contexts[
|
|
2531
|
+
if (typeof input==="object" && !Array.isArray(input) && input!==null) {
|
|
2532
|
+
if (this.isExtendedOptionsPassed(input)) {
|
|
2533
|
+
if (input.contextName) {
|
|
2534
|
+
const obj = this.#contexts[input.contextName];
|
|
2246
2535
|
if (obj) {
|
|
2247
|
-
|
|
2536
|
+
input = Object.assign({}, obj, input);
|
|
2248
2537
|
}
|
|
2249
2538
|
}
|
|
2250
|
-
if (!
|
|
2251
|
-
|
|
2539
|
+
if (!input.target) {
|
|
2540
|
+
input.target = this.getActiveTarget();
|
|
2252
2541
|
}
|
|
2253
2542
|
}
|
|
2254
2543
|
}
|
|
2255
2544
|
|
|
2256
|
-
return
|
|
2545
|
+
return input;
|
|
2257
2546
|
}
|
|
2258
2547
|
|
|
2259
2548
|
listSymbols()
|
|
@@ -2315,13 +2604,25 @@ class ____AnaLogger
|
|
|
2315
2604
|
log(options, ...args)
|
|
2316
2605
|
{
|
|
2317
2606
|
options = this.extractContextFromInput(options);
|
|
2607
|
+
|
|
2318
2608
|
// If the first parameter is not of context format,
|
|
2319
2609
|
// We use the default context
|
|
2320
2610
|
if (!this.isExtendedOptionsPassed(options))
|
|
2321
2611
|
{
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2612
|
+
if (!this.forceLidOn)
|
|
2613
|
+
{
|
|
2614
|
+
const defaultContext = this.generateDefaultContext();
|
|
2615
|
+
this.processOutput.apply(this, [defaultContext, options, ...args]);
|
|
2616
|
+
return;
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
if (!args || !args.length)
|
|
2620
|
+
{
|
|
2621
|
+
args = [options];
|
|
2622
|
+
}
|
|
2623
|
+
|
|
2624
|
+
const newLid = generateLid(this.options.lidLenMax);
|
|
2625
|
+
options = {lid: newLid};
|
|
2325
2626
|
}
|
|
2326
2627
|
|
|
2327
2628
|
const someContext = this.generateDefaultContext();
|
|
@@ -2333,6 +2634,10 @@ class ____AnaLogger
|
|
|
2333
2634
|
return;
|
|
2334
2635
|
}
|
|
2335
2636
|
|
|
2637
|
+
if (this.resolveLineCall)
|
|
2638
|
+
{
|
|
2639
|
+
context.stack = getInvocationLine();
|
|
2640
|
+
}
|
|
2336
2641
|
this.processOutput.apply(this, [context, ...args]);
|
|
2337
2642
|
}
|
|
2338
2643
|
|
|
@@ -2349,16 +2654,25 @@ class ____AnaLogger
|
|
|
2349
2654
|
// We use the error context and display
|
|
2350
2655
|
if (!this.isExtendedOptionsPassed(options))
|
|
2351
2656
|
{
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2657
|
+
if (!this.forceLidOn)
|
|
2658
|
+
{
|
|
2659
|
+
const defaultContext = this.generateErrorContext();
|
|
2660
|
+
this.processOutput.apply(this, [defaultContext, options, ...args]);
|
|
2661
|
+
return;
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
const newLid = generateLid(this.options.lidLenMax);
|
|
2665
|
+
options = {lid: newLid};
|
|
2355
2666
|
}
|
|
2356
2667
|
|
|
2357
2668
|
const errorContext = this.generateErrorContext();
|
|
2358
2669
|
let context = this.convertToContext(options, errorContext);
|
|
2359
2670
|
|
|
2360
|
-
|
|
2361
|
-
|
|
2671
|
+
if (this.resolveErrorLineCall)
|
|
2672
|
+
{
|
|
2673
|
+
context.stack = getInvocationLine();
|
|
2674
|
+
}
|
|
2675
|
+
this.log(context, ...args);
|
|
2362
2676
|
}
|
|
2363
2677
|
|
|
2364
2678
|
overrideError()
|