node項目錯誤處理與日誌

node項目中的錯誤處理

node中Error對象的使用

使用captureStackTrace方法加入自帶的錯誤信息javascript

// Error對象自帶的屬性
Error.captureStackTrace

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

Error.captureStackTrace(obj)

throw obj	// 此時會拋出obj對象的message內信息
複製代碼

使用try catch捕獲錯誤

直接把代碼寫在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}`)
    }
}
複製代碼

這樣,在參數錯誤的地方就能很是方便的調用這個錯誤類型來返回錯誤bash

拋錯的邏輯

錯誤處理中,model,controller中的錯誤,有些是不能直接返回給用戶的,應該只返回給model或controller的調用者。app

使用錯誤處理

正常接口,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進行剩餘錯誤的處理async

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目錄下就生成了今天的日誌

歡迎訪問個人博客

相關文章
相關標籤/搜索