【问题标题】:Is fs.watch() broken in Node v13 or am I doing something wrong?fs.watch() 在 Node v13 中是否损坏或者我做错了什么?
【发布时间】:2020-06-08 17:05:05
【问题描述】:

我一直在尝试设置一个文件观察器来检测何时将新数据添加到文件中。一般顺序是 1.) 客户端连接到服务器。 2.)服务器日志到文件。 3.) fs.watch() 检测到文件已更改并运行一个函数,在这种情况下是一个简单的console.log('New log entry')

除了fs.watch() 没有检测到新消息何时添加到日志文件之外,一切似乎都正常。但是,如果我单击 VScode 中的日志文件,它似乎会触发它。这是较新版本的 Node 中的错误还是我在这里做错了什么?

我意识到我可以使用fs.watchFile(),但我希望避免轮询的开销......

// src/index.js
const path = require('path');
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io')(server);
const logger = require('./logger');
const fs = require('fs');

fs.watch('./logs/combined.log', (event) => {
  if (event === 'change') {
    console.log('New log entry');
  }
});

app.use(express.static(path.join(__dirname, '../public')));
app.get('/', function(req, res, next) {
  res.sendFile(path.join(__dirname, '../public', 'index.html'));
});

io.on('connection', function(socket) {
  logger.info('a user connected');
});

const PORT = process.env.PORT || 8888;

server.listen(PORT, () => {
  logger.info(`Listening at http://localhost:${port}`);
});

-

// src/logger.js
const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'logs/combined.log' })
  ]
});

module.exports = logger

-

// public/index.html
<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost:8888');
</script>

-

// simplified test
const logger = require('./logger');
const fs = require('fs');

fs.watch('./logs/combined.log', event => {
  if (event === 'change') {
    console.log('log file has updated');
  }
});

function intervalFunc() {
  logger.info('new log message');
}
setInterval(intervalFunc, 5000);

【问题讨论】:

  • 如果你想要简单和一致的东西,你应该查看chokidar 它被微软的 Visual Studio Code、gulp、karma、PM2、browserify、webpack、BrowserSync 等使用。
  • I just tested this 看起来你甚至可以从你的主应用程序中启动子进程......我想知道套接字是否搞砸了?我在 Mac 上测试了这个。
  • 很好,我去看看。我还在原始帖子中添加了一个简化测试,您可以尝试看看您是否有问题?我仍然认为 fs.watch() 有点奇怪,但我可能疯了
  • 嘿,对不起,我昨晚不得不去睡觉,这样我才能起床工作。你有没有解决这个问题?如果没有,您能否提供您在该最小示例中使用的package.json 文件?我想测试一下。
  • 干得好!可能想在 Winstons GitHub 上打开一个问题。如果问题仅在您将 Winston 添加到我创建的演示后才开始发生,则 Def 听起来像是 Winston 的问题(证明 Winston 是破坏它的原因)。随意参考我的演示制作并告诉他们添加 Winston 后演示中断(Winston 写入日志而不触发文件观察器).. 祝你好运!干杯。我应该提一下,我确实搜索了他们的未解决问题和已关闭问题,但找不到与此问题相关的问题,所以我认为没有人已经为此提出问题。

标签: javascript node.js express fs winston


【解决方案1】:

fs.watch 的节点文档有一个完整的 Caveats 部分,一开始就说明:

fs.watch API 并非 100% 跨平台一致,而是 在某些情况下不可用。

您应该阅读该部分以了解更多信息,但如果您无法让 fs.watch 为您可靠地工作,您最终可能不得不使用 fs.watchfile

[更新]

Caveats 部分的 Filename Argument 小节也说明了这一点:

即使在受支持的平台上,filename 也不一定总是 假如。因此,不要假设 filename 参数总是 在回调中提供,如果是null,则有一些回退逻辑。

由于您不需要使用 filename 参数(而且您已经知道文件名),因此您的回调不应测试真实的 filename 参数。

