Help us understand the problem. What is going on with this article?

Node.js - chokidar と forever でファイルとディレクトリの変更を検知してログする

More than 1 year has passed since last update.

はじめに

特定のOSに依存せず、特定のディレクトリ内の変更を検知して処理を実行するプログラムを実装したかったので調査しました。
Electron の導入まで考えましたが、 Node.js だけで実現出来そうだったので、コアとなる処理を実装した時のメモをまとめます。

作るもの

今回の実装するアプリケーションの概要をまとめます。

前提条件

前提として、以下の npmnode がインストール済みであるものとします。

command_powershell
> node -v
v10.16.0

> npm -v
6.10.1

動作仕様

今回のアプリケーションは次のような構成で動作することを想定します。

image.png

アプリケーションは次のような機能を持ちます。

  • デバッグの際は、 node watch.js で起動します。
  • 実際の運用では、 forever start watch.js で起動します。
  • ファイルの変更検知は chokidar を使用します。
  • 変更検知する対象ディレクトリ複数の異なるディレクトリ です。
  • 「ファイル」と「ディレクトリ」の両方を変更検知(作成、更新、削除)の対象とします。
  • 変更の情報はログ出力します。

実装

実装に関する情報をまとめます。

バージョン

関連モジュールのバージョンは次の通りです。

  • node : v10.16.0
  • npm : 6.10.1
  • chokidar : 3.0.2
  • fs : 0.0.1-security
  • forever : 1.0.0

初期設定

まず、リポジトリを作成し、必要なモジュールをインストールします。

command_bash
# プロジェクトフォルダの作成
> mkdir node-app && cd $_

# リポジトリの初期化
> npm init -y

# 関連モジュールのインストール
> npm install --save chokidar
> npm install fs

# Global Install.
> sudo npm install -g forever

最終的には次のようなディレクトリ構成になります。
矢印で示した資源は自分で作成します。

command_bash
> tree -L 2
node-app
  ├── data               <-- 監視対象のディレクトリ(1)
  ├── data-002           <-- 監視対象のディレクトリ(2)
  ├── node_modules
  ├── package-lock.json
  ├── package.json
  └── watch.js           <-- アプリケーション本体

コード

完成版のコードは次の通りです。
記載内容はほとんど「paulmillr/chokidar - GitHub」の README.md の通りです。

watch.js
// require
var chokidar = require("chokidar");

// Constants
// ________________________________
// Monitoring Target Directory
const target_directory_01 = 'data/';
const target_directory_02 = 'data-001/';

// Something to use when events are received.
const log = console.log.bind(console);

// Initialize
// ________________________________
// initialize chokidar
var watcher = chokidar.watch(target_directory_01, {
    ignored: /[\/\\]\./,
    persistent: true
});
// Add monitoring target.
watcher.add(target_directory_02);

// Monitoring
// ________________________________
// Ready for changes
watcher.on('ready', function () {

    // ready
    log('Initial scan complete. Ready for changes');

    // watched Paths
    var watchedPaths = watcher.getWatched();
    log("watchedPaths :", watchedPaths);

    // Files
    // _ _ _ _ _ _ _ _ _ _ _ _ _ _
    // Detect File added
    watcher.on('add', function (path, stats) {
        log(`File ${path} has been added`);
        if (stats) console.log(`File ${path} changed size to ${stats.size}`, stats);

        var watchedPaths = watcher.getWatched();
        log("watchedPaths :", watchedPaths);
    });

    // Detect File changed
    watcher.on('change', function (path, stats) {
        log(`File ${path} has been changed`);
        if (stats) console.log(`File ${path} changed size to ${stats.size}`, stats);
    });

    // Detect File removed
    watcher.on('unlink', function (path) {
        log(`File ${path} has been removed`);
    });

    // Directories
    // _ _ _ _ _ _ _ _ _ _ _ _ _ _
    // Detect Directory added
    watcher.on('addDir', function (path) {
        log(`Directory ${path} has been added`);
    });

    // Detect Directory removed
    watcher.on('unlinkDir', function (path) {
        log(`Directory ${path} has been removed`);
    });

    // Error
    // _ _ _ _ _ _ _ _ _ _ _ _ _ _
    // Detect Watcher Error
    watcher.on('error', function (path) {
        log(`Watcher error: ${error}`);
    });

});

cf. paulmillr/chokidar - GitHub

デバッグ

動作確認は次のように行います。
node watch.js でアプリケーションを起動したら、監視対象のフォルダ配下で適当な操作をしてみましょう。

command_bash
> node watch.js
Initial scan complete. Ready for changes
watchedPaths : {}

Directory data/新しいフォルダー has been added    <-- ディレクトリの追加

Directory data/新しいフォルダー has been removed  <-- ディレクトリの削除

File data/test - コピー.txt has been added       <-- ファイルの追加
File data/test - コピー.txt added size to 5 Stats {     <-- ファイル追加結果
  dev: 12,
  mode: 33279,
  nlink: 1,
  uid: 1000,
  gid: 1000,
  rdev: 0,
  blksize: 512,
  ino: 13510798882489840,
  size: 5,
  blocks: 0,
  atimeMs: 1563174366871.4685,
  mtimeMs: 1563173471128.5984,
  ctimeMs: 1563173471128.5984,
  birthtimeMs: 1563173471128.5984,
  atime: 2019-07-15T07:06:06.871Z,
  mtime: 2019-07-15T06:51:11.129Z,
  ctime: 2019-07-15T06:51:11.129Z,
  birthtime: 2019-07-15T06:51:11.129Z }

File data/test.txt has been changed       <-- ファイルの更新
File data/test.txt changed size to 0 Stats {     <-- ファイル更新結果
  dev: 12,
  mode: 33279,
  nlink: 1,
  uid: 1000,
  gid: 1000,
  rdev: 0,
  blksize: 512,
  ino: 45598946227504590,
  size: 0,
  blocks: 0,
  atimeMs: 1563171389606.2122,
  mtimeMs: 1563174613548.453,
  ctimeMs: 1563174613548.453,
  birthtimeMs: 1563174613548.453,
  atime: 2019-07-15T06:16:29.606Z,
  mtime: 2019-07-15T07:10:13.548Z,
  ctime: 2019-07-15T07:10:13.548Z,
  birthtime: 2019-07-15T07:10:13.548Z }

File data/test_001.txt has been removed       <-- ファイルの削除

起動

forever を使用した起動は次のようにします。

command_bash
# forever による起動
> forever start watch.js
warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: watch.js

# forever で起動しているプロセスの一覧
> forever list
info:    Forever processes running
data:        uid  command             script   forever pid id logfile                           uptime
data:    [0] UML_ /usr/local/bin/node watch.js 291     298    /home/user/.forever/UML_.log 0:0:0:22.141

# ログの確認
# `forever list` で出力される `logfile` を `tail -f` した方が便利かもしれない。
> forever logs watch.js

# foreverで起動したアプリの停止
> forever stop watch.js
info:    Forever stopped process:
    uid  command             script   forever pid id logfile                           uptime
[0] UML_ /usr/local/bin/node watch.js 291     298    /home/user/.forever/UML_.log 0:0:10:19.34400000000005

まとめ

想定していた以上に、簡単に実装することが出来ました。

関連情報を調査すると、2016年前後の記事が多く、2018~2019年の情報が少なかったのですが、他にメジャーなやり方などがあるかもしれません。

参考

今回の記事で参考にしたサイトを記載します。

chokidar

forever

Windows

anfangd
Web Application Developer
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした