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/src/ana-logger.cjs
CHANGED
|
@@ -398,6 +398,153 @@ function createTarGzArchiveSync(inputFile, archivePath, compressionLevel = 1) {
|
|
|
398
398
|
}
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
+
function getInvocationLine()
|
|
402
|
+
{
|
|
403
|
+
try
|
|
404
|
+
{
|
|
405
|
+
const error = new Error();
|
|
406
|
+
const stack = error.stack;
|
|
407
|
+
let anaLoggerPossibleFileName = "ana-logger";
|
|
408
|
+
let isMinified = false;
|
|
409
|
+
let result = null;
|
|
410
|
+
let strippedOutStackTrace;
|
|
411
|
+
let errorText = [];
|
|
412
|
+
|
|
413
|
+
if (stack) {
|
|
414
|
+
const lines = stack.split('\n');
|
|
415
|
+
let fileName = null;
|
|
416
|
+
if (lines.length >= 3) {
|
|
417
|
+
let index = 0;
|
|
418
|
+
// Look for the reference of this line
|
|
419
|
+
for (let i = 0, l = lines.length; i < l; i++) {
|
|
420
|
+
const line = lines[i];
|
|
421
|
+
|
|
422
|
+
// We can't use the name if it's minified
|
|
423
|
+
const parts = line.split(':');
|
|
424
|
+
if (parts.length < 3) {
|
|
425
|
+
errorText.push(line);
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
index = i;
|
|
430
|
+
|
|
431
|
+
fileName = parts[parts.length - 3];
|
|
432
|
+
|
|
433
|
+
if (line.indexOf(anaLoggerPossibleFileName)=== -1) {
|
|
434
|
+
// We're sure we can use this stacktrace
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (line.indexOf("getInvocationLine")=== -1) {
|
|
439
|
+
// The file is minified
|
|
440
|
+
// We're only partially sure we can use this stacktrace
|
|
441
|
+
isMinified = true;
|
|
442
|
+
// We try to extract the file name
|
|
443
|
+
anaLoggerPossibleFileName = fileName.split(/[\\/]/).pop();
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// We have no idea if the stacktrace will help us, but we leave the search
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Look for when the call was done exactly
|
|
452
|
+
for (let i = index + 1, l = lines.length; i < l; i++) {
|
|
453
|
+
const lineStr = lines[i];
|
|
454
|
+
if (lineStr.indexOf(fileName) > -1) {
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const parts = lineStr.split(':');
|
|
459
|
+
if (parts.length < 3) {
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
strippedOutStackTrace = errorText.join("\n") + lines.slice(i).join('\n');
|
|
464
|
+
|
|
465
|
+
const col = parseInt(parts.pop());
|
|
466
|
+
const line = parseInt(parts.pop());
|
|
467
|
+
const file = parts.pop();
|
|
468
|
+
let infoStr = parts.pop();
|
|
469
|
+
let infoArr = infoStr.split(" ");
|
|
470
|
+
|
|
471
|
+
let method = null;
|
|
472
|
+
for (let j = 0; j < infoArr.length; j++) {
|
|
473
|
+
const element = infoArr[j];
|
|
474
|
+
if (!element) {
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (element.indexOf("at")===0) {
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
method = element;
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
result = {
|
|
487
|
+
file,
|
|
488
|
+
line,
|
|
489
|
+
col,
|
|
490
|
+
method,
|
|
491
|
+
isMinified,
|
|
492
|
+
stack: strippedOutStackTrace
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return result;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
catch(err)
|
|
503
|
+
{
|
|
504
|
+
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function generateLid(maxChars = 8)
|
|
511
|
+
{
|
|
512
|
+
try
|
|
513
|
+
{
|
|
514
|
+
const line = getInvocationLine();
|
|
515
|
+
if (!line) {
|
|
516
|
+
return `LID${Date.now()}`;
|
|
517
|
+
}
|
|
518
|
+
const fun = line.method.split(".");
|
|
519
|
+
const id = fun[0].toUpperCase().substring(0, 3);
|
|
520
|
+
if (id.length >= maxChars) {
|
|
521
|
+
return id.substring(0, maxChars);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
let combined1 = `${id}:${line.line}`;
|
|
525
|
+
if (combined1.length >= maxChars) {
|
|
526
|
+
combined1 = combined1.replaceAll(":", "");
|
|
527
|
+
return combined1.substring(0, maxChars);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
let combined2 = `${id}:${line.line}:${line.col}`;
|
|
531
|
+
if (combined2.length > maxChars) {
|
|
532
|
+
const combined3 = combined2.substring(0, maxChars);
|
|
533
|
+
if (combined3.endsWith(":")) {
|
|
534
|
+
return `${id}${line.line}:${line.col}`.substring(0, maxChars);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return combined2.substring(0, maxChars);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return `${id}${line.line}:${line.col}`.substring(0, maxChars);
|
|
541
|
+
}
|
|
542
|
+
catch (e) {
|
|
543
|
+
return `ERR_LID${Date.now()}`;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
|
|
401
548
|
/**
|
|
402
549
|
* https://stackoverflow.com/questions/17575790/environment-detection-node-js-or-browser
|
|
403
550
|
* @returns {string}
|
|
@@ -515,6 +662,12 @@ class ____AnaLogger
|
|
|
515
662
|
|
|
516
663
|
originalFormatFunction;
|
|
517
664
|
|
|
665
|
+
static lidTable = {};
|
|
666
|
+
static lidTableOn = false;
|
|
667
|
+
|
|
668
|
+
forceLidOn = false;
|
|
669
|
+
resolveLineCall = false;
|
|
670
|
+
resolveErrorLineCall = false;
|
|
518
671
|
|
|
519
672
|
constructor({name = "default"} = {})
|
|
520
673
|
{
|
|
@@ -568,6 +721,79 @@ class ____AnaLogger
|
|
|
568
721
|
return this.instanceId;
|
|
569
722
|
}
|
|
570
723
|
|
|
724
|
+
/**
|
|
725
|
+
* For the logger to generate a lid when none is specified
|
|
726
|
+
* @param lidOn
|
|
727
|
+
*/
|
|
728
|
+
forceLid(lidOn = true)
|
|
729
|
+
{
|
|
730
|
+
this.forceLidOn = !!lidOn;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
forceResolveLineCall(resolveLineCall = true)
|
|
734
|
+
{
|
|
735
|
+
this.resolveLineCall = !!resolveLineCall;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
forceResolveErrorLineCall(resolveErrorLineCall = true)
|
|
739
|
+
{
|
|
740
|
+
this.resolveErrorLineCall = !!resolveErrorLineCall;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
importLids(lids)
|
|
744
|
+
{
|
|
745
|
+
for (let lid in lids)
|
|
746
|
+
{
|
|
747
|
+
const lidObj = lids[lid] || {};
|
|
748
|
+
lidObj.lid = lid;
|
|
749
|
+
lidObj.callCount = 0;
|
|
750
|
+
lidObj.callTimes = [];
|
|
751
|
+
____AnaLogger.lidTable[lid] = lidObj;
|
|
752
|
+
}
|
|
753
|
+
____AnaLogger.lidTableOn = true;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
loadLids(lids)
|
|
757
|
+
{
|
|
758
|
+
lids = lids || {};
|
|
759
|
+
this.importLids(lids);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
convertTimestampToDate(timestamp)
|
|
763
|
+
{
|
|
764
|
+
const date = new Date(timestamp); // Create a Date object from the timestamp
|
|
765
|
+
|
|
766
|
+
const year = date.getFullYear();
|
|
767
|
+
const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
|
|
768
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
769
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
770
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
771
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
772
|
+
const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
|
|
773
|
+
|
|
774
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
getLids()
|
|
778
|
+
{
|
|
779
|
+
const clone = {...__AnaLogger.lidTable };
|
|
780
|
+
for (let lid in clone)
|
|
781
|
+
{
|
|
782
|
+
const lidObj = clone[lid] || {};
|
|
783
|
+
if (lidObj.callTimes.length)
|
|
784
|
+
{
|
|
785
|
+
lidObj.dates = [];
|
|
786
|
+
for (let j = 0; j < lidObj.callTimes.length; ++j)
|
|
787
|
+
{
|
|
788
|
+
const callTime = lidObj.callTimes[j];
|
|
789
|
+
const readableTime = this.convertTimestampToDate(callTime);
|
|
790
|
+
lidObj.dates.push(readableTime);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
return clone;
|
|
795
|
+
}
|
|
796
|
+
|
|
571
797
|
keepLogHistory()
|
|
572
798
|
{
|
|
573
799
|
this.keepLog = true;
|
|
@@ -2007,18 +2233,74 @@ class ____AnaLogger
|
|
|
2007
2233
|
}
|
|
2008
2234
|
}
|
|
2009
2235
|
|
|
2236
|
+
isContextMessagePattern(str) {
|
|
2237
|
+
return /\{\{[^}]+}}/.test(str);
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
transformContextMessage(template, data)
|
|
2241
|
+
{
|
|
2242
|
+
let result = template;
|
|
2243
|
+
for (const key in data)
|
|
2244
|
+
{
|
|
2245
|
+
const placeholder = `{{${key}}}`;
|
|
2246
|
+
const value = data[key];
|
|
2247
|
+
// Replace all occurrences of the placeholder with the value
|
|
2248
|
+
result = result.replaceAll(placeholder, value);
|
|
2249
|
+
}
|
|
2250
|
+
return result;
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2010
2253
|
/**
|
|
2011
2254
|
* Display log following template
|
|
2012
2255
|
* @param context
|
|
2256
|
+
* @param argsWithoutContext
|
|
2013
2257
|
*/
|
|
2014
|
-
processOutput(context = {})
|
|
2258
|
+
processOutput(context = {}, ...argsWithoutContext)
|
|
2015
2259
|
{
|
|
2016
2260
|
try
|
|
2017
2261
|
{
|
|
2018
2262
|
let message = "";
|
|
2263
|
+
|
|
2264
|
+
if (____AnaLogger.lidTableOn && context.lid) {
|
|
2265
|
+
const lidObj = ____AnaLogger.lidTable[context.lid];
|
|
2266
|
+
|
|
2267
|
+
// If the lid is already in the table, we set the message if not existing
|
|
2268
|
+
if (lidObj)
|
|
2269
|
+
{
|
|
2270
|
+
context.message = context.message || lidObj.message;
|
|
2271
|
+
lidObj.callCount = lidObj.callCount || 0;
|
|
2272
|
+
++lidObj.callCount;
|
|
2273
|
+
lidObj.callTimes.push(Date.now());
|
|
2274
|
+
}
|
|
2275
|
+
// If the lid is not already in the table, we register it
|
|
2276
|
+
else {
|
|
2277
|
+
____AnaLogger.lidTable[context.lid] = {
|
|
2278
|
+
...context,
|
|
2279
|
+
message: argsWithoutContext[0],
|
|
2280
|
+
lid: context.lid,
|
|
2281
|
+
callCount: 1,
|
|
2282
|
+
callTimes: [Date.now()]
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
if (context.message) {
|
|
2288
|
+
// If the context message is a template
|
|
2289
|
+
if (this.isContextMessagePattern(context.message)) {
|
|
2290
|
+
// The context message second parameter should be an object that we will use to perform the replacement
|
|
2291
|
+
if (argsWithoutContext.length >= 1 && typeof argsWithoutContext[0] === "object") {
|
|
2292
|
+
context.message = this.transformContextMessage(context.message, argsWithoutContext[0]);
|
|
2293
|
+
// We remove the second parameter from the arguments
|
|
2294
|
+
argsWithoutContext.shift();
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
// We add the context message as an arguments
|
|
2299
|
+
argsWithoutContext.unshift(context.message);
|
|
2300
|
+
}
|
|
2019
2301
|
this.applySymbolByName(context);
|
|
2020
2302
|
|
|
2021
|
-
this.checkOnLogging(context, context,
|
|
2303
|
+
this.checkOnLogging(context, context, argsWithoutContext, "onContext");
|
|
2022
2304
|
if (!this.isTargetAllowed(context.target))
|
|
2023
2305
|
{
|
|
2024
2306
|
return;
|
|
@@ -2034,12 +2316,12 @@ class ____AnaLogger
|
|
|
2034
2316
|
return;
|
|
2035
2317
|
}
|
|
2036
2318
|
|
|
2037
|
-
|
|
2038
|
-
const newMessages = this.checkOnLogging(context, arguments && arguments.length > 1? arguments[1] : arguments, arguments,"onMessage");
|
|
2319
|
+
const newMessages = this.checkOnLogging(context, argsWithoutContext[0], arguments,"onMessage");
|
|
2039
2320
|
if (newMessages !== undefined) {
|
|
2040
2321
|
arguments[1] = newMessages;
|
|
2041
2322
|
}
|
|
2042
|
-
|
|
2323
|
+
|
|
2324
|
+
let args = argsWithoutContext;
|
|
2043
2325
|
|
|
2044
2326
|
message = this.convertArgumentsToText(args);
|
|
2045
2327
|
|
|
@@ -2146,6 +2428,12 @@ class ____AnaLogger
|
|
|
2146
2428
|
options.hasOwnProperty("lid");
|
|
2147
2429
|
}
|
|
2148
2430
|
|
|
2431
|
+
/**
|
|
2432
|
+
* Convert a string to an object by parsing the string
|
|
2433
|
+
* and identifying key-value pairs
|
|
2434
|
+
* @param str
|
|
2435
|
+
* @returns {{}|null}
|
|
2436
|
+
*/
|
|
2149
2437
|
stringToObject(str) {
|
|
2150
2438
|
try {
|
|
2151
2439
|
str = str.trim();
|
|
@@ -2210,39 +2498,39 @@ class ____AnaLogger
|
|
|
2210
2498
|
/**
|
|
2211
2499
|
* Convert a string into a Context object if possible
|
|
2212
2500
|
* TODO: To implement in next version
|
|
2213
|
-
* @param str
|
|
2214
2501
|
* @returns {string}
|
|
2502
|
+
* @param input
|
|
2215
2503
|
*/
|
|
2216
|
-
extractContextFromInput(
|
|
2504
|
+
extractContextFromInput(input)
|
|
2217
2505
|
{
|
|
2218
|
-
if (typeof
|
|
2506
|
+
if (typeof input === "string" || input instanceof String)
|
|
2219
2507
|
{
|
|
2220
|
-
if (
|
|
2508
|
+
if (input.toLowerCase().indexOf("lid:") !== 0)
|
|
2221
2509
|
{
|
|
2222
|
-
return
|
|
2510
|
+
return input;
|
|
2223
2511
|
}
|
|
2224
2512
|
|
|
2225
|
-
const obj = this.stringToObject(
|
|
2513
|
+
const obj = this.stringToObject(input);
|
|
2226
2514
|
if (obj) {
|
|
2227
|
-
|
|
2515
|
+
input = obj;
|
|
2228
2516
|
}
|
|
2229
2517
|
}
|
|
2230
2518
|
|
|
2231
|
-
if (typeof
|
|
2232
|
-
if (this.isExtendedOptionsPassed(
|
|
2233
|
-
if (
|
|
2234
|
-
const obj = this.#contexts[
|
|
2519
|
+
if (typeof input==="object" && !Array.isArray(input) && input!==null) {
|
|
2520
|
+
if (this.isExtendedOptionsPassed(input)) {
|
|
2521
|
+
if (input.contextName) {
|
|
2522
|
+
const obj = this.#contexts[input.contextName];
|
|
2235
2523
|
if (obj) {
|
|
2236
|
-
|
|
2524
|
+
input = Object.assign({}, obj, input);
|
|
2237
2525
|
}
|
|
2238
2526
|
}
|
|
2239
|
-
if (!
|
|
2240
|
-
|
|
2527
|
+
if (!input.target) {
|
|
2528
|
+
input.target = this.getActiveTarget();
|
|
2241
2529
|
}
|
|
2242
2530
|
}
|
|
2243
2531
|
}
|
|
2244
2532
|
|
|
2245
|
-
return
|
|
2533
|
+
return input;
|
|
2246
2534
|
}
|
|
2247
2535
|
|
|
2248
2536
|
listSymbols()
|
|
@@ -2304,13 +2592,25 @@ class ____AnaLogger
|
|
|
2304
2592
|
log(options, ...args)
|
|
2305
2593
|
{
|
|
2306
2594
|
options = this.extractContextFromInput(options);
|
|
2595
|
+
|
|
2307
2596
|
// If the first parameter is not of context format,
|
|
2308
2597
|
// We use the default context
|
|
2309
2598
|
if (!this.isExtendedOptionsPassed(options))
|
|
2310
2599
|
{
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2600
|
+
if (!this.forceLidOn)
|
|
2601
|
+
{
|
|
2602
|
+
const defaultContext = this.generateDefaultContext();
|
|
2603
|
+
this.processOutput.apply(this, [defaultContext, options, ...args]);
|
|
2604
|
+
return;
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2607
|
+
if (!args || !args.length)
|
|
2608
|
+
{
|
|
2609
|
+
args = [options];
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
const newLid = generateLid(this.options.lidLenMax);
|
|
2613
|
+
options = {lid: newLid};
|
|
2314
2614
|
}
|
|
2315
2615
|
|
|
2316
2616
|
const someContext = this.generateDefaultContext();
|
|
@@ -2322,6 +2622,14 @@ class ____AnaLogger
|
|
|
2322
2622
|
return;
|
|
2323
2623
|
}
|
|
2324
2624
|
|
|
2625
|
+
if (this.resolveLineCall)
|
|
2626
|
+
{
|
|
2627
|
+
// If this.resolveErrorLineCall, the stack has already been set
|
|
2628
|
+
if (!this.resolveErrorLineCall)
|
|
2629
|
+
{
|
|
2630
|
+
context.stack = getInvocationLine();
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2325
2633
|
this.processOutput.apply(this, [context, ...args]);
|
|
2326
2634
|
}
|
|
2327
2635
|
|
|
@@ -2338,16 +2646,25 @@ class ____AnaLogger
|
|
|
2338
2646
|
// We use the error context and display
|
|
2339
2647
|
if (!this.isExtendedOptionsPassed(options))
|
|
2340
2648
|
{
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2649
|
+
if (!this.forceLidOn)
|
|
2650
|
+
{
|
|
2651
|
+
const defaultContext = this.generateErrorContext();
|
|
2652
|
+
this.processOutput.apply(this, [defaultContext, options, ...args]);
|
|
2653
|
+
return;
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
const newLid = generateLid(this.options.lidLenMax);
|
|
2657
|
+
options = {lid: newLid};
|
|
2344
2658
|
}
|
|
2345
2659
|
|
|
2346
2660
|
const errorContext = this.generateErrorContext();
|
|
2347
2661
|
let context = this.convertToContext(options, errorContext);
|
|
2348
2662
|
|
|
2349
|
-
|
|
2350
|
-
|
|
2663
|
+
if (this.resolveErrorLineCall)
|
|
2664
|
+
{
|
|
2665
|
+
context.stack = getInvocationLine();
|
|
2666
|
+
}
|
|
2667
|
+
this.log(context, ...args);
|
|
2351
2668
|
}
|
|
2352
2669
|
|
|
2353
2670
|
overrideError()
|