Skip to content

Commit 844e4f0

Browse files
misteroneillgkatsev
authored andcommitted
feat: Log Levels (#3853)
Add a log levels and history api: `videojs.log.level()` and `videojs.log.history()`. `.level()` will return the current level and you can also set it to be one of: `all`, `error`, `off`, or `warn`. `.history()` will return a list of all things logged since videojs loaded. It can be disabled via `videojs.log.history.disable()` (and re-enabled with `enable()`) as well as cleared with `videojs.log.history.clear()`.
1 parent b07143d commit 844e4f0

File tree

4 files changed

+312
-19
lines changed

4 files changed

+312
-19
lines changed

docs/faq.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* [Q: How can I autoplay a video on a mobile device?](#q-how-can-i-autoplay-a-video-on-a-mobile-device)
2020
* [Q: How can I play RTMP video in video.js?](#q-how-can-i-play-rtmp-video-in-videojs)
2121
* [Q: How can I hide the links to my video/subtitles/audio/tracks?](#q-how-can-i-hide-the-links-to-my-videosubtitlesaudiotracks)
22+
* [Q: Can I turn off video.js logging?](#q-can-i-turn-off-videojs-logging)
2223
* [Q: What is a plugin?](#q-what-is-a-plugin)
2324
* [Q: How do I make a plugin for video.js?](#q-how-do-i-make-a-plugin-for-videojs)
2425
* [Q: Where can I find a list of video.js plugins?](#q-where-can-i-find-a-list-of-videojs-plugins)
@@ -169,6 +170,16 @@ help but are outside of the scope of video.js.
169170

170171
For content that must be highly secure [videojs-contrib-eme][eme] adds DRM support.
171172

173+
## Q: Can I turn off video.js logging?
174+
175+
Yes! This can be achieved by adding the following code _after_ including Video.js, but _before_ creating any player(s):
176+
177+
```js
178+
videojs.log.level('off');
179+
```
180+
181+
For more information, including which logging levels are available, check out the [debugging guide][debug-guide].
182+
172183
## Q: What is a plugin?
173184

174185
A plugin is a group of reusable functionality that can be re-used by others. For instance a plugin could add
@@ -307,3 +318,5 @@ Yes! Please [submit an issue or open a pull request][pr-issue-question] if this
307318
[semver]: http://semver.org/
308319

309320
[starter-example]: http://jsbin.com/axedog/edit?html,output
321+
322+
[debug-guide]: ./guides/debug.md

docs/guides/debugging.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Debugging
2+
3+
## Table of Contents
4+
5+
* [Logging](#logging)
6+
* [API Overview](#api-overview)
7+
* [Log Safely](#log-safely)
8+
* [Log Objects Usefully](#log-objects-usefully)
9+
* [Log Levels](#log-levels)
10+
* [Available Log Levels](#available-log-levels)
11+
* [History](#history)
12+
13+
## Logging
14+
15+
Video.js includes a lightweight wrapper - `videojs.log` - around a subset of [the `console` API][console]. The available methods are `videojs.log`, `videojs.log.warn`, and `videojs.log.error`.
16+
17+
### API Overview
18+
19+
Most of these methods should be fairly self-explanatory, but for complete details, see [the API docs][api].
20+
21+
| Method | Alias Of | Matching Level(s) |
22+
| ------------------------------- | --------------- | ----------------- |
23+
| `videojs.log()` | `console.log` | all |
24+
| `videojs.log.warn()` | `console.warn` | all, warn |
25+
| `videojs.log.error()` | `console.error` | all, warn, error |
26+
| `videojs.log.level()` | n/a | n/a |
27+
| `videojs.log.history()` | n/a | n/a |
28+
| `videojs.log.history.clear()` | n/a | n/a |
29+
| `videojs.log.history.disable()` | n/a | n/a |
30+
| `videojs.log.history.enable()` | n/a | n/a |
31+
32+
For descriptions of these features, please refer to the sections below.
33+
34+
### Log Safely
35+
36+
Unlike the `console`, it's safe to leave `videojs.log` calls in your code. They won't throw errors when the `console` doesn't exist.
37+
38+
### Log Objects Usefully
39+
40+
Similar to the `console`, any number of mixed-type values can be passed to `videojs.log` methods:
41+
42+
```js
43+
videojs.log('this is a string', {butThis: 'is an object'});
44+
```
45+
46+
However, certain browser consoles (namely, IE10 and lower) do not support non-string values. Video.js improves on this situation by passing objects through `JSON.stringify` before logging them in IE10 and below. In other words, instead of the above producing this:
47+
48+
```txt
49+
VIDEOJS: this is a string [object Object]
50+
```
51+
52+
it will produce this:
53+
54+
```txt
55+
VIDEOJS: this is a string {"butThis": "is an object"}
56+
```
57+
58+
### Log Levels
59+
60+
Unlike the `console`, `videojs.log` includes the concept of logging levels. These levels toggle logging methods on or off.
61+
62+
Levels are exposed through the `videojs.log.level` method. This method acts as both a getter and setter for the current logging level. With no arguments, it returns the current logging level:
63+
64+
```js
65+
videojs.log.level(); // "all"
66+
```
67+
68+
By passing a string, the logging level can be changed to one of the available logging levels:
69+
70+
```js
71+
videojs.log.level('error'); // show only error messages and suppress others
72+
videojs.log('foo'); // does nothing
73+
videojs.log.warn('foo'); // does nothing
74+
videojs.log.error('foo'); // logs "foo" as an error
75+
```
76+
77+
### Available Log Levels
78+
79+
* **all** (default): enables all logging methods
80+
* **error**: only show `log.error` messages
81+
* **off**: disable all logging methods
82+
* **warn**: only show `log.warn` _and_ `log.error` messages
83+
84+
### History
85+
86+
> **Note:** In Video.js 5, `videojs.log.history` was an array. As of Video.js 6, it is a function which returns an array. This change was made to provide a richer, safer logging history API.
87+
88+
By default, the `videojs.log` module tracks a history of _everything_ passed to it regardless of logging level:
89+
90+
```js
91+
videojs.log.history(); // an array of everything that's been logged up to now
92+
```
93+
94+
This will work even when logging is set to **off**.
95+
96+
This can be useful, but it can also be a source of memory leaks. For example, logged objects will be retained in history even if references are removed everywhere else!
97+
98+
To avoid this problem, history can be disabled or enabled via method calls (using the `disable` and `enable` methods respectively). Disabling history is as easy as:
99+
100+
```js
101+
videojs.log.history.disable();
102+
```
103+
104+
Finally, the history (if enabled) can be cleared at any time via:
105+
106+
```js
107+
videojs.log.history.clear();
108+
```
109+
110+
[api]: http://docs.videojs.com/docs/api/index.html
111+
112+
[console]: https://developer.mozilla.org/en-US/docs/Web/API/Console

src/js/utils/log.js

Lines changed: 107 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,16 @@ import {isObject} from './obj';
88

99
let log;
1010

11+
// This is the private tracking variable for logging level.
12+
let level = 'all';
13+
14+
// This is the private tracking variable for the logging history.
15+
let history = [];
16+
1117
/**
1218
* Log messages to the console and history based on the type of message
1319
*
20+
* @private
1421
* @param {string} type
1522
* The name of the console method to use.
1623
*
@@ -22,29 +29,34 @@ let log;
2229
* but this is exposed as a parameter to facilitate testing.
2330
*/
2431
export const logByType = (type, args, stringify = !!IE_VERSION && IE_VERSION < 11) => {
32+
const lvl = log.levels[level];
33+
const lvlRegExp = new RegExp(`^(${lvl})$`);
2534

2635
if (type !== 'log') {
2736

28-
// add the type to the front of the message when it's not "log"
37+
// Add the type to the front of the message when it's not "log".
2938
args.unshift(type.toUpperCase() + ':');
3039
}
3140

32-
// add to history
33-
log.history.push(args);
41+
// Add a clone of the args at this point to history.
42+
if (history) {
43+
history.push([].concat(args));
44+
}
3445

35-
// add console prefix after adding to history
46+
// Add console prefix after adding to history.
3647
args.unshift('VIDEOJS:');
3748

3849
// If there's no console then don't try to output messages, but they will
39-
// still be stored in `log.history`.
50+
// still be stored in history.
4051
//
4152
// Was setting these once outside of this function, but containing them
4253
// in the function makes it easier to test cases where console doesn't exist
4354
// when the module is executed.
4455
const fn = window.console && window.console[type];
4556

46-
// Bail out if there's no console.
47-
if (!fn) {
57+
// Bail out if there's no console or if this type is not allowed by the
58+
// current logging level.
59+
if (!fn || !lvl || !lvlRegExp.test(type)) {
4860
return;
4961
}
5062

@@ -76,32 +88,112 @@ export const logByType = (type, args, stringify = !!IE_VERSION && IE_VERSION < 1
7688
};
7789

7890
/**
79-
* Log plain debug messages
91+
* Logs plain debug messages. Similar to `console.log`.
8092
*
81-
* @param {Mixed[]} args
82-
* One or more messages or objects that should be logged.
93+
* @class
94+
* @param {Mixed[]} args
95+
* One or more messages or objects that should be logged.
8396
*/
8497
log = function(...args) {
8598
logByType('log', args);
8699
};
87100

88101
/**
89-
* Keep a history of log messages
102+
* Enumeration of available logging levels, where the keys are the level names
103+
* and the values are `|`-separated strings containing logging methods allowed
104+
* in that logging level. These strings are used to create a regular expression
105+
* matching the function name being called.
106+
*
107+
* Levels provided by video.js are:
108+
*
109+
* - `off`: Matches no calls. Any value that can be cast to `false` will have
110+
* this effect. The most restrictive.
111+
* - `all` (default): Matches only Video.js-provided functions (`log`,
112+
* `log.warn`, and `log.error`).
113+
* - `warn`: Matches `log.warn` and `log.error` calls.
114+
* - `error`: Matches only `log.error` calls.
115+
*
116+
* @type {Object}
117+
*/
118+
log.levels = {
119+
all: 'log|warn|error',
120+
error: 'error',
121+
off: '',
122+
warn: 'warn|error',
123+
DEFAULT: level
124+
};
125+
126+
/**
127+
* Get or set the current logging level. If a string matching a key from
128+
* {@link log.levels} is provided, acts as a setter. Regardless of argument,
129+
* returns the current logging level.
130+
*
131+
* @param {string} [lvl]
132+
* Pass to set a new logging level.
133+
*
134+
* @return {string}
135+
* The current logging level.
136+
*/
137+
log.level = (lvl) => {
138+
if (typeof lvl === 'string') {
139+
if (!log.levels.hasOwnProperty(lvl)) {
140+
throw new Error(`"${lvl}" in not a valid log level`);
141+
}
142+
level = lvl;
143+
}
144+
return level;
145+
};
146+
147+
/**
148+
* Returns an array containing everything that has been logged to the history.
149+
*
150+
* This array is a shallow clone of the internal history record. However, its
151+
* contents are _not_ cloned; so, mutating objects inside this array will
152+
* mutate them in history.
90153
*
91-
* @type {Array}
154+
* @return {Array}
155+
*/
156+
log.history = () => history ? [].concat(history) : [];
157+
158+
/**
159+
* Clears the internal history tracking, but does not prevent further history
160+
* tracking.
92161
*/
93-
log.history = [];
162+
log.history.clear = () => {
163+
if (history) {
164+
history.length = 0;
165+
}
166+
};
167+
168+
/**
169+
* Disable history tracking if it is currently enabled.
170+
*/
171+
log.history.disable = () => {
172+
if (history !== null) {
173+
history.length = 0;
174+
history = null;
175+
}
176+
};
177+
178+
/**
179+
* Enable history tracking if it is currently disabled.
180+
*/
181+
log.history.enable = () => {
182+
if (history === null) {
183+
history = [];
184+
}
185+
};
94186

95187
/**
96-
* Log error messages
188+
* Logs error messages. Similar to `console.error`.
97189
*
98190
* @param {Mixed[]} args
99191
* One or more messages or objects that should be logged as an error
100192
*/
101193
log.error = (...args) => logByType('error', args);
102194

103195
/**
104-
* Log warning messages
196+
* Logs warning messages. Similar to `console.warn`.
105197
*
106198
* @param {Mixed[]} args
107199
* One or more messages or objects that should be logged as a warning.

0 commit comments

Comments
 (0)