[Fourth] @ vue / cli3 plug-in, integrated logging system based on SSR [Part III]

In the previous article [II] created @ vue / cli3 plug and integrated function ---- [ssr SSR The second , we have created a @vue/cli3plug-in, and ssrintegrated into the plug-in service.

This article, let's plug-in to ssrcreate a log system services.

We will come gradually following aspects:

  • Select the log tool library
  • Logging tools integrated into the ssrplug-in
  • Log support distinguish environment, support the classification of the log, the log level of support
  • Cutting logs

Select the log tool library

Some logging tools based nodejs library to choose from:

Here we choose winstonas the basis for logging tools, access to our ssrengineering

Logging tools integrated into the ssrplug-in

We opened winstonthe the README , refer to Creating your own Logger one, to start creating ourlogger

Create a logger

In the last article we opened [II] created @ vue / cli3 plug-in, and integrate ssr SSR The second function ---- [ created vue-cli-plugin-my_ssr_plugin_demoproject

installation winston

yarn add winston
复制代码

In the root folder appcreate folder liband libcreate the logger.jsfiles, customize our own logger in this document

Directory structure is as follows:

├── app
│   ├── lib
│   │   ├── logger.js
│   ├── middlewares
│   │   ├── dev.ssr.js
│   │   ├── dev.static.js
│   │   └── prod.ssr.js
│   └── server.js
...
复制代码

logger.js It reads as follows:

const winston = require('winston')

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'combined.log' })
  ]
})

module.exports = {
  logger
}
复制代码

Then open our app/server.js, in the course of the service starts, the global object mounted on we just createdlogger

...

const { logger } = require('./lib/logger.js')

...

app.listen(port, host, () => {
  logger.info(`[${process.pid}]server started at ${host}:${port}`)
})

...
复制代码

Start the service, in addition to seeing the output terminal, it will also find more than one in the root directory of combined.logthe file, the contents of which are consistent with the output terminal

{"message":"[46071]server started at 127.0.0.1:3000","level":"info"}
复制代码

So far, we have access to the most basic logging into the server, then, let us consider the actual log scene.

Log support distinguish environment, support the classification of the log, the log level of support

For simplicity, we will distinguish between the environment, the log classification, log level simplified into the following specific requirements:

  1. Log needs to be written to the file.
  2. Logs need to support custom level, level in descending order errorare: warning, notice, info, debug, .
  3. Development environment, the best output log colored, can be more easily read format in the terminal.
  4. Increase user request log accesstype, this log needs to be written to a separate file, separate from other types of log area.

On the first request, we in the previous example, has passed winston.transports.Filerealized.

For the second, three requirements, we turn lib/logger.jsto add the relevant code, the final code is as follows:

const winston = require('winston')

const options = {
  // 我们在这里定义日志的等级
  levels: { error: 0, warning: 1, notice: 2, info: 3, debug: 4 },
  transports: [
    // 文件中我们只打印 warning 级别以上的日志(包含 warning)
    new winston.transports.File({ filename: 'combined.log', level: 'warning' })
  ]
}

// 开发环境,我们将日志也输出到终端,并设置上颜色
if (process.env.NODE_ENV === 'development') {
  options.format = winston.format.combine(
    winston.format.colorize(),
    winston.format.json()
  )

  // 输出到终端的信息,我们调整为 simple 格式,方便看到颜色;
  // 并设置打印 debug 以上级别的日志(包含 debug)
  options.transports.push(new winston.transports.Console({
    format: winston.format.simple(), level: 'debug'
  }))
}

const logger = winston.createLogger(options)

module.exports = {
  logger
}
复制代码

We app/servier.jsenter the following code:

...

logger.error('this is the error log')
logger.warning('this is the warning log')
logger.notice('this is the info log')
logger.info('this is the info log')
logger.debug('this is the debug log')

...
复制代码

After hair open environment to start the service, to see the terminal prints out the following:

error: this is the error log
warning: this is the warning log
notice: this is the info log
info: this is the info log
debug: this is the debug log
复制代码

The log file combined.logcontents are as follows:

{"message":"this is the error log","level":"\u001b[31merror\u001b[39m"}
{"message":"this is the warning log","level":"\u001b[31mwarning\u001b[39m"}
复制代码

After the test and production environments start the service, and the log will not be output to the terminal, only the output to a file:

{"message":"this is the error log","level":"error"}
{"message":"this is the warning log","level":"warning"}
复制代码

Next we look at Article IV requirements:

