欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Nodejs监听日志文件的变化的过程解析

程序员文章站 2022-07-05 12:06:17
最近有在做日志文件的分析,其中有一个需求:a服务器项目需要用nodejs监听日志文件的变化,当项目产生了新的日志信息,将新的部分通过socket传输到b服务器项目。sock...

最近有在做日志文件的分析,其中有一个需求:a服务器项目需要用nodejs监听日志文件的变化,当项目产生了新的日志信息,将新的部分通过socket传输到b服务器项目。socket暂时不做分析。

这个需求很简单,通过分析我们开始撸码吧。 在撸码的过程中还能巩固所学nodejs的api,何乐而不为呢?

所用的api

fs.watchfile()

语法

fs.watchfile(filename[, options], listener)

参数解析

filename <string> | <buffer> | <url> ——文件名
options <object>

 persistent <boolean> 默认值: true。——是否应该继续运行
 interval <integer> 默认值: 5007。——轮询目标的频率
listener <function>

 current <fs.stats> ——当前值
 previous <fs.stats> ——之前值

监视 filename 的更改。 每当访问文件时都会调用 listener 回调。

listener 有两个参数,当前的 stat 对象和之前的 stat 对象

这些 stat 对象是 fs.stat 的实例。

要在修改文件(而不仅仅是访问)时收到通知,则需要比较 curr.mtime 和 prev.mtime。

当 fs.watchfile 操作导致 enoent 错误时,它将调用一次监听器,并将所有字段置零(或将日期设为 unix 纪元)。 如果文件是在那之后创建的,则监听器会被再次调用,且带上最新的 stat 对象。 这是 v0.10 之后的功能变化。

使用 fs.watch() 比 fs.watchfile fs.unwatchfile 更高效。 应尽可能使用 fs.watch 代替 fs.watchfile 和 fs.unwatchfile。

当 fs.watchfile() 正在监视的文件消失并重新出现时,第二次回调事件(文件重新出现)返回的 previousstat 会与第一次回调事件(文件消失)返回的 previousstat 相同。

这种情况发生在:

  • 文件被删除,然后又恢复。
  • 文件被重命名两次,且第二次重命名回其原来的名称。

例子

fs.watchfile('message.text', (curr, prev) => {
 console.log(`当前的最近修改时间是: ${curr.mtime}`);
 console.log(`之前的最近修改时间是: ${prev.mtime}`);
});

fs.open()

语法

fs.open(path[, flags[, mode]], callback)

参数解析

path <string> | <buffer> | <url> ——文件路径
flags <string> | <number> 默认值: 'r'。——文件系统标志
mode <integer> 默认值: 0o666(可读写)。——设置文件模式(权限和粘滞位),但仅限于创建文件的情况
callback <function>

 err <error> ——错误
 fd <integer>——文件系统流

fs.read()

语法

fs.read(fd, buffer, offset, length, position, callback)

参数解析

fd <integer> ——文件系统流
buffer <buffer> | <typedarray> | <dataview>——数据将写入的缓冲区
offset <integer>—— buffer 中开始写入的偏移量
length <integer>——要读取的字节数
position <integer>——从文件中开始读取的位置
callback <function>

 err <error>
 bytesread <integer>
 buffer <buffer>

fs.createreadstream()

语法

fs.createreadstream(path[, options])

参数解析

path <string> | <buffer> | <url>——文件路径
options <string> | <object>

 flags <string> 默认值: 'r'。——文件系统标志
 encoding <string> 默认值: null。——字符编码
 fd <integer> 默认值: null。——文件系统流
 mode <integer> 默认值: 0o666。——设置文件模式(权限和粘滞位),但仅限于创建文件的情况
 autoclose <boolean> 默认值: true。——是否自动关闭文件描述符
 start <integer>——文件读取的开始位置
 end <integer> 默认值: infinity。——文件读取的结束位置
 highwatermark <integer> 默认值: 64 * 1024。

返回: <fs.readstream> 参阅可读流。

如果 autoclose 为 false,则即使出现错误,也不会关闭文件描述符。 应用程序负责关闭它并确保没有文件描述符泄漏。 如果 autoclose 设为 true(默认行为),则在 'error' 或 'end' 事件时将自动关闭文件描述符。

mode 用于设置文件模式(权限和粘滞位),但仅限于创建文件的情况。

例子

读取sample.txt文件的10个字符

fs.createreadstream('sample.txt', { start: 90, end: 99 });

readline.createinterface

语法

readline.createinterface(options)

参数解析

