日志介绍
日志可以记录系统的日常和错误行为
系统日志有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.js
的severHandle
中使用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);
});
在控制台执行该文件,查看结果。
标签:fs,const,log,Express,接口,access,Koa2,path,日志 From: https://www.cnblogs.com/Small-Windmill/p/18012146