/** * Simple tail program using the inotify extension * Usage: ./tail.php file */ function main_loop($file, $file_fd) { $inotify = inotify_init(); if ($inotify === false) { fprintf(STDERR, "Failed to obtain an inotify instance\n"); return 1; } $watch = inotify_add_watch($inotify, $file, IN_MODIFY); if ($watch === false) { fprintf(STDERR, "Failed to watch file '%s'", $file); return 1; } while (($events = inotify_read($inotify)) !== false) { echo "Event received !\n"; foreach ($events as $event) { if (!($event['mask'] & IN_MODIFY)) { continue; } echo stream_get_contents($file_fd); break; } } // May not happen inotify_rm_watch($inotify, $watch); fclose($inotify); fclose($file_fd); return 0; }
function tail($file, &$pos) { // get the size of the file if (!$pos) { $pos = filesize($file); } // Open an inotify instance $fd = inotify_init(); // Watch $file for changes. $watch_descriptor = inotify_add_watch($fd, $file, IN_ALL_EVENTS); // Loop forever (breaks are below) while (true) { // Read events (inotify_read is blocking!) $events = inotify_read($fd); // Loop though the events which occured foreach ($events as $event => $evdetails) { // React on the event type switch (true) { // File was modified case $evdetails['mask'] & IN_MODIFY: // Stop watching $file for changes inotify_rm_watch($fd, $watch_descriptor); // Close the inotify instance fclose($fd); // open the file $fp = fopen($file, 'r'); if (!$fp) { return false; } // seek to the last EOF position fseek($fp, $pos); // read until EOF while (!feof($fp)) { $buf .= fread($fp, 8192); } // save the new EOF to $pos $pos = ftell($fp); // (remember: $pos is called by reference) // close the file pointer fclose($fp); // return the new data and leave the function return $buf; break; // File was moved or deleted // File was moved or deleted case $evdetails['mask'] & IN_MOVE: case $evdetails['mask'] & IN_MOVE_SELF: case $evdetails['mask'] & IN_DELETE: case $evdetails['mask'] & IN_DELETE_SELF: // Stop watching $file for changes inotify_rm_watch($fd, $watch_descriptor); // Close the inotify instance fclose($fd); // Return a failure return false; break; } } } }
/** * Clear all watching. * * @return void */ public function clearWatch() { foreach ($this->watchDir as $wd) { inotify_rm_watch($this->inotify, $wd); } $this->watchDir = []; }
public function start() { $this->stop = false; $fd = inotify_init(); $wd = inotify_add_watch($fd, $this->path, IN_ALL_EVENTS); $read = [$fd]; $write = null; $except = null; stream_select($read, $write, $except, 0); stream_set_blocking($fd, 0); while (true) { if ($this->stop) { inotify_rm_watch($fd, $wd); return fclose($fd); } if ($events = inotify_read($fd)) { foreach ($events as $details) { if ($details['name']) { $target = rtrim($this->path, '/') . '/' . $details['name']; } else { $target = $this->path; } $file = new \SplFileInfo($target); switch (true) { case $details['mask'] & IN_MODIFY: $this->modify($file); break; } $this->all($file); } } } }
/** * remove/cancel the given watch identifier previously aquired via add() * i.e. stop watching the associated path * * @param integer $descriptor watch identifier previously returned from add() */ public function remove($descriptor) { if (isset($this->watchDescriptors[$descriptor])) { unset($this->watchDescriptors[$descriptor]); if ($this->watchDescriptors) { // there are still watch paths remaining => only remove this descriptor \inotify_rm_watch($this->inotifyHandler, $descriptor); } else { // no more paths watched => close whole handler $this->close(); } } }
function deleteFiles() { $tmps = scandir($this->path); foreach ($this->filenames as $file) { if (!in_array($file, $tmps)) { unset($this->filenames[$file]); inotify_rm_watch($this->ifds[$file], $this->wds[$file]); unset($this->ifds[$file]); unset($this->wds[$file]); fclose($this->fds[$file]); unset($this->fds[$file]); unset($this->pos[$file]); } } }
/** * Cancels your subscription on object in FS * @param string $path Path * @param mixed $cb Callback * @return boolean */ public function rmWatch($path, $cb) { $path = realpath($path); if (!isset($this->files[$path])) { return false; } if (($k = array_search($cb, $this->files[$path], true)) !== false) { unset($this->files[$path][$k]); } if (sizeof($this->files[$path]) === 0) { if ($this->inotify) { if (($descriptor = array_search($path, $this->descriptors)) !== false) { inotify_rm_watch($this->inotify, $cb); } } unset($this->files[$path]); } return true; }
<?php // Open an inotify instance $fd = inotify_init(); // Watch __FILE__ for metadata changes (e.g. mtime) $watch_descriptor = inotify_add_watch($fd, __FILE__, IN_ATTRIB); // generate an event touch(__FILE__); // Read events $events = inotify_read($fd); print_r($events); // The following methods allows to use inotify functions without blocking on inotify_read(): // - Using stream_select() on $fd: $read = array($fd); $write = null; $except = null; stream_select($read, $write, $except, 0); // - Using stream_set_blocking() on $fd stream_set_blocking($fd, 0); inotify_read($fd); // Does no block, and return false if no events are pending // - Using inotify_queue_len() to check if event queue is not empty $queue_len = inotify_queue_len($fd); // If > 0, inotify_read() will not block // Stop watching __FILE__ for metadata changes inotify_rm_watch($fd, $watch_descriptor); // Close the inotify instance // This may have closed all watches if this was not already done fclose($fd);
/** * Unwatch resource * * @param int $id Watch descriptor */ protected function unwatch($id) { @inotify_rm_watch($this->bag->getInotify(), $id); }
/** * 删除某个文件的监控 * @param string $file */ public static function delFile($file) { return inotify_rm_watch(self::$inotifyFd, $file); }
/** * Monitor the paths for any changes based on the modify time information. * When a change is detected, all listeners are invoked, and the list of * paths is once again traversed to acquire updated modification timestamps. */ private function watchInotify() { if (($eventList = inotify_read($this->inotify)) === false) { return; } foreach ($eventList as $event) { $mask = $event['mask']; if ($mask & IN_DELETE_SELF || $mask & IN_MOVE_SELF) { $watchDescriptor = $event['wd']; if (inotify_rm_watch($this->inotify, $watchDescriptor)) { unset($this->paths[$watchDescriptor]); } break; } } $this->runListeners(); }
private function shutdownInotify($inotify, array $watches) { foreach ($watches as $watch) { /** @noinspection PhpUndefinedFunctionInspection */ inotify_rm_watch($inotify, $watch); } fclose($inotify); }
function deleteDir($dirname) { $path = $this->path . '/' . $dirname; if (in_array($path, $this->dirs)) { unset($this->dirs[$path]); inotify_rm_watch($this->ifds[$path], $this->wds[$path]); unset($this->ifds[$path]); unset($this->wds[$path]); } }
/** * 清理所有inotify监听 */ function clearWatch() { foreach ($this->watchFiles as $wd) { inotify_rm_watch($this->inotify, $wd); } $this->watchFiles = array(); }
public function unwatch(TrackedObject $tracked) { if ($tracked->getResource()->isExists()) { return; } @inotify_rm_watch($this->inotify, $tracked->getID()); unset($this->inotifyMap[$tracked->getID()]); return parent::unwatch($tracked); }
/** * 监控日志文件 * * @param array $logPaths * @return void * @throws ZtChart_Model_Monitor_Exception */ public function tail($logPaths) { if (($inotify = inotify_init()) === false) { throw new ZtChart_Model_Monitor_Daemon_Exception('Failed to obtain an inotify instance.'); } $watchFiles = $watchDirs = array(); foreach ($logPaths as $file) { if (($watch = inotify_add_watch($inotify, $file, IN_CREATE | IN_MODIFY)) === false) { throw new ZtChart_Model_Monitor_Daemon_Exception("Failed to watch file '{$file}'."); } if (is_file($file)) { if (false === ($fd = fopen($file, "r"))) { throw new ZtChart_Model_Monitor_Daemon_Exception("File '{$file}' is not readable."); } $this->_ffseek($fd); $watchFiles[$watch] = $fd; } else { if (is_dir($file)) { $watchFiles[$watch] = array(); $watchDirs[$watch] = $file; } } } while (($events = inotify_read($inotify)) !== false) { foreach ($events as $event) { if ($event['mask'] & IN_Q_OVERFLOW) { throw new ZtChart_Model_Monitor_Daemon_Exception("The number of inotify queued events reaches upper limit."); } if (!$this->accept($event['name'])) { continue; } if ($event['mask'] & (IN_CREATE | IN_MODIFY)) { if (!($event['mask'] & IN_ISDIR)) { if (!array_key_exists($event['name'], $watchFiles[$event['wd']])) { $fn = $fd = null; foreach ($watchFiles[$event['wd']] as $wfn => $wfd) { if (strncasecmp($wfn, $event['name'], strpos($wfn, '.')) == 0) { $fn = $wfn; $fd = $wfd; break; } } // 判断当前创建或修改的日志文件是否最新 if (strcasecmp($fn, $event['name']) < 0) { if (is_resource($fd) && fclose($fd)) { unset($watchFiles[$event['wd']][$fn]); } $filename = $watchDirs[$event['wd']] . DIRECTORY_SEPARATOR . $event['name']; if (false === ($fd = fopen($filename, "r"))) { $this->_logger->err("File '{$filename}' is not readable\n"); continue; } if ($event['mask'] & IN_MODIFY) { $this->_ffseek($fd); } $watchFiles[$event['wd']][$event['name']] = $fd; } else { // 如果不是最新的日志文件(重写的上一个小时的日志文件),则不处理。 continue; } } else { $fd = $watchFiles[$event['wd']][$event['name']]; } } else { continue; // $fd = $watchFiles[$event['wd']]; } // 读取日志并分析 $raw = ''; $lines = 0; while (true) { $raw .= $block = fread($fd, 4096); if (false !== ($pos = strpos($raw, "\n"))) { $rawline = substr($raw, 0, $pos + 1); try { $mlog = new ZtChart_Model_Monitor_Log($rawline); $line = $mlog->transform(); if (!empty($line)) { $this->_shmWrite($mlog->getShmIdentifier(), $line); $lines++; } } catch (ZtChart_Model_Monitor_Log_Exception $e) { $this->_logger->warn("日志处理错误:" . iconv('GBK', 'UTF-8', $rawline)); } $raw = substr($raw, $pos + 1); } else { if (($offset = strlen($block)) > 0) { fseek($fd, -$offset, SEEK_CUR); } break; } } if (0 != $lines) { $this->_logger->info(sprintf("%4s行有效数据已处理:%s", $lines, $watchDirs[$event['wd']] . '/' . $event['name'])); } } } } foreach ($watchFiles as $watch => $fd) { if (is_resource($fd)) { $fd = (array) $fd; } array_walk($fd, 'fclose'); inotify_rm_watch($inotify, $watch); } fclose($inotify); }
public function del($resource) { return inotify_rm_watch($this->inotify, $resource); }
public function start() { $paths = $this->_paths; if ($this->_followLinks) { $paths = LinksHelper::followLinks($paths, $this->_excludePatterns); } $this->_fd = inotify_init(); $finder = new Finder(); $finder->directories(); foreach ($this->_excludePatterns as $excludePattern) { $finder->notName($excludePattern); } foreach ($paths as $p) { $finder->in($p); } $this->_watches = array(); foreach ($paths as $p) { $this->_addWatch($p); } foreach ($finder as $f) { $this->_addWatch($f->__toString()); } $this->_logger->info("Watches set up..."); $read = array($this->_fd); $write = null; $except = null; stream_select($read, $write, $except, 0); stream_set_blocking($this->_fd, 0); $events = array(); while (!$this->_stopped) { while ($inotifyEvents = inotify_read($this->_fd)) { foreach ($inotifyEvents as $details) { $file = $this->_watches[$details['wd']]; if ($details['name']) { $file .= '/' . $details['name']; } if ($details['mask'] & IN_MODIFY || $details['mask'] & IN_ATTRIB) { $events[] = new ModifyEvent($file); } if ($details['mask'] & IN_CREATE) { $events[] = new CreateEvent($file); } if ($details['mask'] & IN_DELETE) { $events[] = new DeleteEvent($file); } if ($details['mask'] & IN_MOVED_FROM) { $this->_previousMoveFromFile = $file; } if ($details['mask'] & IN_MOVED_TO) { if (!isset($this->_previousMoveFromFile)) { $this->_logger->error('MOVED_FROM event is not followed by a MOVED_TO'); } else { $events[] = new MoveEvent($this->_previousMoveFromFile, $file); unset($this->_previousMoveFromFile); } } if ($details['mask'] & IN_DELETE_SELF) { unset($this->_watches[$details['wd']]); } } } $events = $this->_compressEvents($events); if ($this->_queueSizeLimit && count($events) > $this->_queueSizeLimit) { $this->_dispatchEvent(QueueFullEvent::NAME, new QueueFullEvent($events)); $events = array(); } foreach ($events as $event) { $name = call_user_func(array(get_class($event), 'getEventName')); $this->_dispatchEvent($name, $event); } usleep(100 * 1000); } foreach ($this->_watches as $wd => $path) { inotify_rm_watch($this->_fd, (int) $wd); } fclose($this->_fd); return; }