options <object>

  input <stream.readable> 要监听的可读流。此选项是必需的。
  output <stream.writable> 将逐行读取数据写入的可写流。
  completer <function> 用于 tab 自动补全的可选函数。
  terminal <boolean> 如果 input 和 output 应该被视为 tty,并且写入 ansi/vt100 转义码,则为 true。 默认值: 实例化时在 output 流上检查 istty。
  historysize <number> 保留的最大历史记录行数。 要禁用历史记录,请将此值设置为 0。 仅当用户或内部 output 检查将 terminal 设置为 true 时,此选项才有意义,否则根本不会初始化历史记录缓存机制。 默认值: 30。
  prompt - 要使用的提示字符串。默认值: '> '。
  crlfdelay <number> 如果 \r 与 \n 之间的延迟超过 crlfdelay 毫秒,则 \r 和 \n 将被视为单独的行尾输入。  crlfdelay 将被强制转换为不小于 100 的数字。 可以设置为 infinity, 这种情况下, \r 后跟 \n 将始终被视为单个换行符(对于使用 \r\n 行分隔符的文件读取可能是合理的)。 默认值: 100。
  removehistoryduplicates <boolean> 如果为 true, 则当添加到历史列表的新输入行与旧的输入行重复时,将从列表中删除旧行。 默认值: false。
  escapecodetimeout <number> readline 将会等待一个字符的持续时间(当以毫秒为单位读取模糊键序列时,可以使用输入读取到目前为止形成完整的键序列,并且可以采取额外的输入来完成更长的键序列)。 默认值: 500。


这个不需要司机,记住常见的即可,需要的时候查找。

当 flag 选项采用字符串时,可用以下标志:

'a' - 打开文件用于追加。如果文件不存在,则创建该文件。

'ax' - 与 'a' 相似,但如果路径已存在则失败。

'a+' - 打开文件用于读取和追加。如果文件不存在,则创建该文件。

'ax+' - 与 'a+' 相似,但如果路径已存在则失败。

'as' - 以同步模式打开文件用于追加。如果文件不存在,则创建该文件。

'as+' - 以同步模式打开文件用于读取和追加。如果文件不存在,则创建该文件。

'r' - 打开文件用于读取。如果文件不存在,则出现异常。

'r+' - 打开文件用于读取和写入。如果文件不存在,则出现异常。

'rs+' - 以同步模式打开文件用于读取和写入。指示操作系统绕过本地的文件系统缓存。

这对于在 nfs 挂载上打开文件时非常有用,因为它允许跳过可能过时的本地缓存。 它对 i/o 性能有非常实际的影响,因此除非需要,否则不建议使用此标志。

这不会将 fs.open() 或 fspromises.open() 转换为同步的阻塞调用。 如果需要同步的操作,则应使用 fs.opensync() 之类的。

'w' - 打开文件用于写入。如果文件不存在则创建文件,如果文件已存在则截断文件。

'wx' - 与 'w' 相似,但如果路径已存在则失败。

'w+' - 打开文件用于读取和写入。如果文件不存在则创建文件,如果文件已存在则截断文件。

'wx+' - 与 'w+' 相似,但如果路径已存在则失败。

fs.stats 类

fs.stats 对象提供有关文件的信息。

stats {
 dev: 2114,
 ino: 48064969,
 mode: 33188,
 nlink: 1,
 uid: 85,
 gid: 100,
 rdev: 0,
 size: 527,
 blksize: 4096,
 blocks: 8,
 atimems: 1318289051000.1,
 mtimems: 1318289051000.1,
 ctimems: 1318289051000.1,
 birthtimems: 1318289051000.1,
 atime: mon, 10 oct 2011 23:24:11 gmt,
mtime: mon, 10 oct 2011 23:24:11 gmt,
  ctime: mon, 10 oct 2011 23:24:11 gmt,
  birthtime: mon, 10 oct 2011 23:24:11 gmt }

 开始监听日志文件

前提,在app.js中调用watchfile方法,将需要监听的文件路径传入该方法中。

function watchfile(filename) {
 console.log('log monitoring...');
 // open the file for reading and appending
 fs.open(filename, 'a+', function (err, fd) {
 if (err) {
  throw err;
 }
 var buffer;
 fs.watchfile(filename, {
  persistent: true,
  interval: 1000
 }, (curr, prev) => {
  // compare the time before and after
  if (curr.mtime > prev.mtime) {
  // console.log(`the current latest revision time is: ${curr.mtime}`);
  // console.log(`the latest modification time is: ${prev.mtime}`);

  // changes in the contents of documents
  buffer = new buffer(curr.size - prev.size);
   // (curr.size - prev.size) this is the newly added length of the log file
  readfile(fd, buffer, (curr.size - prev.size), prev.size);
  }
 });
 });

}

读取新增内容

function readfile(fd, buffer, length, position) {
 // read file
 fs.read(fd, buffer, 0, length, position, function (err, bytesread, buffer) {
 if (err) {
  log.error(err);
 }
 console.log('additional contents', buffer.tostring());
 });
}

额外功能:读取历史内容

function fetchhistorylogs(filename) {
 const rl = readline.createinterface({
 input: fs.createreadstream(filename, {
  enconding: 'utf8'
 }),
 output: null,
 terminal: false
 });

 rl.on('line', (line) => {
 if (line) {
  logsarr.push(line.tostring());
 }
 }).on('close', () => {
 for (var i = 0; i < logsarr.length; i++) {
  // print the data for each row
  console.log(`original data: \n ${logsarr[i]}`);
 }
 });
}

总结

以上所述是小编给大家介绍的nodejs监听日志文件的变化的过程解析,希望对大家有所帮助