summaryrefslogtreecommitdiff
path: root/javascript/videojs/src/js/utils/create-logger.js
diff options
context:
space:
mode:
Diffstat (limited to 'javascript/videojs/src/js/utils/create-logger.js')
-rw-r--r--javascript/videojs/src/js/utils/create-logger.js287
1 files changed, 287 insertions, 0 deletions
diff --git a/javascript/videojs/src/js/utils/create-logger.js b/javascript/videojs/src/js/utils/create-logger.js
new file mode 100644
index 0000000..08a8c74
--- /dev/null
+++ b/javascript/videojs/src/js/utils/create-logger.js
@@ -0,0 +1,287 @@
+/**
+ * @file create-logger.js
+ * @module create-logger
+ */
+import window from 'global/window';
+
+// This is the private tracking variable for the logging history.
+let history = [];
+
+/**
+ * Log messages to the console and history based on the type of message
+ *
+ * @private
+ * @param {string} name
+ * The name of the console method to use.
+ *
+ * @param {Object} log
+ * The arguments to be passed to the matching console method.
+ *
+ * @param {string} [styles]
+ * styles for name
+ */
+const LogByTypeFactory = (name, log, styles) => (type, level, args) => {
+ const lvl = log.levels[level];
+ const lvlRegExp = new RegExp(`^(${lvl})$`);
+
+ let resultName = name;
+
+ if (type !== 'log') {
+
+ // Add the type to the front of the message when it's not "log".
+ args.unshift(type.toUpperCase() + ':');
+ }
+
+ if (styles) {
+ resultName = `%c${name}`;
+ args.unshift(styles);
+ }
+
+ // Add console prefix after adding to history.
+ args.unshift(resultName + ':');
+
+ // Add a clone of the args at this point to history.
+ if (history) {
+ history.push([].concat(args));
+
+ // only store 1000 history entries
+ const splice = history.length - 1000;
+
+ history.splice(0, splice > 0 ? splice : 0);
+ }
+
+ // If there's no console then don't try to output messages, but they will
+ // still be stored in history.
+ if (!window.console) {
+ return;
+ }
+
+ // Was setting these once outside of this function, but containing them
+ // in the function makes it easier to test cases where console doesn't exist
+ // when the module is executed.
+ let fn = window.console[type];
+
+ if (!fn && type === 'debug') {
+ // Certain browsers don't have support for console.debug. For those, we
+ // should default to the closest comparable log.
+ fn = window.console.info || window.console.log;
+ }
+
+ // Bail out if there's no console or if this type is not allowed by the
+ // current logging level.
+ if (!fn || !lvl || !lvlRegExp.test(type)) {
+ return;
+ }
+
+ fn[Array.isArray(args) ? 'apply' : 'call'](window.console, args);
+};
+
+export default function createLogger(name, delimiter = ':', styles = '') {
+ // This is the private tracking variable for logging level.
+ let level = 'info';
+
+ // the curried logByType bound to the specific log and history
+ let logByType;
+
+ /**
+ * Logs plain debug messages. Similar to `console.log`.
+ *
+ * Due to [limitations](https://github.com/jsdoc3/jsdoc/issues/955#issuecomment-313829149)
+ * of our JSDoc template, we cannot properly document this as both a function
+ * and a namespace, so its function signature is documented here.
+ *
+ * #### Arguments
+ * ##### *args
+ * *[]
+ *
+ * Any combination of values that could be passed to `console.log()`.
+ *
+ * #### Return Value
+ *
+ * `undefined`
+ *
+ * @namespace
+ * @param {...*} args
+ * One or more messages or objects that should be logged.
+ */
+ function log(...args) {
+ logByType('log', level, args);
+ }
+
+ // This is the logByType helper that the logging methods below use
+ logByType = LogByTypeFactory(name, log, styles);
+
+ /**
+ * Create a new subLogger which chains the old name to the new name.
+ *
+ * For example, doing `mylogger = videojs.log.createLogger('player')` and then using that logger will log the following:
+ * ```js
+ * mylogger('foo');
+ * // > VIDEOJS: player: foo
+ * ```
+ *
+ * @param {string} subName
+ * The name to add call the new logger
+ * @param {string} [subDelimiter]
+ * Optional delimiter
+ * @param {string} [subStyles]
+ * Optional styles
+ * @return {Object}
+ */
+ log.createLogger = (subName, subDelimiter, subStyles) => {
+ const resultDelimiter = subDelimiter !== undefined ? subDelimiter : delimiter;
+ const resultStyles = subStyles !== undefined ? subStyles : styles;
+ const resultName = `${name} ${resultDelimiter} ${subName}`;
+
+ return createLogger(resultName, resultDelimiter, resultStyles);
+ };
+
+ /**
+ * Create a new logger.
+ *
+ * @param {string} newName
+ * The name for the new logger
+ * @param {string} [newDelimiter]
+ * Optional delimiter
+ * @param {string} [newStyles]
+ * Optional styles
+ * @return {Object}
+ */
+ log.createNewLogger = (newName, newDelimiter, newStyles) => {
+ return createLogger(newName, newDelimiter, newStyles);
+ };
+
+ /**
+ * Enumeration of available logging levels, where the keys are the level names
+ * and the values are `|`-separated strings containing logging methods allowed
+ * in that logging level. These strings are used to create a regular expression
+ * matching the function name being called.
+ *
+ * Levels provided by Video.js are:
+ *
+ * - `off`: Matches no calls. Any value that can be cast to `false` will have
+ * this effect. The most restrictive.
+ * - `all`: Matches only Video.js-provided functions (`debug`, `log`,
+ * `log.warn`, and `log.error`).
+ * - `debug`: Matches `log.debug`, `log`, `log.warn`, and `log.error` calls.
+ * - `info` (default): Matches `log`, `log.warn`, and `log.error` calls.
+ * - `warn`: Matches `log.warn` and `log.error` calls.
+ * - `error`: Matches only `log.error` calls.
+ *
+ * @type {Object}
+ */
+ log.levels = {
+ all: 'debug|log|warn|error',
+ off: '',
+ debug: 'debug|log|warn|error',
+ info: 'log|warn|error',
+ warn: 'warn|error',
+ error: 'error',
+ DEFAULT: level
+ };
+
+ /**
+ * Get or set the current logging level.
+ *
+ * If a string matching a key from {@link module:log.levels} is provided, acts
+ * as a setter.
+ *
+ * @param {'all'|'debug'|'info'|'warn'|'error'|'off'} [lvl]
+ * Pass a valid level to set a new logging level.
+ *
+ * @return {string}
+ * The current logging level.
+ */
+ log.level = (lvl) => {
+ if (typeof lvl === 'string') {
+ if (!log.levels.hasOwnProperty(lvl)) {
+ throw new Error(`"${lvl}" in not a valid log level`);
+ }
+ level = lvl;
+ }
+ return level;
+ };
+
+ /**
+ * Returns an array containing everything that has been logged to the history.
+ *
+ * This array is a shallow clone of the internal history record. However, its
+ * contents are _not_ cloned; so, mutating objects inside this array will
+ * mutate them in history.
+ *
+ * @return {Array}
+ */
+ log.history = () => history ? [].concat(history) : [];
+
+ /**
+ * Allows you to filter the history by the given logger name
+ *
+ * @param {string} fname
+ * The name to filter by
+ *
+ * @return {Array}
+ * The filtered list to return
+ */
+ log.history.filter = (fname) => {
+ return (history || []).filter((historyItem) => {
+ // if the first item in each historyItem includes `fname`, then it's a match
+ return new RegExp(`.*${fname}.*`).test(historyItem[0]);
+ });
+ };
+
+ /**
+ * Clears the internal history tracking, but does not prevent further history
+ * tracking.
+ */
+ log.history.clear = () => {
+ if (history) {
+ history.length = 0;
+ }
+ };
+
+ /**
+ * Disable history tracking if it is currently enabled.
+ */
+ log.history.disable = () => {
+ if (history !== null) {
+ history.length = 0;
+ history = null;
+ }
+ };
+
+ /**
+ * Enable history tracking if it is currently disabled.
+ */
+ log.history.enable = () => {
+ if (history === null) {
+ history = [];
+ }
+ };
+
+ /**
+ * Logs error messages. Similar to `console.error`.
+ *
+ * @param {...*} args
+ * One or more messages or objects that should be logged as an error
+ */
+ log.error = (...args) => logByType('error', level, args);
+
+ /**
+ * Logs warning messages. Similar to `console.warn`.
+ *
+ * @param {...*} args
+ * One or more messages or objects that should be logged as a warning.
+ */
+ log.warn = (...args) => logByType('warn', level, args);
+
+ /**
+ * Logs debug messages. Similar to `console.debug`, but may also act as a comparable
+ * log if `console.debug` is not available
+ *
+ * @param {...*} args
+ * One or more messages or objects that should be logged as debug.
+ */
+ log.debug = (...args) => logByType('debug', level, args);
+
+ return log;
+}