}else{ //若无时间参数则获取当前时间,然后精度默认 var date = new Date(+new Date()+8*3600*1000).toISOString().replace(/T/g,' ').replace(/\.[\d]{3}Z/,'').slice(0,10) var type=null
} var op = arguments[2] var countResult = 0 //对日志结果进行统计 var logPath = appDirName.slice(0,-3)+'log\\'+'ivsvr_'+date+'.log' //拼接日志文件名称 var logStr = ''
fs.stat(logPath, function (err, stats) { //获取对应的日志文件状态 if(err){ //日志不存在或者异常处理信息
$('#logTipInfo tr td').html('无日志信息可供查看') console.log(err)
}else{ var lineCount = 0 var readline = require('readline') var fReadName = logPath var fRead = fs.createReadStream(fReadName) var objReadline = readline.createInterface({ input: fRead,
}) //按行读取日志
objReadline.on('line', (line)=>{ var itemStr = $.trim(line) var time = itemStr.slice(0,19) var content = itemStr.substr(20) if(!time || !content){return}
++ lineCount //计数行数 var matched = true var itemStr = $.trim(line) var itemArr = itemStr.split(' ') var logDate = itemArr[0] var logTime = itemArr[1] var time = logDate+' '+logTime switch(type){ //进度查找过滤 case '0': case null:
matched = true break case '1': var timeSplit = logTime.slice(0,2) if(timeSplit == hour){
matched = true break
}
matched = false break case '2': var timeSplit = logTime.slice(0,5) if(timeSplit == minute){
matched = true break
}
matched = false break case '3': var timeSplit = logTime.slice(0,8) if(timeSplit == second){
matched = true break
}
matched = false break default: console.log('unkonw type!') break
} if(matched === true &&(lineCount>logReadFlag)){ //日志结果格式化输出呈现
countResult ++ var result = itemArr[2] if(result == 'err'){ var operation = itemArr[4]
result = '失败:'+itemArr[5]+' '+(itemArr[6]?itemArr[6]:'')
}else{ var operation = itemArr[4]+' '+itemArr[5]+(itemArr[6]?itemArr[6]:'')
result = '成功'
}
logStr += '<tr><td>'+time+'</td><td>'+operation+'</td><td>'+result+'</td></tr>'
}
logStr += '<tr><td>'+time+'</td><td>'+content+'</td></tr>'
}) objReadline.on('close', ()=>{ if(logReadFlag == 0 && (logStr == '')){ var info = '无日志信息可供查看'
} if(logReadFlag >0 && (logStr != '')){ var newLogNum = lineCount - logReadFlag var info = '刷新成功,更新'+newLogNum+'条日志!'
$('#logInfoTable').prepend(logStr)
}else if(logReadFlag >0 && (logStr == '')){ var info = '刷新成功,无日志更新!'
}else{
$('#logInfoTable').html(logStr)
} if(op == 'search'){ var info = '查找到'+countResult+'条日志'
}
$('#logTipInfo tr td').html(info) if((op == 'search' || op == 'refresh') &&(logReadFlag != 0 || newLogNum >0 || countResult >0)){
setTimeout(function() {$('#logTipInfo').fadeOut(567)}, 2000) //操作结束后给出信息反馈,反馈自动淡出消失
} else{
$('#logTipInfo').hide()
}
logReadFlag = lineCount console.log('closed')
})
}
})
}
为了完成这点,你会需要使用一个最流行的开发包,叫做 winston. Winston 是一个 Node.js 的多通道异步传输日志库。
你可以通过安装 winston 的方式,添加它到你的项目中:
一旦你安装之后,你可以这样添加 winston 到你的项目:
上面的代码片段会推送接下来的这行信息到 stdout :
如同你所看到的那样,我们传递了 info 字符串到 winston ,从而告诉 winston 这个将要日志的事件有一个日志级别与之关联,也就是 info。默认情况下, winston 附带了接下来的几种日志级别 (也可以添加自定义的级别) :
你可以通过接下来的一行设置日志的级别:
在 RisingStack ,我们通常利用一个叫 LOG_LEVEL 的环境变量来配置。这样的话,我们就可以动态改变哪些内容应该被日志记录:
当你的日志级别是 silly 时,你应该尽可能的多记录所有的日志。尽管如此,你还是需要遵守一个经验法则:绝对不要记录凭证,密码以及任何敏感的信息。
“绝对不要记录凭证,密码以及任何敏感的信息。” via @RisingStack #nodejs #logging #security
点击直达 TWEET
通常来说,会有至少一个以上的用户访问日志,所以,日志事件里面包含凭证信息会增加额外的风险。
当你 开始使用微服务 , 从日志角度来看,最大的挑战就是分布式追踪。
在一个分布式的架构中,错误检测会令人沮丧,因为由于系统的瑕疵会导致大量的警报信息涌现。分布式追踪的目的就是为了消除这个问题,它可以提供更多的事务和错误的视角,而普通的日志文件并没有能力做到这些。
为了做到这点,你不得不使用一个所谓的相关标识符——并且把它传递给所有的参与事务操作的服务。然后,如果每行日志都标注了这个 ID ,你就可以搜索这些事件了。
为了生成一个唯一的 ID ,你可以这样使用 uuid 模块:
这个 ID 不得不在函数调用中传递,并且它也不得不被发送到下游的服务。 如同你可以想象到的,这不是个特别值当的任务。
这里讲到追踪,我们的 Node.js / 微服务监控 解决方案如下图所示。追踪相关的 ID 到请求的容器,并且可视化了一个简单的树状图的数据流。你不会需要去搜索日志,因为它会直接以一种容易理解的方式去展示你的事务:
Node.js distributed tracing with trace by risingstack
根据这种方式, 你可以直接看到你的微服务和持续产生的 issue 之间的依赖关系
如果你实现了我们刚刚讨论的这些方法和工具,Node.js 的日志记录将不再是一件难事。