-
Notifications
You must be signed in to change notification settings - Fork 7.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: createLogger for easier logging in individual modules #5418
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
492acb2
feat: createLogger for easier logging in individual modules
gkatsev 1003a75
don't expose logByType
gkatsev f7b13fb
curry LogByType factory for name, log, and history
gkatsev c0b4f22
fix linting
gkatsev c92b203
add a logger to player
gkatsev c55c6e4
simpler shared history
gkatsev f6c35dd
shared history with filter
gkatsev 2aa2a23
add sub-logger which chains names
gkatsev 4e057ce
Add some docs
gkatsev b0da459
add docs and fixup history filter
gkatsev 899dbd8
fixup doc
gkatsev 6b64c01
update tests
gkatsev b031776
createLogger
gkatsev bc70f3b
fix linting
gkatsev ec2f9e0
merge master
gkatsev 1e62641
Merge branch 'master' into create-logger
gkatsev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
/** | ||
* @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} type | ||
* The name of the console method to use. | ||
* | ||
* @param {Array} args | ||
* The arguments to be passed to the matching console method. | ||
*/ | ||
const LogByTypeFactory = (name, log) => (type, level, args) => { | ||
const lvl = log.levels[level]; | ||
const lvlRegExp = new RegExp(`^(${lvl})$`); | ||
|
||
if (type !== 'log') { | ||
|
||
// Add the type to the front of the message when it's not "log". | ||
args.unshift(type.toUpperCase() + ':'); | ||
} | ||
|
||
// Add console prefix after adding to history. | ||
args.unshift(name + ':'); | ||
|
||
// Add a clone of the args at this point to history. | ||
if (history) { | ||
history.push([].concat(args)); | ||
} | ||
|
||
// 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) { | ||
// 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 | ||
* Mixed[] | ||
* | ||
* Any combination of values that could be passed to `console.log()`. | ||
* | ||
* #### Return Value | ||
* | ||
* `undefined` | ||
* | ||
* @namespace | ||
* @param {Mixed[]} args | ||
* One or more messages or objects that should be logged. | ||
*/ | ||
const log = function(...args) { | ||
logByType('log', level, args); | ||
}; | ||
|
||
// This is the logByType helper that the logging methods below use | ||
logByType = LogByTypeFactory(name, log); | ||
|
||
/** | ||
* Create a new sublogger which chains the old name to the new name. | ||
* | ||
* For example, doing `videojs.log.createLogger('player')` and then using that logger will log the following: | ||
* ```js | ||
* mylogger('foo'); | ||
* // > VIDEOJS: player: foo | ||
* ``` | ||
* | ||
* @param {string} name | ||
* The name to add call the new logger | ||
* @return {Object} | ||
*/ | ||
log.createLogger = (subname) => createLogger(name + ': ' + subname); | ||
|
||
/** | ||
* 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 {string} [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 {Mixed[]} 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 {Mixed[]} 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 {Mixed[]} args | ||
* One or more messages or objects that should be logged as debug. | ||
*/ | ||
log.debug = (...args) => logByType('debug', level, args); | ||
|
||
return log; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't recall which versions it is, but there are some IEs that don't allow using
apply
/call
onconsole
methods. Probably not the case in IE11, but might be worth checking.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code wasn't changed from what was around previously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, then, it's probably safe. I could be showing my age again. 😄