在项目中将打印日志保存到本地

实现日志功能
在console.log时将打印的东西写入日志,关键是重写了console.log方法
console.warn和console.error也一样。

1、引入node的path和fs模块。

在NW项目中,可以在前端使用node模块来写日志;但如果是在浏览器中,就不能使用node模块。

var path = null
var fs = null
if (global.hasOwnProperty('nw')) {
  path = nw.require('path')
  fs = nw.require('fs')
} else if (Meteor.isServer) {
  path = require('path')
  fs = require('fs')
} else {
  console.warn('In browser, Can not write log.')
}

2、定义一个Logger类,用来写日志。

1、在构造函数中

1、生成日志存放的路径。

在当前项目的根目录下创建log文件夹。

if(Meteor.isServer) {
      this._LogPath = path.resolve(process.cwd(), '..', '..', 'log')
    } else {
      this._LogPath = path.resolve(process.cwd(), 'log')
    }

2、根据路径创建文件夹

if (!fs.existsSync(this._LogPath)) {
      fs.mkdirSync(this._LogPath)
    }

3、调用原型上的addLogPath方法

 this.addLogPath('client', 'client.log')

2、定义Logger类的原型方法

1、addLogPath方法

用于创建一个名为logFile(名称前加时间)的文件

addLogPath(key, logFile) {
    let logPath = path.join(this._LogPath, this.dateFormat(new Date(), 'yyyyMMdd') + '.' + logFile)
    if (this._LogFiles[key] !== logPath) {
      this._LogFiles[key] = logPath
      if (!fs.existsSync(logPath)) {
        fs.writeFileSync(logPath, '')
      }
      this._Logfd[key] = fs.openSync(this._LogFiles[key], 'a')
    }
  }

2、needToWrite方法

判断是否有日志可写,即判断_LogBuffer[key]是否为空字符串。

 needToWrite () {
    for (const key in this._LogBuffer) {
      if (this._LogBuffer.hasOwnProperty(key)) {
        if (this._LogBuffer[key] !== '') {
          return true
        }
      }
    }
    return false
  }

3、writeLogToFile方法

  • this._LogFiles[key]是日志的路径
writeLogToFile() {
    for (const key in this._LogBuffer) {
      if (this._LogBuffer.hasOwnProperty(key) && this._LogFiles[key]) {
        try {
          if (!this._Logfd[key]) {
            if (!fs.existsSync(this._LogFiles[key])) {
              fs.writeFileSync(this._LogFiles[key], '')
            }
            this._Logfd[key] = fs.openSync(this._LogFiles[key], 'a')
          }
          fs.appendFileSync(this._Logfd[key], this._LogBuffer[key], {
            encoding: 'utf8' 
          })
        } catch (error) {
          console.error(error)
        }
        this._LogBuffer[key] = ''
      }
    }
    return this.needToWrite()
  }

4、start方法

start方法中,

  • 1、如果此时计时器没开,并且有日志可写,就开启计时器,调用writeLogToFile写日志。
  • 2、在writeLogToFile方法中会返回是否还要写,返回false时关闭计时器
  • 3、如果还要写,会在时间间隔后再次调用去写
  • 4、计时器中的操作是放在任务队列的
start() {
    if (this._WriteTimer === null && this.needToWrite()) {
      this._WriteTimer = setInterval(() => {
        if (!this.writeLogToFile()) {
          clearInterval(this._WriteTimer)
          this._WriteTimer = null
        }
      }, this._SaveInterval);
    }
  }

5、writeLog方法

为_LogBuffer[key]日志缓存字符串添加新来的日志,调用start开始写日志。
key在前端时是字符串’client’

writeLog(key, logdata) {
    if (!this._LogBuffer[key]) {
      this._LogBuffer[key] = ''
    }
    this._LogBuffer[key] += logdata
    this.start()
  }

6、addLog方法

对writeLog方法的一层封装

7、dateFormat方法

用于生成格式化日期字符串,作为日志标题一部分

8、formatLog方法

格式化日志内容,在日志前添加记录时间和日志类型,字符串最后添加\r\n
回车符\r 换行符\n

Logger类全部代码:

export class Logger {
  constructor() {
    this._LogFiles = {}
    this._Logfd = {}
    this._LogBuffer = {}
    this._WriteTimer = null
    this._SaveInterval = 1000

    if(Meteor.isServer) {
      this._LogPath = path.resolve(process.cwd(), '..', '..', 'log')
    } else {
      this._LogPath = path.resolve(process.cwd(), 'log')
    }
    
    if (!fs.existsSync(this._LogPath)) {
      fs.mkdirSync(this._LogPath)
    }

    this.addLogPath('client', 'client.log')
  }

