Koa Log Middleware Packaging Development

Keywords: Database npm JSON Attribute

Logging is essential for a server application. We need to use it to record what the project program does every day, when and what errors have happened. It is convenient for us to review and grasp the running status of the server in real time, and restore the problem scenario in the future.

The Role of Logs

  • Record the running status of the server program;
  • Help developers quickly catch errors, locate and troubleshoot.

Log middleware development tool log4js

  1. There is no log module in node, so a third-party module is needed.
  2. Use module: log4js
  3. Installation: NPM I log4js-S
  4. logsjs official document
  5. Log classification:
    1. Access logs: Record client access to projects, mainly http requests. Used to help improve and enhance the performance and user experience of the website;
    2. Application logs: Printed logs of project markers and record locations, including abnormal situations, to facilitate queries about project status and locate bugs (including debug, info, warn and error levels).

Log level

  • If the log level is configured, it can only record log information at a higher level than that set.
  • Log Level Map

If you configure level:'error', you can only output log information at the error,fatar,mark levels.

Development of Log Middleware

Set up the information segments (log_info.js) that need to be logged

export default (ctx, message, commonInfo) => {
  const {
   method, // Request method
   url,     // Request link
   host,   // The host of the client sending the request
   headers   // headers in requests
  } = ctx.request;
  const client = {
   method,
   url,
   host,
   message,
   referer: headers['referer'], // The source address of the request
   userAgent: headers['user-agent'] // Client Information Device and Browser Information
  }
  return JSON.stringify(Object.assign(commonInfo, client));
}

Set up the log4js object (logger.js) after the general access configuration

const getLog = ({env, appLogLevel, dir}, name) => {
   
  //log4js Basic Description Configuration Item, you can customize the key name for categories.appenders custom selection
  let appenders = {
    // Custom Configuration Item 1
    cheese: {
      type: 'dateFile', //Output log type
      filename: `${dir}/task`, //Output log path
      pattern: '-yyyy-MM-dd.log', //Log file suffix name (task-2019-03-08.log)
      alwaysIncludePattern: true
    }
  }
  // If you configure the development environment to print information on the console
  if (env === "dev" || env === "local" || env === "development") {
    // Custom Configuration Item 2
    appenders.out = {
     type: "stdout"
    }
  }
  // log4js configuration
  let config = {
    appenders,
    //Get the key name of the log object as the getLogger method, default is used by default
    categories: {
     default: {
      appenders: Object.keys(appenders), // Say there are configuration items in appenders
      level: appLogLevel
     }
    }
  }
  log4js.configure(config) //Use configuration items
  return log4js.getLogger(name)// This cheese parameter value will be first found in categories, and if it is not found, default appenders will be used by default, and the information will be output to y yyyyMMdd-out.log.
}

Log log middleware development (logger.js)

export default (options) => {
  const contextLogger = {}; //Later assignment to ctx.log
  const { env, appLogLevel, dir, serverIp, projectName } = Object.assign({}, baseInfo, options || {});
  // Take out the generic configuration (project name, server request IP)
  const commonInfo = { projectName, serverIp };
 
  const logger = getLog({env, appLogLevel, dir},'cheese');
 
  return async (ctx, next) => {
    const start = Date.now(); //Logging start time
    // The log type is assigned to ctx.log. The special location of the late middleware needs to record the log. It can record different types of logs directly with ctx.log.error(err).
    methods.forEach((method, i) => {
      contextLogger[method] = (message) => {
        logger[method](logInfo(ctx, message, commonInfo))
      }
    })
    ctx.log = contextLogger;
    // Execution Middleware
    await next()
    // End time
    const responseTime = Date.now() - start;
    // logger.info will be recorded for execution time
    logger.info(logInfo(ctx,
      {
        responseTime: `The response time is ${responseTime/1000}s`
      }, commonInfo)
    )
  }
}

Middleware usage (app.js)

import Log from '../log/logger';
...
app.use(Log({
    env: app.env, // Environment variables provided by koa
    projectName: 'back-API',
    appLogLevel: 'debug',
    dir: 'logs',
    serverIp: ip.address()
  }))

Other special locations require logging

ctx.log.error(err.stack); //Logging errors
ctx.log.info(err.stack); // Recording Information Log
ctx.log.warn(err.stack); // Record warning logs
...

Run screenshots

In order to help you make learning easy and efficient, we can share a lot of information for free, and help you overcome difficulties on the way to become a whole stack engineer and even an architect. Here we recommend a front-end stack of learning and communication circle: 866109386. Welcome to the group for discussion, learning and communication, and common progress. log4js uses basic configuration and process parsing

Setting configuration items,

// Configuration Item Form
{
  appenders:{
    [custom key]:{}
  },
  categories:{
  }
}
// To configure
config: {
  appenders:{
    // Each property can be viewed as a configuration module
    out: {
      type: 'dateFile', //Output log type
      filename: `log/task`, //Output log path
      pattern: '-yyyy-MM-dd.log', //Log file suffix name (task-2019-03-08.log)
      ...//Configuration See Official Website
    },
    error: {
      type: 'dateFile',
      filename: 'log/error',
      pattern: '-yyyy-MM-dd.log'',
      "alwaysIncludePattern": true
    },
    stdout: { type: 'stdout' }, //Print information on the console
  },
  // The log4js configuration is retrieved by categories and returned to the log4js object after configuration. Each attribute configuration corresponds to a different log4js configuration object entry; default is the default entry (getLogger () defaults when it cannot find the entry)
  categories:{
    // Configure the default entry, using the'stdout'and'out' configuration modules in appenders to record the level log above trace
    default: { appenders: ['stdout','out'], level: 'trace' },
    // Configure the error gate entrance, use the'stdout','err'configuration module in appenders to record the level log above error
    error : {appenders: ['err'], level: 'error'}
  }
}

Use let logger_out = log4js.getLogger('app');

log4js.getLogger('app') finds a specific log4js object flow: first, according to the app parameter value, find no app in categories, then default corresponding appenders will be used to configure, that is, the information will be output to the log/task-yyy-mm-dd.log file, and will be output to the console.

Use let logger_out = log4js.getLogger('error');

According to the value of error parameter, it is found that there is no error configuration in categories, and then it will be configured using the corresponding appenders of error, that is, information will be output to log/error-yyyy-mm-dd.log file, because the stdout module is not used in the appenders of error configuration item, so the information will not be output to the console.

Later consideration

Whether it is necessary to store and persist logs in database?

Considering that it is impossible to keep the log records all the time, it may not be necessary to store the logs one month or a week ago. It is necessary to develop and set up a timer to automatically delete the expired log files (get the database log records).

Posted by Andrei on Fri, 17 May 2019 13:54:27 -0700