Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 424x 424x 9x 9x 490x 489x 490x 9x 9x 9x 151x 299x 151x 151x 151x 9x 148x 148x 148x 148x 1x 1x 148x 9x 68x 68x 68x 68x 68x 67x 68x 9x 9x 9x 9x 9x 9x 9x 9x 356x 356x 356x 356x 9x 9x 1439x 1439x 9x 9x 547x 547x 547x 547x 9x 9x 1439x 547x 547x 1006x 1x 1x 1439x 9x 9x 18x 18x 9x 9x 108x 108x 9x 9x 119x 119x 9x 9x 1194x 1194x 9x 9x 9x 9x 9x 349x 349x 349x 9x 9x 1054x 1054x 19x 19x 19x 1054x 1x 1x 1054x 9x | // Logging with levels and redaction (DESIGN 2.7). secretKey, signature, token and audio bytes are
// never logged; appKey is logged as its first 4 characters plus ***.
export const LogLevel = Object.freeze({
OFF: 'OFF',
ERROR: 'ERROR',
WARN: 'WARN',
INFO: 'INFO',
DEBUG: 'DEBUG',
});
const RANK = { OFF: 0, ERROR: 1, WARN: 2, INFO: 3, DEBUG: 4 };
export function isLogLevel(v) {
return typeof v === 'string' && Object.prototype.hasOwnProperty.call(RANK, v);
}
export function maskAppKey(appKey) {
if (!appKey) return '';
return String(appKey).slice(0, 4) + '***';
}
/** Redacts credential query parameters of a URL before it is logged. */
export function redactUrl(url) {
return String(url).replace(/([?&])(signature|token|secretKey|appKey)=([^&#]*)/g, (all, sep, name, value) => {
if (name === 'appKey') return sep + name + '=' + maskAppKey(decodeSafe(value));
return sep + name + '=***';
});
}
function decodeSafe(v) {
try {
return decodeURIComponent(v);
} catch (e) {
return v;
}
}
function consoleSink(level, tag, message, error) {
if (typeof console === 'undefined') return;
const fn = level === 'ERROR' ? console.error : level === 'WARN' ? console.warn : level === 'INFO' ? console.info : console.log;
const line = '[' + tag + '] ' + message;
if (error !== undefined) fn.call(console, line, error);
else fn.call(console, line);
}
export class Logger {
/**
* @param level OFF, ERROR, WARN, INFO or DEBUG
* @param sink function (level, tag, message, error) or undefined for the console
* @param secrets strings that must never appear in a log line (secretKey, token)
*/
constructor(level, sink, secrets) {
this.level = isLogLevel(level) ? level : LogLevel.WARN;
this.sink = typeof sink === 'function' ? sink : consoleSink;
this.secrets = (secrets || []).filter((s) => typeof s === 'string' && s.length >= 4);
}
enabled(level) {
return RANK[level] > 0 && RANK[level] <= RANK[this.level];
}
scrub(text) {
let s = String(text);
for (let i = 0; i < this.secrets.length; i++) s = s.split(this.secrets[i]).join('***');
return s;
}
log(level, tag, message, error) {
if (!this.enabled(level)) return;
try {
this.sink(level, tag, this.scrub(message), error);
} catch (e) {
// A failing sink must never break the SDK.
}
}
error(tag, message, error) {
this.log('ERROR', tag, message, error);
}
warn(tag, message, error) {
this.log('WARN', tag, message, error);
}
info(tag, message, error) {
this.log('INFO', tag, message, error);
}
debug(tag, message, error) {
this.log('DEBUG', tag, message, error);
}
}
/** Calls optional EventListener hooks (DESIGN 2.7), isolating the SDK from exceptions they throw. */
export class EventHub {
constructor(listener, logger) {
this.listener = listener && typeof listener === 'object' ? listener : null;
this.logger = logger;
}
emit(name) {
const l = this.listener;
if (!l || typeof l[name] !== 'function') return;
const args = Array.prototype.slice.call(arguments, 1);
try {
l[name].apply(l, args);
} catch (e) {
if (this.logger) this.logger.error('YuguSDK', 'eventListener.' + name + ' threw', e);
}
}
}
|