实现日志功能
在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))
}
}
}