Node.js+Express+Koa2开发接口学习笔记(五)

日志介绍

日志可以记录系统的日常和错误行为

系统日志有2种类型:

①访问日志access log(server端最重要的日志)

②自定义日志(包括自定义事件、错误记录等)

系统日志通常是写在一个文件中,而不是写进Mysql或者redis中。

nodejs文件操作

新建一个项目file-text

在目录下创建test.js和data.txt(在txt文件中随便添加几句)

读取文件时需要用到fs库和path库,用来读取某个路径下的文件

const fs = require("fs"); // 文件库
const path = require("path"); // 路径库,统一mac和windows的路径形式

// 当前目录的data.txt文件
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);
  }
});

③判断文件是否存在

const exist = fs.existsSync(fileName);
console.log("文件是否存在", exist);

stream操作文件

IO包括“网络IO”和“文件IO”,相比于CPU计算和内存读写,IO的突出特点就是:慢!

如何在有限的硬件资源下提高IO的操作效率?使用stream。

IO操作就是一口气将A桶的水倒入B桶,而stream操作就是通过管道将A桶的水慢慢流入B桶。

// test.js
// 标准输入输出
process.stdin.pipe(process.stdout);

运行node test.js文件,在控制台输入123可以立马看到返回了123。

// 标准输入输出
// process.stdin.pipe(process.stdout);

const http = require("http");
const server = http.createServer((req, res) => {
  if (req.method === "POST") {
    req.pipe(res); // req与res通过pipe建立联系,如果req很大时才会一点一点传过来
  }
});
server.listen(8080);

运行node test.js文件,在postman或者apifox软件请求本地端口8080,在Body输入数据可以看到返回了刚才输入的数据。

有了stream的概念后就可以尝试使用stream操作文件

①复制文件

const fs = require("fs");
const path = require("path");

const fileName1 = path.resolve(__dirname, "data.txt");
const fileName2 = path.resolve(__dirname, "data-bak.txt");

// 读取文件的stream对象
const readStream = fs.createReadStream(fileName1);
// 写入文件的stream对象
const writeStream = fs.createWriteStream(fileName2);
// 执行拷贝,通过pipe
readStream.pipe(writeStream);
// 每次"一点点"读取的数据内容
readStream.on("data", (chunk) => {
  console.log(chunk.toString());
});
// 数据读取完成,即将拷贝完成
readStream.on("end", function () {
  console.log("拷贝完成");
});

②请求读取某个文件内容

const http = require("http");
const fs = require("fs");
const path = require("path");

// 发起请求,读取文件内容
const server = http.createServer(function (req, res) {
  const method = req.method;
  if (method === "GET") {
    const fileName = path.resolve(__dirname, "data.txt");
    const stream = fs.createReadStream(fileName);
    stream.pipe(res);
  }
});
server.listen(8000);

访问端口8000可以看到data.txt的文件内容。

写日志

在blog项目的根目录下创建logs文件夹,该文件夹下分别创建access.log(访问日志)error.log(错误日志)event.log(自定义事件日志)

在src目录中创建utils->logs.js用来对外提供一个可以写入访问日志的方法。

const fs = require("fs");
const path = require("path");
const env = process.env.NODE_ENV; //环境变量

// 写日志
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) {
  // if (env == "dev") {
  //   console.log(log);
  // } else if (env == "production") {
  //   writeLog(accessWriteStream, log);
  // }
  //任何环境都写入访问日志中
  writeLog(accessWriteStream, log);
}
module.exports = {
  access,
};

然后在app.jsseverHandle中使用access方法记录acccess log

const { access } = require("./src/utils/log");

const serverHandle = (req, res) => {
	  // 记录 access log
      access(
        `${req.method} -- ${req.url} -- ${
          req.headers["user-agent"]
        } -- ${Date.now()}`
      );
	...

}

拆分日志

  • 日志内容会慢慢积累,放在一个文件中不好处理
  • 按时间划分日志,如2024-02-08.access.log
  • 实现方式:linux的crontab命令,即定时任务

crontab

  • 设置定时任务,格式:*****command
  • 将access.log拷贝并重命名为2024-02-08.access.log
  • 清空access.log,继续记录日志

简单脚本

由于是windows系统,所以需要下载Git,借助Git Bash执行脚本文件。

使用Git Bash运行pwd命令获取logs目录的路径

在src->utils下创建copy.sh,添加脚本代码

#!/bin/sh
cd /d/MyLearning/myproject/blog-1/logs
cp access.log $(date +%Y-%m-%d).access.log
echo "" > access.log
  • #!/bin/sh脚本文件头
  • cd进入某个目录
  • cp拷贝命令
  • echo "" > access.log清空并赋值给access.log,也就是将原来的access.log内容清空

使用Git Bash运行cd命令进入src下的utils目录,然后执行命令sh copy.sh,就可以在logs下看到2024-02-08.access.log以及内容被清空的access.log文件

由于是windows系统,这里就没法用crontab命令对copy.sh这个脚本文件设置定时任务

日志分析

  • 如针对access.log日志,分析chrome的占比
  • 日志是按行存储的,一行就是一条日志
  • 使用nodejs的readline(基于stream,效率高)

utils文件夹下创建readline.js

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) {
    chromeNum++;
  }
});
// 监听读取完成
rl.on("close", () => {
  console.log("chrome 占比:" + chromeNum / sum);
});

在控制台执行该文件,查看结果。

posted @ 2024-02-08 21:23  小风车吱呀转  阅读(9)  评论(0编辑  收藏  举报