Error handling in the Node project

The use of Error objects in node

Add the built-in error message using the captureStackTrace method

CaptureStackTrace var obj = {message:'something is wrong'} Error. CaptureStackTrace (obj) throw obj // The message inside the obj object is thrownCopy the code

Use try catch to catch errors

Error messages can be caught by simply writing code in a try catch

try{
    throw new Error('oh no')
}catch(e){
	console.log(e)
}
Copy the code

In asynchronous code, a direct try catch does not catch the error message, so you can use the following method

function foo(params, cb){
    const error = new Error('something is wrong')
    if(error) cb(error)
}
Copy the code

Node already supports async await, so use callback to handle errors

async function foo(){
    try{
        await bar()
    }catch(e){
        console.log(e)
    }
}

async function bar(){
    throw new Error('async function got wrong) } foo()Copy the code

Basic error types

Error messages can be handled in multiple places in a project, so write a basic error type first for ease of use

// 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,'Resource does not exist', 10000, 'resouse is not found');
} catch (e) {
  console.log(e.message);
  console.log(e.httpStatusCode);
  console.log(e.httpMsg);
  console.log(e.errCode);
}
Copy the code

Specific error type

In addition to the basic type, different cases have different error messages, and you need to use a specific error type to handle a specific error message

Const ERROR_CODE = 40000 class HttpRequestParamError extends HttpBaseError {constructor(paramName,) desc, msg) { super(200, desc, ERROR_CODE, `${paramName} wrong: ${msg}`)}}Copy the code

This makes it very easy to call the error type to return an error if the argument is wrong

Throw the logic wrong

In error handling, some errors in model and controller cannot be returned directly to the user, but should only be returned to the caller of model or Controller.

Use error handling

Controller/model errors are handled using specified error types, such as HttpRequestParamError. At the end of all routes, an error handler is required to handle all errors in a centralized manner

// error handler
function handler(options) {
    return function (err, req, res, next) {
        if(err instanceof HttpRequestParamError) {// Here we do different things for different errors console.log('http request error')
            res.statusCode = err.httpStatusCode
            res.json({
                code: err.errCode,
                msg: err.httpMsg
            })
        } elseNext (err)}}Copy the code

In addition to predictable errors, there are also unknown types of errors, in which case an unknown error handler is required to handle the rest of the errors

function unKnowErrorHandler(options) {
    return function (err, req, res, next) {
        console.log(err)
        res.json({
            code: 99999,
            msg: 'unKnow error'}}})Copy the code

Logs in node

Normally, there is no problem with using console to debug, but in online environment, we cannot see console effectively. Using log system can better facilitate online debugging and recording information

The use of Winston

Winston is a logging plug-in commonly used in Node

const winston = require('winston')

const logger = winston.createLogger({
    transports: [
        new winston.transports.Console(),
        new winston.transports.File({
            name: 'info_logger', / /logThe name of the filename:'logs/info.log'// Log file address level:'info'/ / setlog}), // The second logger, which records the error levellog
        new winston.transports.File({
            name: 'error_logger',
            filename: 'logs/error.log',
            level: 'error']}})); // The error level is higher than info. The error. Log file only records the error log logger.error('first error log with winston'// the info level will be recorded in the filelogAnd higher than infologFor example error logger.info('first info log with winston')
Copy the code

Log rotation

In applications that generate a large amount of data, the output of logs is large. Therefore, logs need to be split, for example, logs are recorded according to the frequency of each day.

Winston doesn’t have its own log rotation, so we need to introduce the Winston-daily-rotate-file library

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! ');
Copy the code

Run the log file, at which point today’s log is generated in the logs directory

Welcome to my blog