Increase user request log accesstype, this log needs to be written to a separate file, separate from other types of log area.

If we need to add a accesslog type, and outputs its contents to a separate file, the easiest way is to create one loggerinstance:

...
winston.loggers.add('access', {
  levels: { access: 0 },
  level: 'access',
  format: winston.format.combine(
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ filename: 'access.log', level: 'access' })
  ]
})
...
复制代码

We app/servier.jsadd printing accesslogs code:

const { logger, accessLogger } = require('./log.js')
...
accessLogger.access('this is the access log')

复制代码

After starting the service development environment, we found that in addition to combined.logoutside the log file, the addition of a access.logfile, reads:

{"message":"this is the access log","level":"access"}
复制代码

So far, we have not log automatically records the current time, we have lib/logger.jstwo categories are added on a log time, add the following code:

const winston = require('winston')

const options = {
  // 我们在这里定义日志的等级
  levels: { error: 0, warning: 1, notice: 2, info: 3, debug: 4 },
  format: winston.format.combine(
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' })
  ),
  transports: [
    // 文件中我们只打印 warning 级别以上的日志(包含 warning)
    new winston.transports.File({ filename: 'combined.log', level: 'warning' })
  ]
}

// 开发环境,我们将日志也输出到终端,并设置上颜色
if (process.env.NODE_ENV === 'development') {
  options.format = winston.format.combine(
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }),
    winston.format.colorize(),
    winston.format.json()
  )

  // 输出到终端的信息,我们调整为 simple 格式,方便看到颜色;
  // 并设置打印 debug 以上级别的日志(包含 debug)
  options.transports.push(new winston.transports.Console({
    format: winston.format.simple(), level: 'debug'
  }))
}

winston.loggers.add('access', {
  levels: { access: 0 },
  level: 'access',
  format: winston.format.combine(
    winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ filename: 'access.log', level: 'access' })
  ]
})

const logger = winston.createLogger(options)

module.exports = {
  logger,
  accessLogger: winston.loggers.get('access')
}
复制代码

After development environment to start the service, we found the log carrying current time information, the terminal reads:

error: this is the error log {"timestamp":"2019-06-06 17:02:36.736"}
warning: this is the warning log {"timestamp":"2019-06-06 17:02:36.740"}
notice: this is the info log {"timestamp":"2019-06-06 17:02:36.741"}
info: this is the info log {"timestamp":"2019-06-06 17:02:36.741"}
debug: this is the debug log {"timestamp":"2019-06-06 17:02:36.741"}
复制代码

`` File contents are as follows:

{"message":"this is the error log","level":"\u001b[31merror\u001b[39m","timestamp":"2019-06-06 17:02:36.736"}
{"message":"this is the warning log","level":"\u001b[31mwarning\u001b[39m","timestamp":"2019-06-06 17:02:36.740"}
复制代码

`` File contents are as follows:

{"message":"this is the access log","level":"access","timestamp":"2019-06-06 17:02:36.741"}
复制代码

Cutting logs

After our future deployment of on-line service, the server logs recorded content will continue to have written to the log to the same file, which for long-running services, is there a log too big risks.

Here, we split logs per hour in accordance with the contents of the log within each hour, write different files.

In addition, since the deployment of goods and services have multiple workerprocesses and services, so we assign a separate folder (in order to distinguish between the process id + date) for each process to store all logs this process:

logs
├──your_project_name
│   ├──pid_1236_2019_01_01
│   │   ├──access-2019-01-01-23.log
│   │   └──combined-2019-01-01-23.log
│   └──pid_1237_2019_01_01
│      ├──access-2019-01-01-23.log
│      └──combined-2019-01-01-23.log
复制代码

In order to achieve our expected log cutting function, we need to introduce a library:winston-daily-rotate-file

yarn add winston-daily-rotate-file
复制代码

After installation, we have lib/logger.jsintroduced in

require('winston-daily-rotate-file')
复制代码

After the introduction, we can winston.transports.DailyRotateFilehave automatic cutting function tracsports instance creation

const _getToday = (now = new Date()) => `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`

let dirPath += '/pid_' + pid + '_' + _getToday() + '/'

let accessTransport = new (winston.transports.DailyRotateFile)({
  filename: dirPath + 'access-%DATE%.log', // 日志文件存储路径 + 日志文件名称
  datePattern: 'YYYY-MM-DD-HH', // 日志文件切割的粒度,这里为每小时
  zippedArchive: true, // 是否压缩
  maxSize: '1g', // 每个日志文件最大的容量,如果达到此容量则触发切割
  maxFiles: '30d' // 日志文件保留的时间,这里为 30 天,30天之前的日志会被删除掉
})
复制代码

