最近发生了一个特别诡异的问题, 无奈只能一个一个模块去去解读,包管理是好,但遇到一些诡异的问题, 只能一行一行源码去读, 索性是开源的, 如果非开源的。。。边读边写加深印象
作为一个debug工具基本功能应该具备以下几点
- 打印日志(核心功能)
- 显示 区分 不同的日志
- 控制 输出 不同的日志
- 开启关闭 日志
我们带着这些需求去看这个模块的源码,首先我们看下文件结构
- index.js (入口文件)
- debug.js (核心模块)
- node.js (node 格式化输出)
- browser.js (browser 格式化输出)
不管做什么都是从开头开始的, 首先看 index.js
if (typeof process !== 'undefined' && process.type === 'renderer') {
module.exports = require('./browser.js');
} else {
module.exports = require('./node.js');
}
这段代码很容易看出根据环境来判断应该使用哪种类型的debug功能
我对 browser 不是很了解, 就不去管这个了,直接看node.js
exports = module.exports = require('./debug');
exports.log = log;
exports.formatArgs = formatArgs;
很容易看出来 核心模块是debug, node.js是在该模块上添加或者修改了某一些功能
接着我看下重头戏 debug.js
exports = module.exports = debug.debug = debug;
function debug(namespace) {
// define the `disabled` version
function disabled() {
}
disabled.enabled = false;
// define the `enabled` version
function enabled() {
var self = enabled;
.... 省略部分初始化代码
var args = new Array(arguments.length);
.... 省略 对于参数部分处理的代码
// 参数格式化
args = exports.formatArgs.apply(self, args);
// 兼容打印日志
var logFn = enabled.log || exports.log || console.log.bind(console);
logFn.apply(self, args);
}
enabled.enabled = true;
var fn = exports.enabled(namespace) ? enabled : disabled;
fn.namespace = namespace;
// 返回对应处理函数
return fn;
}
// 使用 require加载debug模块, debug 作为函数并调用 debug('socket.io:client') 赋值给debug
var debug = require('debug')('socket.io:client');
首先我们看之前的第一个需求, 打印debug信息
var logFn = enabled.log || exports.log || console.log.bind(console);
logFn.apply(self, args);
该段代码说明打印功能的实现
如果需要扩展打印 enabled.log || exports.log 可对这两个方法进行扩展, 并附带优先级
需求4 开启关闭日志
var fn = exports.enabled(namespace) ? enabled : disabled;
该处判断了,对某类 debug 信息 开启还是关闭
由于这个功能我们需要使用, 就深入看一下 exports.enabled 源码
function enabled(name) {
.... 省略n多代码
if (exports.names[i].test(name)) {
return true;
}
return false;
}
function enable(namespaces) {
exports.save(namespaces);
.... 省略n多代码
exports.names.push(new RegExp('^' + namespaces + '$'));
}
那什么时候加入到 exports.names 中的呢? 看 node.js 这段代码
exports.enable(load());
function load() {
return process.env.DEBUG;
}
说明他读取的 是 环境变量 DEBUG 的值, 就是说, 我们对环境变量 debug 赋值 且正则 匹配正确 以后 才会输出信息, 否则不会
注意 debug赋值只是开启,而正确的正则匹配才是真实的输出日志 这里就实现了 需求3
set DEBUG=* & node app.js 的原理就是这样子的
剩下的只有 需求2: 显示 区分 不同的日志
args = exports.formatArgs.apply(self, args);
对打印的参数进行格式化
node.js
function formatArgs() {
....省略代码
var c = this.color;
args[0] = ' \u001b[3' + c + ';1m' + name + ' '
+ '\u001b[0m'
+ args[0];
args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m');
return args;
}
该段代码就是控制 具体的显示的颜色的
好了, 模块分析到此结束。 啰嗦一句, 这个可以稍微改进一下, 对控制层进行再次封装, 实现不重启进行打印日志