【讨论】:

  • 谢谢,我已阅读文档,并且“在某些情况下不可用”非常含糊。我在 Windows 机器上。我正在寻找的是代码是否存在问题,或者这是否属于不可用的“某些情况”部分。
  • 查看我的更新答案,以防万一。是的,文档有点模糊,但是在各种文件系统中支持这个特性真的很难,而且很难完整地记录下来。
  • 感谢您的更新。我不确定为什么该检查存在,但删除它后,它没有帮助。正在将日志写入日志文件,但仍未检测到文件更改。
  • 如果我打开日志文件是 VScode 并直接在其中键入,则会检测到更改,但是当 Winston 写入文件时,直到我打开文件才检测到它...不确定这是否有助于缩小什么都下来了。
【解决方案2】:

更新:

所以它@98​​7654321@。这些监听器的行为类似于文件监听器,并允许您挂钩某些事件。您可以挂钩的事件之一称为“数据” - 这使您可以监听数据何时写入文件,并运行回调函数。

这提供了与file.watch 类似的行为。

它们允许您监听以下事件:

  • 关闭
  • 数据
  • 结束
  • 错误
  • 可读

我在 Windows 上进行了测试,它运行良好。

这是我正在使用的测试文件:

const winston = require('winston');

const { createLogger, format: { json }, transports: { File } } = winston;

const logger = createLogger({
  level: 'info',
  format: json(),
  transports: [
    new File({ filename: './log.txt' })
  ],  
});

/**
 * Added a built in Winston listener
 */
logger.addListener('data', chunk => {
    console.log('\r\n[winston listener] we have logged some data:\n', chunk)
})

/**
 * Their documentation seems to use the `.on` method.
 * 
 * This appears to provide the same type of behavior that `.addListener` does.
 * 
 * I'm not sure which is best, or recommended, `.addListener` or `.on` - you
 * may want to dig deeper into that.
 */
logger.on('data', chunk => {
    console.log('\r\n[winston on "data"] we have logged some data:\n', chunk);
});

setInterval(() => {
  logger.info('new log message');
}, 5000);

所以我一直在考虑这个问题,起初我认为这是因为 Winston 使用写入流来更新文件..

然后我继续尝试复制您的问题,但我无法复制它。

每次更新日志文件时,都会向控制台写入一条消息(意味着fs.watch 正在工作。

您使用的是 Windows 吗?您使用的是哪个版本的 Node?​​p>

这是我正在使用的测试文件:

const winston = require('winston');
const fs = require('fs');

const { createLogger, format: { json }, transports: { File } } = winston;

const logger = createLogger({
  level: 'info',
  format: json(),
  transports: [
    new File({ filename: './log.txt' })
  ]
});

fs.watch('./log.txt', event => { 
  if (event === 'change') {
    console.log('log file has updated');
  }
});

setInterval(() => {
  logger.info('new log message');
}, 5000);

【讨论】:

  • 我在 Windows 10 上使用我的工作电脑上的 Node v13.9.0 和我的个人电脑上的 Node v13.7.0,两者都存在同样的问题。我可以录制一个快速截屏,以便在今天晚些时候进行演示。当我打开日志文件时,它唯一一次将它打印到控制台(我猜是因为访问文件会更改元数据或触发更改事件的东西?)我将在今天晚些时候回家时链接到一个视频示例。
  • 我能够在 Windows 上进行测试(它在 Mac 上为我工作),我现在遇到了同样的问题。我确实注意到,当我物理单击文件时,它会写入控制台。我个人认为这与 Winston 如何使用流写入文件有关。
  • @HexxNine 所以我相信我已经想出办法了,这给了您与file.watch 相同的行为。我已使用此信息更新了我的答案 - 请查看并告诉我您的想法。
  • 干得好,马特!它工作得很好。它出现的平台之间肯定存在一些不一致之处。感谢您解决这个问题,非常感谢!
猜你喜欢
  • 2020-01-06
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多