debug是开发过程的重要一环,趁着国庆放假,正好优化一下debug工具,下面对debug的输出进行自定义,并实现以下功能:
- 同时输出到console和log文件,方便软件打包后的日志记录。
- 显示函数调用链,方便定位问题来源
- 展开显示数组和对象
- 实现日志等级的高亮显示,如:INFO、ERROR等
debug基本用法
debug包是被大量使用的开发基础包,有上千万的下载量,支持定义命名空间,并通过命名空间控制日志的输出,很好的弥补了console.log的不足。
import debug from 'debug' //模块中引入
const log = debug('home') //定义命名空间,后面使用log将自动以home开头
log('name', name) //括号中支持任意多个参数,将输出:home name 小明
详情请看gitlab介绍
自定义输出
通过debug.log方法自定义输出,先上完整代码,再详细说明:
/**
* 重定义debug输出, 可同时输出到终端和文件
*/
debug.log = (...args) => {
//* 输出到console
if (args[0].includes('ERROR')) {
console.error(...args) // 浏览器console error突出显示
} else {
console.log(...args) // 一般信息
}
//* 输出到文件
// 字符过滤--去掉颜色表识符%c
let headInfo = args[0].split('%c').join('') + ' '
// 过滤多余的color参数
args = args.filter(item => {
if (!item || typeof item !== 'string') {
return true // 避免下面空值报错
} else {
return item.substring(0, 6) !== 'color:'
}
})
//空值显示处理
let restInfo = ''
if (args.length > 1) {
restInfo = args
.slice(1)
.map(item => {
if (item === undefined) return 'undefined'
if (item === null) return 'null'
if (item === []) return item
if (item === {}) return item
// eslint-disable-next-line prettier/prettier
if (typeof item === 'string') return ' \'' + item + '\''
if (typeof item === 'object') return JSON.stringify(item, null, 2) //util.inspect(item, true, 3) //数组和对象格式化输出
return item
})
.join(' ')
}
//获取函数调用信息
let fnCallArr = new Error().stack.match(/at (.*?) /g)
//过滤意义不大的数组项
let fnCallInfo = fnCallArr
.slice(2)
.filter(item => {
if (['webpack_require', 'node_modules', 'invokeWithErrorHandling', 'updateComponent'].some(i => item.includes(i))) return false
return true
})
.join('🠐 ')
//过滤用处不大的字符
;[
'at ',
'VueComponent.',
'?vue&type=script&lang=js& ',
'Module../src/',
' 🠐 callHook 🠐 Object.insert 🠐 invokeInsertHook 🠐 Vue.patch 🠐 Vue._update',
' 🠐 eval 🠐 Array.reduce 🠐 Proxy.render 🠐 Vue._render',
].forEach(item => (fnCallInfo = fnCallInfo.split(item).join('')))
console.log('---------fnCallArr:', fnCallArr)
//空格填充对齐, 至少距左侧45个字符(不含日期), 更多的每10个一位
let info = headInfo + restInfo
//字符数计算,中文2个,英文1个
let infoLen = 0
if (info.includes('\n')) {
//有换行时取最后一行,并补充空格57
info = info + ' '
infoLen = getByteLen(info.split('\n').pop()) //字符计数,中文2个,英文1个
} else infoLen = getByteLen(info)
//生成需补充的空格, 函数调用信息显示的开始位置为 22(日期) + 45(最小位置), 下面是未考虑日期的, 因此以45为基准
let space = infoLen < 45 ? ' '.substring(infoLen) : ' '.substring((infoLen - 45) % 10)
console.log('infoLen', infoLen, 'space', space.length)
info = info + space + '# ' + fnCallInfo
// 日期时间
let d = thisTime('all') //自己写的当前日期时间生成函数, 输出格式: 20190420 06:20:54.513
//添加到文件
fs.appendFileSync(DB_PATH + '/log.log', d + ' ' + info + '\n')
//fs.appendFileSync(DB_PATH + '/log.log', d + ' ' + '@ infoLen ' + infoLen + ' space ' + space.length + '\n')
// fs.appendFileSync(DB_PATH + '/log.log', d + ' ' + util.inspect(args) + '\n') //原字符
}
下面分别说明一下
日志等级
日志一般分以下等级,不过个人开发一般只用到INFO和ERROR,直接用vscode查看日志,在日志中使用下面大写的符号即可高亮显示。
FATAL(致命错误):记录系统中出现的能使用系统完全失去功能,服务停止,系统崩溃等使系统无法继续运行下去的错误。例如,数据库无法连接,系统出现死循环。
ERROR(一般错误):记录系统中出现的导致系统不稳定,部分功能出现混乱或部分功能失效一类的错误。例如,数据字段为空,数据操作不可完成,操作出现异常等。
WARN(警告):记录系统中不影响系统继续运行,但不符合系统运行正常条件,有可能引起系统错误的信息。例如,记录内容为空,数据内容不正确等。
INFO(一般信息):记录系统运行中应该让用户知道的基本信息。例如,服务开始运行,功能已经开户等。
DEBUG (调试信息):记录系统用于调试的一切信息,内容或者是一些关键数据内容的输出。
如:
log('name', name) //括号中支持任意多个参数,
log('ERROR', 'name', name) //需要区分等级的,将等级放在第一个,方便区分显示
字符过滤
原输出内容如下,是给终端显示的,带有颜色定义的字符,当输出到文件时则用处不大,需要过滤掉。
//原内容
[ '%cmain %c空数组:%c +2ms',
'color: #6600FF',
'color: inherit',
'color: #6600FF',
'array',
[]
]
过滤如下
// 字符过滤--去掉颜色表识符%c
let headInfo = args[0].split('%c').join('') + ' '
// 过滤多余的color参数
args = args.filter(item => {
if (!item || typeof item !== 'string') {
return true // 避免下面空值报错
} else {
return item.substring(0, 6) !== 'color:'
}
})
函数调用链
通过error对象获得调用信息
let fnCallArr = new Error().stack.match(/at (.*?) /g)
//原信息如下,是一个数组:
0: "at Function.debug__WEBPACK_IMPORTED_MODULE_8___default.a.log "
1: "at debug "
2: "at eval "
3: "at Module../src/main.js "
4: "at __webpack_require__ "
5: "at fn "
6: "at Object.0 "
7: "at __webpack_require__ "
//vue组件调用
0: "at Function.debug__WEBPACK_IMPORTED_MODULE_8___default.a.log "
1: "at debug "
2: "at VueComponent.mounted "
3: "at invokeWithErrorHandling "
4: "at callHook "
5: "at Object.insert "
6: "at invokeInsertHook "
7: "at Vue.patch "
8: "at Vue._update "
9: "at Vue.updateComponent "
信息比较冗杂,需要过滤一下内容
//过滤数组项
arr[0]、arr[1]
__webpack_require__
node_modules
invokeWithErrorHandling
updateComponent
//过滤字符
at
VueComponent.
?vue&type=script&lang=js&
Module../src/
🠐 callHook 🠐 Object.insert 🠐 invokeInsertHook 🠐 Vue.patch 🠐 Vue._update
🠐 eval 🠐 Array.reduce 🠐 Proxy.render 🠐 Vue._render
输出文件显示
第一次在掘金发帖,有不足的的欢迎指教,如果喜欢的记得点赞哦~~