sys/inotify.h を使用する Linux から、kqueues を使用する OS X にログ監視プログラムを移植しています。アイデアは、kqueue がファイル記述子を使用してファイルへの変更を監視することです。ファイルが変更されると、別の関数にファイル ポインターが渡され、ファイルへの変更がスキャンされ、特定のデータが検索されます。元のファイル データは stdout に出力され、スキャン対象のデータは stderr に出力されます。kqueues はログを正常に監視しているように見え、変更ごとに正しいバイト数を返します。正常に動作していないように見えるのはスキャン機能です。
kqueue ループ:
#define BUFLEN 2048
int i, kq, off, rval, fplen;
char *path = "file_to_watch";
FILE *fp;
struct kevent ke_mon, ke_data;
struct stat stats;
fp = fopen(path, "r");
fstat(fileno(fp), &stats);
fplen = stats.st_size;
kq = open(path, O_RDONLY);
EV_SET(&ke_mon, kq, EVFILT_VNODE, EV_ADD, NOTE_DELETE|NOTE_RENAME, 0, path);
EV_SET(&ke_mon, kq, EVFILT_READ, EV_ADD, 0, 0, path);
off = 0;
rval = 0;
while(off < BUFLEN) {
memset(&ke, 0x00, sizeof(ke));
i = kevent(kq, NULL, 0, &ke_data, 1, NULL); // wait indefinitely for log to update
if (i < 0 || ke_data.flags & EV_ERROR)
continue;
if (ke_data.flags & EVFILT_READ)
rval |= LOG_MODIFIED;
if (ke_data.flags & EVFILT_VNODE)
// rval |= LOG_DELETED or LOG_RENAMED, depending on ke_data.fflags
off += ke_data.data;
lseek(kq, ke_data.data, SEEK_CUR); // Update the descriptor's location
}
if (rval & LOG_MODIFIED) {
// check for truncation.
if (truncated) {
// do some stuff
} else {
fplen = scan_log(fp);
}
}
if (rval & (LOG_DELETED|LOG_RENAMED)
// log was moved or renamed (rotation) so we would start over with new log
scan_log 機能:
int scan_log(FILE *fp)
{
char buf[1024];
int ct = 0;
while (fgets(buf, 1024, fp) != NULL {
ct += strlen(buf);
fprintf(stdout, "%s", buf);
for ( some looping construct) {
// Sometimes we don't ever enter this loop. It all depends on if there
// is data we are expecting to see.
// If we are in this loop however, do the following...
// Match data that I'm looking for and print to stderr.
// Print all log data to stdout
}
}
fflush(stdout);
fflush(stderr);
return ct;
}
scan_log の for ループに入らなくても、このプログラムの Linux バージョンから変更されていません。必要でない場合もあります。
何が起こっているかというと、ログから何も出力されず、stderr または stdout に出力されません。fp の位置を監視するために、scan_log の前後に ftell の呼び出しを使用しています。最初は動きますが、その後は動きません。いずれの場合も、データは stdout/stderr に出力されません。
編集: scan_log() コードを更新して、欠落している fprintf 呼び出しを含めました。