日志
- 系统没有日志,等于人没有眼睛
- 访问日志,access log(server端最重要的日志)
- 自定义日志(包括自定义事件,错误记录等)
- nodejs文件操作,nodejs stream
- 日志功能的开发和利用
- 日志的拆分,日志内容分析
文件操作
const fs = require('fs')
const path = require('path')
const fileName = path.resolve(__dirname, 'data.txt')
// // 读取文件内容
// fs.readFile(fileName, (err, data) => {
// if (err) {
// console.error(err)
// return
// }
// // data 是二进制类型,需要转换为字符串
// console.log(data.toString())
// })
// // 写入文件
// const content = '这是新写入的内容\n'
// const opt = {
// flag: 'a' // 追加写入。覆盖用 'w'
// }
// fs.writeFile(fileName, content, opt, (err) => {
// if (err) {
// console.error(err)
// }
// })
// 判断文件是否存在
fs.exists(fileName, (exist) => {
console.log('exist', exist)
})
stream
IO操作性能瓶颈
- IO包括网络IO和文件IO
- 相比于CPU计算和内存读写,IO的突出特点就是慢
- 如何让在有限的硬盘资源下提高IO操作的效率
- 使用stream
使用
// // 标准输入输出
// process.stdin.pipe(process.stdout)
// const http = require('http')
// const server = http.createServer((req, res) => {
// if (req.method === 'POST') {
// req.pipe(res) // 最主要
// }
// })
// server.listen(8000)
// // 复制文件
// const fs = require('fs')
// const path = require('path')
// const fileName1 = path.resolve(__dirname, 'data.txt')
// const fileName2 = path.resolve(__dirname, 'data-bak.txt')
// const readStream = fs.createReadStream(fileName1)
// const writeStream = fs.createWriteStream(fileName2)
// readStream.pipe(writeStream)
// readStream.on('data', chunk => {
// console.log(chunk.toString())
// })
// readStream.on('end', () => {
// console.log('copy done')
// })
const http = require('http')
const fs = require('fs')
const path = require('path')
const fileName1 = path.resolve(__dirname, 'data.txt')
const server = http.createServer((req, res) => {
if (req.method === 'GET') {
const readStream = fs.createReadStream(fileName1)
readStream.pipe(res)
}
})
server.listen(8000)
写日志
写日志工具函数
const fs = require('fs')
const path = require('path')
// 写日志
function writeLog(writeStream, log) {
writeStream.write(log + '\n') // 关键代码
}
// 生成 write Stream
function createWriteStream(fileName) {
const fullFileName = path.join(__dirname, '../', '../', 'logs', fileName)
const writeStream = fs.createWriteStream(fullFileName, {
flags: 'a'
})
return writeStream
}
// 写访问日志
const accessWriteStream = createWriteStream('access.log')
function access(log) {
writeLog(accessWriteStream, log)
}
module.exports = {
access
}
app.js 获取日志
// 记录 access log
access(`${req.method} -- ${req.url} -- ${req.headers['user-agent']} -- ${Date.now()}`)
日志拆分
- 日志内容会慢慢积累,放在一个文件中不好处理
- 按时间划分日志,如 2019-02-20.access.log
- 实现方式:Linux的crontab命令,即定时任务
crontab
-
设置定时任务,格式:* * * * *command
-
将access.log拷贝并重命名为2019-02-10.access.log
-
清空access.log文件,并继续积累日志
copy.sh
#!/bin/sh
cd /Users/wfp/Project/video-tutorial/node-tutorial/code-demo/blog-1/logs
cp access.log $(date +%Y-%m-%d).access.log
echo "" > access.log
linux命令
-
crontab -e开始编辑 -
写入
* 0 * * * sh copy.sh路径/copy.sh -
crontabe -l执行
日志分析
- 如针对access.log日志,分析chrome的占比
- 日志时按行存储的,一行就是一条日志
- 使用nodejs的readline(基于stream,效率高)
使用readline
const fs = require('fs')
const path = require('path')
const readline = require('readline')
// 文件名
const fileName = path.join(__dirname, '../', '../', 'logs', 'access.log')
// 创建 read stream
const readStream = fs.createReadStream(fileName)
// 创建 readline 对象
const rl = readline.createInterface({
input: readStream
})
let chromeNum = 0
let sum = 0
// 逐行读取
rl.on('line', (lineData) => {
if (!lineData) {
return
}
// 记录总行数
sum++
const arr = lineData.split(' -- ')
if (arr[2] && arr[2].indexOf('Chrome') > 0) {
// 累加 chrome 的数量
chromeNum++
}
})
// 监听读取完成
rl.on('close', () => {
console.log('chrome 占比:' + chromeNum / sum)
})