analogger 1.36.1 → 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 +346 -28
package/src/ana-logger.cjs
CHANGED
|
@@ -144,6 +144,7 @@ const symbolNames = {
|
|
|
144
144
|
lock : "🔒",
|
|
145
145
|
male_sign : "♂",
|
|
146
146
|
minus_sign : "➖",
|
|
147
|
+
money_bag : "💰",
|
|
147
148
|
no_entry : "⛔",
|
|
148
149
|
old_key : "🗝️",
|
|
149
150
|
partly_sunny : "⛅",
|
|
@@ -397,6 +398,153 @@ function createTarGzArchiveSync(inputFile, archivePath, compressionLevel = 1) {
|
|
|
397
398
|
}
|
|
398
399
|
}
|
|
399
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
|
+
|
|
400
548
|
/**
|
|
401
549
|
* https://stackoverflow.com/questions/17575790/environment-detection-node-js-or-browser
|
|
402
550
|
* @returns {string}
|
|
@@ -514,6 +662,12 @@ class ____AnaLogger
|
|
|
514
662
|
|
|
515
663
|
originalFormatFunction;
|
|
516
664
|
|
|
665
|
+
static lidTable = {};
|
|
666
|
+
static lidTableOn = false;
|
|
667
|
+
|
|
668
|
+
forceLidOn = false;
|
|
669
|
+
resolveLineCall = false;
|
|
670
|
+
resolveErrorLineCall = false;
|
|
517
671
|
|
|
518
672
|
constructor({name = "default"} = {})
|
|
519
673
|
{
|
|
@@ -567,6 +721,79 @@ class ____AnaLogger
|
|
|
567
721
|
return this.instanceId;
|
|
568
722
|
}
|
|
569
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
|
+
|
|
570
797
|
keepLogHistory()
|
|
571
798
|
{
|
|
572
799
|
this.keepLog = true;
|
|
@@ -2006,18 +2233,74 @@ class ____AnaLogger
|
|
|
2006
2233
|
}
|
|
2007
2234
|
}
|
|
2008
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
|
+
|
|
2009
2253
|
/**
|
|
2010
2254
|
* Display log following template
|
|
2011
2255
|
* @param context
|
|
2256
|
+
* @param argsWithoutContext
|
|
2012
2257
|
*/
|
|
2013
|
-
processOutput(context = {})
|
|
2258
|
+
processOutput(context = {}, ...argsWithoutContext)
|
|
2014
2259
|
{
|
|
2015
2260
|
try
|
|
2016
2261
|
{
|
|
2017
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
|
+
}
|
|
2018
2301
|
this.applySymbolByName(context);
|
|
2019
2302
|
|
|
2020
|
-
this.checkOnLogging(context, context,
|
|
2303
|
+
this.checkOnLogging(context, context, argsWithoutContext, "onContext");
|
|
2021
2304
|
if (!this.isTargetAllowed(context.target))
|
|
2022
2305
|
{
|
|
2023
2306
|
return;
|
|
@@ -2033,12 +2316,12 @@ class ____AnaLogger
|
|
|
2033
2316
|
return;
|
|
2034
2317
|
}
|
|
2035
2318
|
|
|
2036
|
-
|
|
2037
|
-
const newMessages = this.checkOnLogging(context, arguments && arguments.length > 1? arguments[1] : arguments, arguments,"onMessage");
|
|
2319
|
+
const newMessages = this.checkOnLogging(context, argsWithoutContext[0], arguments,"onMessage");
|
|
2038
2320
|
if (newMessages !== undefined) {
|
|
2039
2321
|
arguments[1] = newMessages;
|
|
2040
2322
|
}
|
|
2041
|
-
|
|
2323
|
+
|
|
2324
|
+
let args = argsWithoutContext;
|
|
2042
2325
|
|
|
2043
2326
|
message = this.convertArgumentsToText(args);
|
|
2044
2327
|
|
|
@@ -2145,6 +2428,12 @@ class ____AnaLogger
|
|
|
2145
2428
|
options.hasOwnProperty("lid");
|
|
2146
2429
|
}
|
|
2147
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
|
+
*/
|
|
2148
2437
|
stringToObject(str) {
|
|
2149
2438
|
try {
|
|
2150
2439
|
str = str.trim();
|
|
@@ -2209,39 +2498,39 @@ class ____AnaLogger
|
|
|
2209
2498
|
/**
|
|
2210
2499
|
* Convert a string into a Context object if possible
|
|
2211
2500
|
* TODO: To implement in next version
|
|
2212
|
-
* @param str
|
|
2213
2501
|
* @returns {string}
|
|
2502
|
+
* @param input
|
|
2214
2503
|
*/
|
|
2215
|
-
extractContextFromInput(
|
|
2504
|
+
extractContextFromInput(input)
|
|
2216
2505
|
{
|
|
2217
|
-
if (typeof
|
|
2506
|
+
if (typeof input === "string" || input instanceof String)
|
|
2218
2507
|
{
|
|
2219
|
-
if (
|
|
2508
|
+
if (input.toLowerCase().indexOf("lid:") !== 0)
|
|
2220
2509
|
{
|
|
2221
|
-
return
|
|
2510
|
+
return input;
|
|
2222
2511
|
}
|
|
2223
2512
|
|
|
2224
|
-
const obj = this.stringToObject(
|
|
2513
|
+
const obj = this.stringToObject(input);
|
|
2225
2514
|
if (obj) {
|
|
2226
|
-
|
|
2515
|
+
input = obj;
|
|
2227
2516
|
}
|
|
2228
2517
|
}
|
|
2229
2518
|
|
|
2230
|
-
if (typeof
|
|
2231
|
-
if (this.isExtendedOptionsPassed(
|
|
2232
|
-
if (
|
|
2233
|
-
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];
|
|
2234
2523
|
if (obj) {
|
|
2235
|
-
|
|
2524
|
+
input = Object.assign({}, obj, input);
|
|
2236
2525
|
}
|
|
2237
2526
|
}
|
|
2238
|
-
if (!
|
|
2239
|
-
|
|
2527
|
+
if (!input.target) {
|
|
2528
|
+
input.target = this.getActiveTarget();
|
|
2240
2529
|
}
|
|
2241
2530
|
}
|
|
2242
2531
|
}
|
|
2243
2532
|
|
|
2244
|
-
return
|
|
2533
|
+
return input;
|
|
2245
2534
|
}
|
|
2246
2535
|
|
|
2247
2536
|
listSymbols()
|
|
@@ -2303,13 +2592,25 @@ class ____AnaLogger
|
|
|
2303
2592
|
log(options, ...args)
|
|
2304
2593
|
{
|
|
2305
2594
|
options = this.extractContextFromInput(options);
|
|
2595
|
+
|
|
2306
2596
|
// If the first parameter is not of context format,
|
|
2307
2597
|
// We use the default context
|
|
2308
2598
|
if (!this.isExtendedOptionsPassed(options))
|
|
2309
2599
|
{
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
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};
|
|
2313
2614
|
}
|
|
2314
2615
|
|
|
2315
2616
|
const someContext = this.generateDefaultContext();
|
|
@@ -2321,6 +2622,14 @@ class ____AnaLogger
|
|
|
2321
2622
|
return;
|
|
2322
2623
|
}
|
|
2323
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
|
+
}
|
|
2324
2633
|
this.processOutput.apply(this, [context, ...args]);
|
|
2325
2634
|
}
|
|
2326
2635
|
|
|
@@ -2337,16 +2646,25 @@ class ____AnaLogger
|
|
|
2337
2646
|
// We use the error context and display
|
|
2338
2647
|
if (!this.isExtendedOptionsPassed(options))
|
|
2339
2648
|
{
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
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};
|
|
2343
2658
|
}
|
|
2344
2659
|
|
|
2345
2660
|
const errorContext = this.generateErrorContext();
|
|
2346
2661
|
let context = this.convertToContext(options, errorContext);
|
|
2347
2662
|
|
|
2348
|
-
|
|
2349
|
-
|
|
2663
|
+
if (this.resolveErrorLineCall)
|
|
2664
|
+
{
|
|
2665
|
+
context.stack = getInvocationLine();
|
|
2666
|
+
}
|
|
2667
|
+
this.log(context, ...args);
|
|
2350
2668
|
}
|
|
2351
2669
|
|
|
2352
2670
|
overrideError()
|