乐趣区

node错误处理与日志

node 项目中的错误处理
node 中 Error 对象的使用
使用 captureStackTrace 方法加入自带的错误信息
// Error 对象自带的属性
Error.captureStackTrace

// 如何使用 captureStackTrace
var obj = {
message: ‘something is wrong’
}

Error.captureStackTrace(obj)

throw obj // 此时会抛出 obj 对象的 message 内信息
使用 try catch 捕获错误
直接把代码写在 try catch 中即可捕获错误信息
try{
throw new Error(‘oh no’)
}catch(e){
console.log(e)
}
在异步代码中,直接 try catch 是无法捕获错误信息的, 可以使用如下方法
function foo(params, cb){
const error = new Error(‘something is wrong’)
if(error) cb(error)
}
以上使用 callback 方式来做错误处理比较容易麻烦,容易出错,现在 node 已经支持 async await 所以尽量使用它们准没错
async function foo(){
try{
await bar()
}catch(e){
console.log(e)
}
}

async function bar(){
throw new Error(‘async function got wrong)
}

foo()
基本错误类型
在项目会有多个地方对错误信息进行处理,所以先写一个基本错误类型,方便使用
// 基本错误类型
class HttpBaseError extends Error {
constructor(httpStatusCode, httpMsg, errCode, msg) {
super(`HTTP ERROR: ${msg}`);
this.httpStatusCode = httpStatusCode;
this.httpMsg = httpMsg;
this.errCode = errCode;
}
}

try {
// 直接抛出定义好的错误即可
throw new HttpBaseError(404, ‘ 资源不存在 ’, 10000, ‘resouse is not found’);
} catch (e) {
console.log(e.message);
console.log(e.httpStatusCode);
console.log(e.httpMsg);
console.log(e.errCode);
}
特定错误类型
除了基本类型,不同情况下会有不同错误信息,需要用一个特定的错误类型来处理特定的错误信息
// 一个参数错误类型
const ERROR_CODE = 40000 // 错误码
class HttpRequestParamError extends HttpBaseError {
constructor(paramName, desc, msg) {
super(200, desc, ERROR_CODE, `${paramName} wrong: ${msg}`)
}
}
这样,在参数错误的地方就能非常方便的调用这个错误类型来返回错误
抛错的逻辑
错误处理中,model,controller 中的错误,有些是不能直接返回给用户的,应该只返回给 model 或 controller 的调用者。
使用错误处理
正常接口,controller,model 的错误,使用设定好的错误类型进行处理,例如前面写的 HttpRequestParamError,在所有所有路由的最后,需要使用一个 error handler 来对所有的错误进行集中处理
// error handler
function handler(options) {
return function (err, req, res, next) {
if (err instanceof HttpRequestParamError) {// 这里对不同的错误做不同的处理
console.log(‘http request error’)
res.statusCode = err.httpStatusCode
res.json({
code: err.errCode,
msg: err.httpMsg
})
} else {
// 设定之外的错误,把管理权向外移交
next(err)
}
}
}
除了可预知的错误,还有未知的类型的错误,此时需要一个 unknow error handler 进行剩余错误的处理
function unKnowErrorHandler(options) {
return function (err, req, res, next) {
console.log(err)
res.json({
code: 99999,
msg: ‘unKnow error’
})
}
}
node 中的日志
平时使用 console 来 debug 是没有问题的,但是在线上环境,我们并不能有效的看到 console,使用日志系统可以更好的方便线上的 debug,记录信息等
winston 的使用
winston 是 node 中常用的日志插件
const winston = require(‘winston’)

const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
new winston.transports.File({
name: ‘info_logger’, // log 名称
filename: ‘logs/info.log’, // 日志记录文件地址
level: ‘info’ // 设置 log 的类型
}),
// 第二个 logger,记录 error 级别的 log
new winston.transports.File({
name: ‘error_logger’,
filename: ‘logs/error.log’,
level: ‘error’
})
]
});

// error 级别比 info 要高,error.log 文件只会记录 error 日志
logger.error(‘first error log with winston’)
// info 文件内会记录 info 级别的 log 和比 info 级别高的 log,比如 error
logger.info(‘first info log with winston’)
日志滚动(log rotation)
在产生大量数据的应用当中,日志的输出是大量的,这是就需要对日志进行拆分处理,例如按照每天的频率来分别记录日志。
winston 并不自带 log rotation,需要引入 winston-daily-rotate-file 库
const {
createLogger,
format,
transports
} = require(‘winston’);
const {
combine,
timestamp,
label,
prettyPrint
} = format;
require(‘winston-daily-rotate-file’)

var transport = new(transports.DailyRotateFile)({
filename: ‘./logs/app-%DATE%.log’,
datePattern: ‘YYYY-MM-DD-HH’,
maxSize: ’20m’,
maxFiles: ’14d’,
format: combine(
label({
label: ‘right meow!’
}),
timestamp(),
prettyPrint()
),
});
transport.on(‘rotate’, function (oldFilename, newFilename) {});

var logger = createLogger({
transports: [
transport
]
});

logger.info(‘Hello World!’);
运行日志文件,此时在 logs 目录下就生成了今天的日志欢迎访问我的博客

退出移动版