How to watch file for changes in Node.js

In the previous post, we’ve known how to watch folder for changes. This tutorial comes with another approach, we won’t listen to a folder with adding file event, read & delete the file. We’re gonna watch file for its changes in Node.js, for example: read the latest line at the time it is added to the file.

Related post: How to watch folder for changes in Node.js

Overview

Watch file for changes in Node.js

We’re gonna create a service working independently of the main project (that updates the log file).

The main project Performance will randomly add a line to the end of info.log file in logs folder.

So what we will do is watching the info.log file: If any line is added to info.log, read & show it.

This is the structure for our example:

nodejs-watch-file-changes-project-structure

Way to watch file for changes

How do we build a service to work for this process?
In previous post, we’ve known that we can use fs.watch, fs.watchFile from Node.js fs module to watch changes of a file, its disadvantages and a new solution: using chokidar module.

We continue to use chokidar module to create a watcher in this tutorial.
Again, I want to show you the overview of chokidar API:

const chokidar = require('chokidar');

// Initialize watcher.
const watcher = chokidar.watch('path/to/folder', { persistent: true });
 
// Add event listeners.
watcher
  .on('add', path => log(`File ${path} has been added`))
  .on('change', path => log(`File ${path} has been changed`))
  .on('unlink', path => log(`File ${path} has been removed`));
 
// More possible events.
watcher
  .on('addDir', path => log(`Directory ${path} has been added`))
  .on('unlinkDir', path => log(`Directory ${path} has been removed`))
  .on('error', error => log(`Watcher error: ${error}`))
  .on('ready', () => log('Initial scan complete. Ready for changes'))

Next, we use read-last-lines module for reading the last line of a file:

const readLastLines = require('read-last-lines');

readLastLines.read('path/to/file', 42) // read last 42 lines
    .then((lines) => console.log(lines));

Practice

Setup Node.js modules

We need to install 2 packages: chokidar and read-last-lines.
So run the command:
npm install chokidar read-last-lines

Create Service for watching folder

Under services folder, create obserser.js file:

const chokidar = require('chokidar');
const EventEmitter = require('events').EventEmitter;
const readLastLines = require('read-last-lines');

class Observer extends EventEmitter {
  constructor() {
    super();
  }

  watchFile(targetFile) {
    try {
      console.log(
        `[${new Date().toLocaleString()}] Watching for file changes on: ${targetFile}`
      );

      var watcher = chokidar.watch(targetFile, { persistent: true });

      watcher.on('change', async filePath => {
        console.log(
          `[${new Date().toLocaleString()}] ${filePath} has been updated.`
        );

        // Get update content of file, in this case is one line
        var updateContent = await readLastLines.read(filePath, 1);

        // emit an event when the file has been updated
        this.emit('file-updated', { message: updateContent });
      });
    } catch (error) {
      console.log(error);
    }
  }
}

module.exports = Observer;

Everything is simple:
– import necessary module: chokidar, events, read-last-lines.
– define Observer class that extends EventEmitter which can emit event (emit() method) and listen to event (on() method).
– create watcher variable using chokidar.watch() function. {persistent: true} indicates whether the process should continue to run as long as files are being watched.
watcher.on('change') is the event listener for a file changed event.
– in the handler, we use readLastLines() to read the last line of the file, emit 'file-updated' event with the content as message.
– export Observer module.

Use Observer object

Now we create server.js:

const Obserser = require('./services/observer');

var obserser = new Obserser();

const file = 'Performance/logs/info.log';

obserser.on('file-updated', log => {
  console.log(log.message);
});

obserser.watchFile(file);

What we do:
– import Observer class and initialize observer object.
– use on() method to listen 'file-updated' event. In the handler, you can do anything such as: push alert message to chatwork, slack…
– call watchFile() function.

Check result

On the project root folder, run this command:
node src/server.js

The console shows:

[8/29/2019, 10:22:35 PM] Watching for file changes on: Performance/logs/info.log

Now we add a new line to info.log file, "new information here" for example. Console will immediately show:

[8/29/2019, 10:24:36 PM] Performance/logs/info.log has been updated.
new information here

Conclusion

Today we’ve learned another way to listen/watch a file for changes by solving the real world problem: get the last line immediatly when it is added.

With the previous post: How to watch folder for changes in Node.js, we hope you have more ways to work with folder/file changes.

Happy learning! See you again.

Further Reading

Source Code

You can find the complete source code for this example on Github.

2 thoughts to “How to watch file for changes in Node.js”

  1. Hi.
    Thanks for this great article. I need to monitor a directory for new log files created or added. this part is fine. i need my react app to receive this info real time. what would be the best way to do this? is send server event the best method to send new log aaded event to react app? is there any other best way to do it?

Leave a Reply

Your email address will not be published. Required fields are marked *