diff options
Diffstat (limited to 'shared/metrics-8/node_modules/@amp-metrics/mt-client-logger-core/dist')
| -rw-r--r-- | shared/metrics-8/node_modules/@amp-metrics/mt-client-logger-core/dist/mt-client-logger-core.esm.js | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/shared/metrics-8/node_modules/@amp-metrics/mt-client-logger-core/dist/mt-client-logger-core.esm.js b/shared/metrics-8/node_modules/@amp-metrics/mt-client-logger-core/dist/mt-client-logger-core.esm.js new file mode 100644 index 0000000..2ef3193 --- /dev/null +++ b/shared/metrics-8/node_modules/@amp-metrics/mt-client-logger-core/dist/mt-client-logger-core.esm.js @@ -0,0 +1,533 @@ +import { reflect, string } from '@amp-metrics/mt-metricskit-utils-private'; + +/* + * src/utils.js + * mt-client-logger-core + * + * Copyright © 2016-2017 Apple Inc. All rights reserved. + * + */ + +function FlagSymbol(key) { + this.key = key; +} +FlagSymbol.prototype.toString = function toString() { + return this.key; +}; + +var utils = { + /** + ************************************ PUBLIC METHODS/IVARS ************************************ + */ + + /** Special flag classes that can be passed as arguments to logger methods in order to dictate logging behavior + * Use class instances to guarantee that flag arguments are unique, and use constructor names for O(1) lookup */ + flagArguments: { + /** + * When logging, if any of the arguments is an instance of this class, the log output will include a call stack trace. + * @example usage: logger.warn('danger!', logger.INCLUDE_CALL_STACK); + */ + INCLUDE_CALL_STACK: new FlagSymbol('INCLUDE_CALL_STACK'), + /** + * When logging, if any of the arguments is an instance of this class, the remaining arguments will be mirrored to the logging server + * @example usage: logger.info('some message', logger.MIRROR_TO_SERVER); + */ + MIRROR_TO_SERVER: new FlagSymbol('MIRROR_TO_SERVER'), + /** + * When logging, if any of the arguments is an instance of this class, the client (console) output will be suppressed + * This would typically be used when callers want to log an event to the server without printing it + * @example usage: logger.debug(someDiagnosticsInfoObject, logger.MIRROR_TO_SERVER, logger.SUPPRESS_CLIENT_OUTPUT); + */ + SUPPRESS_CLIENT_OUTPUT: new FlagSymbol('SUPPRESS_CLIENT_OUTPUT') + }, + + /** + * Allows replacement of one or more of this class' functions + * Any method on the passed-in object which matches a method that this class has will be called instead of the built-in class method. + * To replace *all* methods of his class, simply have your delegate implement all the methods of this class + * Your delegate can be a true object instance, an anonymous object, or a class object. + * Your delegate is free to have as many additional non-matching methods as it likes (these methods will not be copied to the target object). + * It can even act as a delegate for multiple MetricsKit objects, though that is not recommended. + * + * "setDelegate()" may be called repeatedly, with the functions in the most-recently set delegates replacing any functions matching those in the earlier delegates, as well as any as-yet unreplaced functions. + * This allows callers to replace some number of methods that need custom implementations. + * If, for example, a client wants to use the standard logger implementation with the exception of, say, the "debug" method, they can + * call "setDelegate()" with their own delegate containing only a single method of "debug" as the delegate, which would leave all the other methods intact. + * + * NOTE: The delegate function will have a property called origFunction representing the original function that it replaced. + * This allows the delegate to, essentially, call "super" before or after it does some work. + * If a replaced method is overridden again with a subsequent "setDelegate()" call, the "origFunction" property will be the previous delegate's function. + * @example: + * To override one or more methods, in place: + * logger.setDelegate({ debug: console.debug }); + * To override one or more methods with a separate object: + * logger.setDelegate(customLoggerDelegate); + * (where "customLoggerDelegate" might be defined elsewhere as, e.g.: + * var customLoggerDelegate = { debug: function(msg) { document.getElementById('debugMsg').innerHTML = msg; }, + * serverUrl: function() { return 'https://custom-log-server.apple.com'; } }; + * To override one or more methods with an instantiated object from a class definition: + * eventRecorder.setDelegate(new CustomLoggerDelegate()); + * (where "CustomLoggerDelegate" might be defined elsewhere as, e.g.: + * function CustomLoggerDelegate() { + * } + * CustomLoggerDelegate.prototype.debug = function debug(msg) { + * document.getElementById('debugMsg').innerHTML = msg; + * }; + * CustomLoggerDelegate.prototype.serverUrl = function serverUrl() { + * return 'https://custom-log-server.apple.com'; + * }; + * To override one or more methods with a class object (with "static" methods): + * eventRecorder.setDelegate(CustomLoggerDelegate); + * (where "CustomLoggerDelegate" might be defined elsewhere as, e.g.: + * function CustomLoggerDelegate() { + * } + * CustomLoggerDelegate.debug = function debug(msg) { + * document.getElementById('debugMsg').innerHTML = msg; + * }; + * CustomLoggerDelegate.serverUrl = function serverUrl() { + * return 'https://custom-log-server.apple.com'; + * }; + * @param {Object} delegate Object or Class with delegate method(s) to be called instead of default (built-in) methods. + * @returns {Boolean} true if one or more methods on the delegate object match one or more methods on the default object, + * otherwise returns false. + */ + setDelegate: function setDelegate(delegate) { + return reflect.attachDelegate(this, delegate); + }, + + /** + * If the log level allows, logs/throws an error to the console and mirrors the log event to the server + * @param {Logger} logger + * @param {String} methodName + * @param {Array-like Object} origArguments + */ + execute: function execute(logger, methodName, origArguments) { + var methodLevel = logger.levelStringToIntMap[methodName]; + + if (logger.level() !== logger.NONE && logger.level() <= methodLevel) { + var argumentsArray = Array.prototype.slice.call(origArguments); + var logArguments = utils.nonFlagLogArguments(argumentsArray); + var logOptions = utils.logOptions(logger, methodLevel, argumentsArray); + var callstack = logOptions.includeCallStack ? new Error().stack : null; + var enrichedLogArguments = callstack ? logArguments.concat('\n' + callstack) : logArguments; // add newline for nicer output + + // so testing harness can verify logging done within tested functions: + logger[methodName]._lastLog = enrichedLogArguments; + + if (logOptions.mirrorToServer) { + utils.sendToServer(logger, methodName, logArguments, callstack); + } + + if (logOptions.throwInsteadOfPrint) { + throw new Error(logArguments.toString()); + } else if (!logOptions.suppressClientOutput) { + if (console[methodName]) { + console[methodName].apply(console, enrichedLogArguments); + } else { + // fallback to console.log - node does not have console.debug + console.log.apply(console, enrichedLogArguments); + } + } + } + }, + + /** + * Indicates whether an item is a specific flag object that dictates logging behavior + * @param {*} argument + * @return {Boolean} + */ + isFlagObject: function isFlagObject(argument) { + return argument && argument === utils.flagArguments[argument.toString()]; + }, + + /** + * Creates a new array without specific arguments that dictate logging behavior (and are not intended to be logged) + * @param {Array} argumentsArray + * @return {Array} + */ + nonFlagLogArguments: function nonFlagLogArguments(argumentsArray) { + return argumentsArray.filter(function (argument) { + return !utils.isFlagObject(argument); + }); + }, + + /** + * Inspects an array of arguments for specific flag objects that dictate log behavior and returns an object representing the intended behavior + * By checking for all of the various flags in one pass, we avoid looping over the arguments array more than necessary + * @param {Logger} logger + * @param {Int} methodLevel + * @param {Array} argumentsArray + * @return {Object} + */ + logOptions: function logOptions(logger, methodLevel, argumentsArray) { + var logOptions = {}; + var optionName; + + argumentsArray.forEach(function (argument) { + if (utils.isFlagObject(argument)) { + optionName = string.snakeCaseToCamelCase(argument.toString()); + logOptions[optionName] = true; + } + }); + + if ( + reflect.isFunction(logger.mirrorToServerLevel) && + logger.mirrorToServerLevel() !== logger.NONE && + logger.mirrorToServerLevel() <= methodLevel + ) { + logOptions.mirrorToServer = true; + } + if (logger.throwLevel() !== logger.NONE && logger.throwLevel() <= methodLevel) { + logOptions.throwInsteadOfPrint = true; + } + + return logOptions; + }, + + /** + * Sends a log event to the server immediately without checking resolution + * TODO: refactor to use eventRecorder once it is a standalone package + * NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED + * @param {Logger} logger + * @param {String} level + * @param {Array} logArguments + * @param {String} (optional) callstack + * @return {String} the JSON-stringified event that was sent to the server + * @overridable + */ + sendToServer: function sendToServer(logger, level, logArguments, callstack) {} +}; + +/* + * src/logger.js + * mt-client-logger-core + * + * Copyright © 2016-2017 Apple Inc. All rights reserved. + * + */ + +/** + ************************************ PRIVATE METHODS/IVARS ************************************ + */ + +// Define log levels separately to expose this constant. +// TODO clean constants up when consolidate. +var LOG_LEVELS = { + NONE: 0, + DEBUG: 1, + INFO: 2, + WARN: 3, + ERROR: 4 +}; +var LOGGER_LEVELS = { + MIN_LEVEL: LOG_LEVELS.NONE, + MAX_LEVEL: LOG_LEVELS.ERROR, + levelIntToStringMap: { + 0: 'none', + 1: 'debug', + 2: 'info', + 3: 'warn', + 4: 'error' + }, + levelStringToIntMap: { + none: 0, + debug: 1, + info: 2, + warn: 3, + error: 4 + } +}; + +reflect.extend(LOGGER_LEVELS, LOG_LEVELS); + +/** Global properties */ +var LOGGER_PROPERTIES = { + loggerName: 'defaultLogger', + level: LOGGER_LEVELS.INFO, + throwLevel: LOGGER_LEVELS.NONE +}; + +var _initialized = false; + +/** A map of logger names to Logger instances */ +var _loggers = {}; + +/** + * Provides basic "log4j" type functionality. + * The functionality in this class is typically replaced via a delegate. + * NOTE: This class has a "secret" field extending each logger function called "_lastLog" which allows us to inspect logged errors from within our test cases of various functionality + * to ensure that the correct errors are thrown. + * DEFAULT implementation: console logging + * DEFAULT logger level: INFO + * @see setDelegate + * @delegatable + * @constructor + * @param {String} loggerName + */ +function Logger(loggerName) { + // @private + this._loggerName = loggerName; + + /* These variables are enumerated here for clarity */ + // @private + this._level; + // @private + this._throwLevel; + + // lazily add prototype properties + if (!_initialized) { + _initialized = true; + reflect.extend(Logger.prototype, LOGGER_LEVELS); + reflect.extend(Logger.prototype, utils.flagArguments); + } +} + +/** + * Returns the logger instance that has the name <loggerName>, creating a new one if it doesn't exist + * @param {String} loggerName + * @return {Logger} + */ +function loggerNamed(loggerName) { + loggerName = loggerName || LOGGER_PROPERTIES.loggerName; + var returnLogger = _loggers[loggerName]; + + if (!returnLogger) { + returnLogger = new Logger(loggerName); + _loggers[loggerName] = returnLogger; + } + + return returnLogger; +} + +/** + * Remove a logger from the cache + * @param loggerName + */ +function removeLogger(loggerName) { + if (_loggers) { + delete _loggers[loggerName]; + } +} + +function resetLoggerCache() { + _loggers = {}; +} + +/** Default class property setters and getters */ +Logger.level = function level() { + return LOGGER_PROPERTIES.level; +}; +Logger.throwLevel = function throwLevel() { + return LOGGER_PROPERTIES.throwLevel; +}; + +// TODO: new PR with this, flesh out and make app-wide with docs +// Logger.setDelegate = function setDelegate() { }; +// Logger.logCallback = function logCallback() { }; + +/** + ************************************ PUBLIC METHODS/IVARS ************************************ + */ + +/** + * Allows replacement of one or more of this class instance's functions + * Any method on the passed-in object which matches a method that this class has will be called instead of the built-in class method. + * To replace *all* methods of his class, simply have your delegate implement all the methods of this class + * Your delegate can be a true object instance, an anonymous object, or a class object. + * Your delegate is free to have as many additional non-matching methods as it likes (these methods will not be copied to the target object). + * It can even act as a delegate for multiple MetricsKit objects, though that is not recommended. + * + * "setDelegate()" may be called repeatedly, with the functions in the most-recently set delegates replacing any functions matching those in the earlier delegates, as well as any as-yet unreplaced functions. + * This allows callers to replace some number of methods that need custom implementations. + * If, for example, a client wants to use the standard logger implementation with the exception of, say, the "debug" method, they can + * call "setDelegate()" with their own delegate containing only a single method of "debug" as the delegate, which would leave all the other methods intact. + * + * NOTE: The delegate function will have a property called origFunction representing the original function that it replaced. + * This allows the delegate to, essentially, call "super" before or after it does some work. + * If a replaced method is overridden again with a subsequent "setDelegate()" call, the "origFunction" property will be the previous delegate's function. + * @example: + * To override one or more methods, in place: + * logger.setDelegate({ debug: console.debug }); + * To override one or more methods with a separate object: + * logger.setDelegate(customLoggerDelegate); + * (where "customLoggerDelegate" might be defined elsewhere as, e.g.: + * var customLoggerDelegate = { debug: function(msg) { document.getElementById('debugMsg').innerHTML = msg; }, + * serverUrl: function() { return 'https://custom-log-server.apple.com'; } }; + * To override one or more methods with an instantiated object from a class definition: + * eventRecorder.setDelegate(new CustomLoggerDelegate()); + * (where "CustomLoggerDelegate" might be defined elsewhere as, e.g.: + * function CustomLoggerDelegate() { + * } + * CustomLoggerDelegate.prototype.debug = function debug(msg) { + * document.getElementById('debugMsg').innerHTML = msg; + * }; + * CustomLoggerDelegate.prototype.serverUrl = function serverUrl() { + * return 'https://custom-log-server.apple.com'; + * }; + * To override one or more methods with a class object (with "static" methods): + * eventRecorder.setDelegate(CustomLoggerDelegate); + * (where "CustomLoggerDelegate" might be defined elsewhere as, e.g.: + * function CustomLoggerDelegate() { + * } + * CustomLoggerDelegate.debug = function debug(msg) { + * document.getElementById('debugMsg').innerHTML = msg; + * }; + * CustomLoggerDelegate.serverUrl = function serverUrl() { + * return 'https://custom-log-server.apple.com'; + * }; + * @param {Object} delegate Object or Class with delegate method(s) to be called instead of default (built-in) methods. + * @returns {Boolean} true if one or more methods on the delegate object match one or more methods on the default object, + * otherwise returns false. + */ +Logger.prototype.setDelegate = function setDelegate(delegate) { + return reflect.attachDelegate(this, delegate); +}; + +/** + * The name of this logger + * @returns {String} + * @overridable + */ +Logger.prototype.loggerName = function loggerName() { + return this._loggerName; +}; + +/** + * Deduces the integer level from either a string or integer + * @param {*} level loglevel which may be either a string (e.g. 'debug', 'DEBUG', 'Debug', etc.) or an integer (e.g. 1, 2, 3 or logger.DEBUG, logger.INFO, logger.WARN, etc. + * @return {Int} the level as an integer or null if an invalid level argument was passed + * @overrideable + */ +Logger.prototype.levelParameterAsInt = function levelParameterAsInt(level) { + var returnLevel = null; + var integerLevel; + + if (reflect.isString(level)) { + integerLevel = this.levelStringToIntMap[level.toLowerCase()]; + } else if (reflect.isNumber(level)) { + integerLevel = level; + } + + if (integerLevel >= this.MIN_LEVEL && integerLevel <= this.MAX_LEVEL) { + returnLevel = integerLevel; + } + + return returnLevel; +}; + +/** + * Sets the level at which we will log at or above + * @param {*} level loglevel which may be either a string (e.g. 'debug', 'DEBUG', 'Debug', etc.) or an integer (e.g. 1, 2, 3 or logger.DEBUG, logger.INFO, logger.WARN, etc. + * @overridable + */ +Logger.prototype.setLevel = function setLevel(level) { + var integerLevel = this.levelParameterAsInt(level); + if (integerLevel !== null) { + this._level = integerLevel; + } +}; + +/** + * NOTE: This setting should be honored by all delegates. + * This setting will cause any emitted log message at or above the specified level to throw an exception with the log message instead of logging to the console. + * This is useful during testcase execution when we would expect to have no log output, or perhaps only "info" log output, etc. + * @param {*} throwLevel loglevel which may be either a string (e.g. 'debug', 'DEBUG', 'Debug', etc.) or an integer (e.g. 1, 2, 3 or logger.DEBUG, logger.INFO, logger.WARN, etc. + */ +Logger.prototype.setThrowLevel = function setThrowLevel(throwLevel) { + var integerLevel = this.levelParameterAsInt(throwLevel); + if (integerLevel !== null) { + this._throwLevel = integerLevel; + } +}; + +/** + * Returns the current logger level as an integer + * @overridable + */ +Logger.prototype.level = function level() { + var level = this._level; + return reflect.isNumber(level) ? level : Logger.level(); +}; + +/** + * Returns the current logger level as a string + * @overridable + */ +Logger.prototype.levelString = function levelString() { + return this.levelIntToStringMap[this.level()]; +}; + +/** + * Returns the current logger throw level as an integer + * @overridable + */ +Logger.prototype.throwLevel = function throwLevel() { + var throwLevel = this._throwLevel; + return reflect.isNumber(throwLevel) ? throwLevel : Logger.throwLevel(); +}; + +/** + * Emits the log message if log level is set to "debug". + * DEFAULT implementation: console.debug() + * @param {Object} a list of objects (perhaps a single string) to be stringified and emitted as the log message + * @api public + * @overridable + */ +Logger.prototype.debug = function debug() { + utils.execute(this, 'debug', arguments); +}; + +/** + * Emits the log message if log level is set to "info". + * DEFAULT implementation: console.info() + * @param {Object} a list of objects (perhaps a single string) to be stringified and emitted as the log message + * @api public + * @overridable + */ +Logger.prototype.info = function info() { + utils.execute(this, 'info', arguments); +}; + +/** + * Emits the log message if log level is set to "warn". + * DEFAULT implementation: console.warn() + * @param {Object} a list of objects (perhaps a single string) to be stringified and emitted as the log message + * @api public + * @overridable + */ +Logger.prototype.warn = function warn() { + utils.execute(this, 'warn', arguments); +}; + +/** + * Emits the log message if log level is set to "error". + * DEFAULT implementation: console.error() + * @param {Object} a list of objects (perhaps a single string) to be stringified and emitted as the log message + * @api public + * @overridable + */ +Logger.prototype.error = function error() { + utils.execute(this, 'error', arguments); +}; + +/** + * @param {String} levelString + * @return {String} the most recent log event for this level + */ +Logger.prototype.lastLog = function lastLog(levelString) { + return this[levelString] ? this[levelString]._lastLog : null; +}; + +var level = Logger.level; +var throwLevel = Logger.throwLevel; + +/* + * mt-client-logger-core/index.js + * mt-client-logger-core + * + * Copyright © 2016-2017 Apple Inc. All rights reserved. + * + */ + +export default Logger; +export { LOG_LEVELS, level, loggerNamed, removeLogger, resetLoggerCache, throwLevel, utils }; |
