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

Source Code

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

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

One thought to “How to watch file for changes in Node.js”

Leave a Reply

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