使用captureStackTrace
方法加入自帶的錯誤信息javascript
// Error對象自帶的屬性 Error.captureStackTrace // 如何使用captureStackTrace var obj = { message: 'something is wrong' } Error.captureStackTrace(obj) throw obj // 此時會拋出obj對象的message內信息
直接把代碼寫在try catch
中便可捕獲錯誤信息java
try{ throw new Error('oh no') }catch(e){ console.log(e) }
在異步
代碼中,直接try catch是沒法捕獲錯誤信息的,可使用以下方法node
function foo(params, cb){ const error = new Error('something is wrong') if(error) cb(error) }
以上使用callback
方式來作錯誤處理比較容易麻煩,容易出錯,如今node已經支持async await
因此儘可能使用它們準沒錯git
async function foo(){ try{ await bar() }catch(e){ console.log(e) } } async function bar(){ throw new Error('async function got wrong) } foo()
在項目會有多個地方對錯誤信息進行處理,因此先寫一個基本錯誤
類型,方便使用github
// 基本錯誤類型 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); }
除了基本類型,不一樣狀況下會有不一樣錯誤信息,須要用一個特定
的錯誤類型來處理特定的錯誤信息json
// 一個參數錯誤類型 const ERROR_CODE = 40000 // 錯誤碼 class HttpRequestParamError extends HttpBaseError { constructor(paramName, desc, msg) { super(200, desc, ERROR_CODE, `${paramName} wrong: ${msg}`) } }
這樣,在參數錯誤的地方就能很是方便的調用這個錯誤類型來返回錯誤app
錯誤處理中,model,controller中的錯誤,有些是不能直接返回給用戶的,應該只返回給model或controller的調用者。異步
正常接口,controller,model的錯誤,使用設定好的錯誤類型進行處理,例如前面寫的HttpRequestParamError
,在全部全部路由的最後,須要使用一個error handler來對全部的錯誤進行集中處理
async
// 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進行剩餘錯誤的處理ui
function unKnowErrorHandler(options) { return function (err, req, res, next) { console.log(err) res.json({ code: 99999, msg: 'unKnow error' }) } }
平時使用console來debug是沒有問題的,可是在線上環境,咱們並不能有效的看到console,使用日誌系統能夠更好的方便線上的debug,記錄信息等
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')
在產生大量數據的應用當中,日誌的輸出是大量的,這是就須要對日誌進行拆分
處理,例如按照天天的頻率來分別記錄日誌。
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目錄下就生成了今天的日誌
歡迎訪問個人博客