node.js博客学习之博客日志

460 阅读2分钟

日志

  • 系统没有日志,等于人没有眼睛
  • 访问日志,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)
})