node错误处理与日志记录的实现
node项目中的错误处理
node中Error对象的使用
使用captureStackTrace方法加入自带的错误信息
//Error对象自带的属性 Error.captureStackTrace //如何使用captureStackTrace varobj={ message:'somethingiswrong' } Error.captureStackTrace(obj) throwobj//此时会抛出obj对象的message内信息
使用trycatch捕获错误
直接把代码写在trycatch中即可捕获错误信息
try{ thrownewError('ohno') }catch(e){ console.log(e) }
在异步代码中,直接trycatch是无法捕获错误信息的,可以使用如下方法
functionfoo(params,cb){ consterror=newError('somethingiswrong') if(error)cb(error) }
以上使用callback方式来做错误处理比较容易麻烦,容易出错,现在node已经支持asyncawait所以尽量使用它们准没错
asyncfunctionfoo(){ try{ awaitbar() }catch(e){ console.log(e) } } asyncfunctionbar(){ thrownewError('asyncfunctiongotwrong) } foo()
基本错误类型
在项目会有多个地方对错误信息进行处理,所以先写一个基本错误类型,方便使用
//基本错误类型 classHttpBaseErrorextendsError{ constructor(httpStatusCode,httpMsg,errCode,msg){ super(`HTTPERROR:${msg}`); this.httpStatusCode=httpStatusCode; this.httpMsg=httpMsg; this.errCode=errCode; } } try{ //直接抛出定义好的错误即可 thrownewHttpBaseError(404,'资源不存在',10000,'resouseisnotfound'); }catch(e){ console.log(e.message); console.log(e.httpStatusCode); console.log(e.httpMsg); console.log(e.errCode); }
特定错误类型
除了基本类型,不同情况下会有不同错误信息,需要用一个特定的错误类型来处理特定的错误信息
//一个参数错误类型 constERROR_CODE=40000//错误码 classHttpRequestParamErrorextendsHttpBaseError{ constructor(paramName,desc,msg){ super(200,desc,ERROR_CODE,`${paramName}wrong:${msg}`) } }
这样,在参数错误的地方就能非常方便的调用这个错误类型来返回错误
抛错的逻辑
错误处理中,model,controller中的错误,有些是不能直接返回给用户的,应该只返回给model或controller的调用者。
使用错误处理
正常接口,controller,model的错误,使用设定好的错误类型进行处理,例如前面写的HttpRequestParamError,在所有所有路由的最后,需要使用一个errorhandler来对所有的错误进行集中处理
//errorhandler functionhandler(options){ returnfunction(err,req,res,next){ if(errinstanceofHttpRequestParamError){//这里对不同的错误做不同的处理 console.log('httprequesterror') res.statusCode=err.httpStatusCode res.json({ code:err.errCode, msg:err.httpMsg }) }else{ //设定之外的错误,把管理权向外移交 next(err) } } }
除了可预知的错误,还有未知的类型的错误,此时需要一个unknowerrorhandler进行剩余错误的处理
functionunKnowErrorHandler(options){ returnfunction(err,req,res,next){ console.log(err) res.json({ code:99999, msg:'unKnowerror' }) } }
node中的日志
平时使用console来debug是没有问题的,但是在线上环境,我们并不能有效的看到console,使用日志系统可以更好的方便线上的debug,记录信息等
winston的使用
winston是node中常用的日志插件
constwinston=require('winston') constlogger=winston.createLogger({ transports:[ newwinston.transports.Console(), newwinston.transports.File({ name:'info_logger',//log名称 filename:'logs/info.log',//日志记录文件地址 level:'info'//设置log的类型 }), //第二个logger,记录error级别的log newwinston.transports.File({ name:'error_logger', filename:'logs/error.log', level:'error' }) ] }); //error级别比info要高,error.log文件只会记录error日志 logger.error('firsterrorlogwithwinston') //info文件内会记录info级别的log和比info级别高的log,比如error logger.info('firstinfologwithwinston')
日志滚动(logrotation)
在产生大量数据的应用当中,日志的输出是大量的,这是就需要对日志进行拆分处理,例如按照每天的频率来分别记录日志。
winston并不自带logrotation,需要引入winston-daily-rotate-file库
const{ createLogger, format, transports }=require('winston'); const{ combine, timestamp, label, prettyPrint }=format; require('winston-daily-rotate-file') vartransport=new(transports.DailyRotateFile)({ filename:'./logs/app-%DATE%.log', datePattern:'YYYY-MM-DD-HH', maxSize:'20m', maxFiles:'14d', format:combine( label({ label:'rightmeow!' }), timestamp(), prettyPrint() ), }); transport.on('rotate',function(oldFilename,newFilename){}); varlogger=createLogger({ transports:[ transport ] }); logger.info('HelloWorld!');
运行日志文件,此时在logs目录下就生成了今天的日志
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。