After adding cutting function lib/logger.jsas follows:

const winston = require('winston')
const { format } = winston
const { combine, timestamp, json } = format

const _getToday = (now = new Date()) => `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`

const rotateMap = {
  'hourly': 'YYYY-MM-DD-HH',
  'daily': 'YYYY-MM-DD',
  'monthly': 'YYYY-MM'
}

module.exports = (dirPath = './', rotateMode = '') => {

  if (!~Object.keys(rotateMap).indexOf(rotateMode)) rotateMode = ''

  let accessTransport
  let combineTransport

  if (rotateMode) {
    require('winston-daily-rotate-file')

    const pid = process.pid

    dirPath += '/pid_' + pid + '_' + _getToday() + '/'

    const accessLogPath = dirPath + 'access-%DATE%.log'
    const combineLogPath = dirPath + 'combine-%DATE%.log'

    const datePattern = rotateMap[rotateMode] || 'YYYY-MM'

    accessTransport = new (winston.transports.DailyRotateFile)({
      filename: accessLogPath,
      datePattern: datePattern,
      zippedArchive: true,
      maxSize: '1g',
      maxFiles: '30d'
    })

    combineTransport = new (winston.transports.DailyRotateFile)({
      filename: combineLogPath,
      datePattern: datePattern,
      zippedArchive: true,
      maxSize: '500m',
      maxFiles: '30d'
    })
  }

  const options = {
    // 我们在这里定义日志的等级
    levels: { error: 0, warning: 1, notice: 2, info: 3, debug: 4 },
    format: combine(
      timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' })
    ),
    transports: rotateMode ? [
      combineTransport
    ] : []
  }

  // 开发环境,我们将日志也输出到终端,并设置上颜色
  if (process.env.NODE_ENV === 'development') {
    options.format = combine(
      timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }),
      winston.format.colorize(),
      json()
    )

    // 输出到终端的信息,我们调整为 simple 格式,方便看到颜色;
    // 并设置打印 debug 以上级别的日志(包含 debug)
    options.transports.push(new winston.transports.Console({
      format: format.simple(), level: 'debug'
    }))
  }

  winston.loggers.add('access', {
    levels: { access: 0 },
    level: 'access',
    format: combine(
      timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }),
      json()
    ),
    transports: rotateMode ? [
      accessTransport
    ] : []
  })

  const logger = winston.createLogger(options)

  return {
    logger: logger,
    accessLogger: winston.loggers.get('access')
  }
}
复制代码

In app/server.jsthe introduction lib/logger.jsalso need to be adjusted as follows:

const { logger, accessLogger } = require('./lib/logger.js')('./', 'hourly')
复制代码

In a development environment to start the service, we will find that in addition to the output terminal of the log, we log file into a structure as follows:

./pid_48794_2019-6-6
├── access-2019-06-06-18.log
└── combine-2019-06-06-18.log
复制代码

Eventually, the plug-in vue-cli-plugin-my_ssr_plugin_demofull directory structure is as follows:

├── app
│   ├── middlewares
│   │   ├── dev.ssr.js
│   │   ├── dev.static.js
│   │   └── prod.ssr.js
│   ├── lib
│   │   └── logger.js
│   └── server.js
├── generator
│   ├── index.js
│   └── template
│       ├── src
│       │   ├── App.vue
│       │   ├── assets
│       │   │   └── logo.png
│       │   ├── components
│       │   │   └── HelloWorld.vue
│       │   ├── entry-client.js
│       │   ├── entry-server.js
│       │   ├── main.js
│       │   ├── router
│       │   │   └── index.js
│       │   ├── store
│       │   │   ├── index.js
│       │   │   └── modules
│       │   │       └── book.js
│       │   └── views
│       │       ├── About.vue
│       │       └── Home.vue
│       └── vue.config.js
├── index.js
└── package.json
复制代码

So far, we have completed the logging system. The next article, we talk about how to vue-cli-plugin-my_ssr_plugin_demodesign and integrated monitoring system.


Drop front-end team to recruit partners, welcome to send your resume to the mailbox: [email protected]

Reproduced in: https: //juejin.im/post/5d030cc4f265da1bd04edc64

Guess you like

Origin blog.csdn.net/weixin_34038652/article/details/93182168