  addLogPath(key, logFile) {
    console.log('Logger.setLogPath', key, logFile)
    let logPath = path.join(this._LogPath, this.dateFormat(new Date(), 'yyyyMMdd') + '.' + logFile)
    if (this._LogFiles[key] !== logPath) {
      this._LogFiles[key] = logPath
      if (!fs.existsSync(logPath)) {
        fs.writeFileSync(logPath, '')
      }
      this._Logfd[key] = fs.openSync(this._LogFiles[key], 'a')
    }
  }

  needToWrite () {
    for (const key in this._LogBuffer) {
      if (this._LogBuffer.hasOwnProperty(key)) {
        if (this._LogBuffer[key] !== '') {
          return true
        }
      }
    }
    return false
  }

  writeLogToFile() {
    for (const key in this._LogBuffer) {
      if (this._LogBuffer.hasOwnProperty(key) && this._LogFiles[key]) {
        try {
          if (!this._Logfd[key]) {
            if (!fs.existsSync(this._LogFiles[key])) {
              fs.writeFileSync(this._LogFiles[key], '')
            }

            this._Logfd[key] = fs.openSync(this._LogFiles[key], 'a')
          }

          fs.appendFileSync(this._Logfd[key], this._LogBuffer[key], {
            encoding: 'utf8' 
          })
        } catch (error) {
          console.error(error)
        }
        this._LogBuffer[key] = ''
      }
    }
    return this.needToWrite()
  }

  start() {
    if (this._WriteTimer === null && this.needToWrite()) {
      this._WriteTimer = setInterval(() => {
        if (!this.writeLogToFile()) {
          clearInterval(this._WriteTimer)
          this._WriteTimer = null
        }
      }, this._SaveInterval);
    }
  }

  writeLog(key, logdata) {
    // console.log('addLog', type, logdata)
    if (!this._LogBuffer[key]) {
      this._LogBuffer[key] = ''
    }

    this._LogBuffer[key] += logdata
    this.start()
  }

  addLog(key, type, data) {
    this.writeLog(key, this.formatLog(type, data))
  }

  dateFormat (date, fmt) {
    var o = {
      "M+" : date.getMonth()+1,                 //月份
      "d+" : date.getDate(),                    //日
      "h+" : date.getHours(),                   //小时
      "m+" : date.getMinutes(),                 //分
      "s+" : date.getSeconds(),                 //秒
      "q+" : Math.floor((date.getMonth()+3)/3), //季度
      "S"  : date.getMilliseconds()             //毫秒
    };
  
    if(/(y+)/.test(fmt)){
      fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length));
    }
          
    for(var k in o){
      if(new RegExp("("+ k +")").test(fmt)){
        if (k === 'S') {
          fmt = fmt.replace(RegExp.$1, (("000"+ o[k]).substr((""+ o[k]).length)))
        } else {
          fmt = fmt.replace(
            RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
        }
      }       
    }
  
    return fmt;
  }

  formatLog (type, data) {
    return `[${this.dateFormat(new Date(), 'hh:mm:ss.S')}] [${type}] - ${data}\r\n`
  }
}

3、定义一个模块logutil.js,在模块中重写console.log方法

import {Logger} from './logger.class'
if (!window.ArchonLogger) {
  window.ArchonLogger = {
    formatLog (args) {
      let logdata = ''
      for (let index = 0; index < args.length; index++) {
        const item = args[index];
        let addTxt = ''
        if (item === null) {
          addTxt = 'null'
        } else if (typeof item === 'object' ) {
          addTxt = '{' + item.toString() + '}'//util.inspect(item, { compact: true, depth: 5, breakLength: 160 })
        } else if (Array.isArray(item)) {
          addTxt = '[' + item.toString() + ']'
        } else {
          addTxt = item
        }
        logdata += addTxt  + ' '
      }
      return logdata
    },
    Logger : new Logger()
  }

  if (process.env.NODE_ENV !== 'development') {//非开发模式下不打印到控制台,记录到本地文件中
    console.log = function() {//重写了console.log方法
      ArchonLogger.Logger.addLog('client', 'Info', ArchonLogger.formatLog(arguments))
    }

    console.warn = function() {
      ArchonLogger.Logger.addLog('client', 'Warn', ArchonLogger.formatLog(arguments))
    }
    
    console.error = function() {
      ArchonLogger.Logger.addLog('client', 'Error', ArchonLogger.formatLog(arguments))
    }
  }
}

4、在前端main.js中引入模块logutil.js

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值