/** * 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; }
/** * Execute the console command. * * @return mixed */ public function fire() { $watches = array(); $in = inotify_init(); // add watches starting from root directory $root = Path::fromRelative(''); $this->addWatches($in, $root, $watches); printf("\nReading for events\n"); while (true) { $events = inotify_read($in); foreach ($events as $event) { $path = $watches[$event['wd']]; $expanded = $this->expandMask($event['mask']); $eventName = trim(implode(', ', $expanded), ', '); // if the event has a name attached, then index that if ($event['name']) { $newPathName = $path->getPathname() . '/' . $event['name']; $newPath = new Path($newPathName); Indexer::index($newPath, 1); // this may be a new directory, so add a watch to it anyway if ($newPath->exists() && $newPath->isDir()) { try { $wd = inotify_add_watch($in, $newPath->getPathname(), $this->computedMask); $watches[$wd] = $newPath; } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; } } } else { // event must apply to this directory, so index it, 1 level deep Indexer::index($path, 1); } } } }
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); } } } }
/** * @param array $directories * @param \Closure|null $callback * @return Watcher * @throws \RuntimeException */ public function watch(array $directories, \Closure $callback = null) { foreach ($directories as $directory) { if (!is_dir($directory)) { $this->clearWatch(); throw new \RuntimeException("[{$directory}] is not a directory."); } $wd = inotify_add_watch($this->inotify, $directory, $this->events); $this->watchDir[$directory] = $wd; } $this->callback = $callback; // Listen modify. \swoole_event_add($this->inotify, function () use($callback) { $events = inotify_read($this->inotify); if (!$events) { return; } foreach ($events as $event) { if (!empty($event['name'])) { echo sprintf("[%s]\t" . sprintf('["%s"] modify', $event['name']) . PHP_EOL, date('Y-m-d H:i:s')); } } if (is_callable($callback)) { $callback($this); } }); return $this; }
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; } } } }
/** * Check the file system, triggered by timer * @return void */ public function watch() { if ($this->inotify) { $events = inotify_read($this->inotify); if (!$events) { return; } foreach ($events as $ev) { $path = $this->descriptors[$ev['wd']]; if (!isset($this->files[$path])) { continue; } $this->onFileChanged($path); } } else { static $hash = []; foreach ($this->files as $path => $v) { if (!file_exists($path)) { // file can be deleted unset($this->files[$path]); continue; } $mt = filemtime($path); if (isset($hash[$path]) && $mt > $hash[$path]) { $this->onFileChanged($path); } $hash[$path] = $mt; } } }
/** * Tick handler */ public function tick() { $events = inotify_read($this->inotifyStreamDescriptor); if (is_array($events)) { $this->handleEvents($events); } }
/** * Evaluate Filesystem changes * * @return mixed */ public function evaluate() { $this->tracker->clearChangeSet(); $this->modified = array(); $inEvents = inotify_read($this->inotify); $inEvents = is_array($inEvents) ? $inEvents : array(); foreach ($inEvents as $inEvent) { $this->translateEvent($inEvent); } }
/** * 获取更改的文件 * @return array */ public static function getModifiedFiles() { // 读取监控事件 $events = inotify_read(self::$inotifyFd); if (empty($events)) { return false; } // 获得哪些文件被修改 $modify_files = array(); foreach ($events as $ev) { $modify_files[$ev['wd']] = self::$inotifyWatchFds[$ev['wd']]; } return $modify_files; }
/** * Checks all new inotify events available * and emits them via evenement */ public function __invoke() { if (false !== ($events = \inotify_read($this->inotifyHandler))) { foreach ($events as $event) { // make sure the watch descriptor assigned to this event is // still valid. removing watch descriptors via 'remove()' // implicitly sends a final event with mask IN_IGNORE set: // http://php.net/manual/en/inotify.constants.php#constant.in-ignored if (isset($this->watchDescriptors[$event['wd']])) { $path = $this->watchDescriptors[$event['wd']]['path']; $this->emit($event['mask'], array($path . $event['name'])); } } } }
function check_files_change($inotify_fd) { global $monitor_files; // 读取有哪些文件事件 $events = inotify_read($inotify_fd); if ($events) { // 检查哪些文件被更新了 foreach ($events as $ev) { // 更新的文件 $file = $monitor_files[$ev['wd']]; echo $file . " update and reload\n"; unset($monitor_files[$ev['wd']]); // 需要把文件重新加入监控 $wd = inotify_add_watch($inotify_fd, $file, IN_MODIFY); $monitor_files[$wd] = $file; } // 给父进程也就是主进程发送reload信号 posix_kill(posix_getppid(), SIGUSR1); } }
/** * @return Result */ public function run() { /** @noinspection PhpUndefinedFunctionInspection */ $inotify = inotify_init(); $watches = $this->createInotifyWatches($inotify); stream_set_blocking($inotify, 0); while (true) { /** @noinspection PhpUndefinedFunctionInspection */ $events = inotify_read($inotify); if ($events) { if ($this->clear) { passthru('bash -c clear'); } $this->runTasksForInotifyEvents($events); } sleep(1); } $this->shutdownInotify($inotify, $watches); return $this->gasp->result()->setStatus(Result::SUCCESS)->setMessage('And now his watch is ended.'); }
public function start() { $this->init(); $this->fd = fopen($this->path, 'r'); stream_set_blocking($this->fd, 0); $pos = filesize($this->path); while (true) { $events = inotify_read($this->ifd); foreach ($events as $event) { switch (true) { case $event['mask'] & self::MASK: fseek($this->fd, $pos); $buf = ''; while (!feof($this->fd)) { $buf .= fread($this->fd, 8192); } $this->handler->InModify($buf, $this->filename); $pos = ftell($this->fd); break; } } } }
/** * @param $serverPid * @throws NotFound */ function __construct($serverPid) { $this->pid = $serverPid; if (posix_kill($serverPid, 0) === false) { throw new NotFound("Process#{$serverPid} not found."); } $this->inotify = inotify_init(); $this->events = IN_MODIFY | IN_DELETE | IN_CREATE | IN_MOVE; swoole_event_add($this->inotify, function ($ifd) { $events = inotify_read($this->inotify); if (!$events) { return; } var_dump($events); foreach ($events as $ev) { if ($ev['mask'] == IN_IGNORED) { continue; } else { if ($ev['mask'] == IN_CREATE or $ev['mask'] == IN_DELETE or $ev['mask'] == IN_MODIFY or $ev['mask'] == IN_MOVED_TO or $ev['mask'] == IN_MOVED_FROM) { $fileType = strstr($ev['name'], '.'); //非重启类型 if (!isset($this->reloadFileTypes[$fileType])) { continue; } } } //正在reload,不再接受任何事件,冻结10秒 if (!$this->reloading) { $this->putLog("after 10 seconds reload the server"); //有事件发生了,进行重启 swoole_timer_after($this->afterNSeconds * 1000, array($this, 'reload')); $this->reloading = true; } } }); }
/** * Returns all events happened since last event readout * * @return array */ protected function readEvents() { return inotify_read($this->inotify); }
/** * 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(); }
public function wait() { return inotify_read($this->inotify); }
function start() { $this->initDirs(); while (true) { $fds = $this->ifds; if (stream_select($fds, $w = null, $e = null, 1)) { foreach ($fds as $file => $ifd) { $events = inotify_read($ifd); foreach ($events as $event) { switch (true) { case $event['mask'] & IN_MODIFY: if (isset($this->fds[$file])) { fseek($this->fds[$file], $this->pos[$file]); $buf = ''; while (!feof($this->fds[$file])) { $buf .= fread($this->fds[$file], self::BUFFER_SIZE); } if ($buf) { $this->handler->InModify($buf, basename($file)); $this->pos[$file] = ftell($this->fds[$file]); } } break; case $event['mask'] & IN_CREATE and $event['mask'] & IN_ISDIR: $this->addDir($event['name']); $this->log("add dir event " . $event['name']); break; case $event['mask'] & IN_CREATE: $this->addFile($event['name']); $this->log("add file event " . $event['name']); break; case $event['mask'] & IN_DELETE and $event['mask'] & IN_ISDIR: $this->deleteDir($event['name']); break; case $event['mask'] & IN_DELETE: $this->deleteFile($event['name']); break; } } } } if (date("His") == "000100") { $yesterday = date($this->format, time() - 24 * 3600); $this->log(date("Y-m-d H:i:s") . "stop watch {$yesterday}"); $this->stopWatchDir($yesterday); } } }
<?php class G { static $users = array(); static $files = array(); static $watchList = array(); static $inotify; } $server = new swoole_websocket_server("0.0.0.0", 9502, SWOOLE_BASE); $server->on('WorkerStart', function (swoole_websocket_server $server, $worker_id) { G::$inotify = inotify_init(); swoole_event_add(G::$inotify, function ($ifd) use($server) { $events = inotify_read(G::$inotify); if (!$events) { return; } foreach ($events as $event) { $filename = G::$watchList[$event['wd']]; $line = fgets(G::$files[$filename]['fp']); if (!$line) { echo "fgets failed\n"; } //遍历监听此文件的所有用户,进行广播 foreach (G::$files[$filename]['users'] as $fd) { $server->push($fd, $line); } } }); }); $server->on('Message', function (swoole_websocket_server $server, $frame) {
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; }
<?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);
protected function watchPackages(InputInterface $input, OutputInterface $output) { if (!function_exists('inotify_init')) { throw new \RuntimeException('Watch require inotify support, please install the inotify extension http://php.net/inotify'); } $packageNames = $input->getArgument('package'); if (empty($packageNames)) { $packageNames = array_keys($this->packages); } $inotify = inotify_init(); $watches = []; $mapping = []; foreach ($packageNames as $packageName) { if (!isset($this->packages[$packageName])) { throw new \RuntimeException('The package "' . $packageName . '" does not exist'); } if ($output->getVerbosity() >= OutputInterface::VERBOSITY_NORMAL) { $output->writeln(sprintf('* start watching package <comment>%s</comment>', $packageName)); } $package = $this->packages[$packageName]; $this->addWatches($package, $package, $mapping, $watches, $inotify, $output); } while (true) { if ($output->getVerbosity() >= OutputInterface::VERBOSITY_NORMAL) { $output->writeln('* <info>waiting for modifications</info>'); } $events = inotify_read($inotify); if (is_array($events)) { foreach ($events as $event) { $pathname = $watches[$event['wd']]; $packages = $mapping[$pathname]; if ($output->getVerbosity() >= OutputInterface::VERBOSITY_NORMAL) { $output->writeln(sprintf('modification on <comment>%s</comment> detected', $pathname)); } foreach ($packages as $package) { try { $this->buildPackage($package, $input, $output); } catch (\Exception $e) { $this->getApplication()->renderException($e, $output); } } } } } }
/** * 监控日志文件 * * @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); }
<?php // Open an inotify instance $fd = inotify_init(); // Watch __FILE__ for metadata changes (e.g. mtime) $watch_descriptor = inotify_add_watch($fd, __DIR__ . '/php', IN_MODIFY | IN_MOVED_FROM | IN_CREATE | IN_DELETE | IN_ISDIR); while (true) { // Read events $events = inotify_read($fd); print_r($events); }
function watchFiles() { $this->initFiles(); while (true) { $fds = $this->ifds; if (stream_select($fds, $w = null, $e = null, 0)) { foreach ($fds as $file => $ifd) { $events = inotify_read($ifd); foreach ($events as $event) { switch (true) { case $event['mask'] & IN_MODIFY: if (isset($this->fds[$file])) { fseek($this->fds[$file], $this->pos[$file]); $buf = ''; while (!feof($this->fds[$file])) { $buf .= fread($this->fds[$file], self::BUFFER_SIZE); } //var_dump($file,$this->fds[$file],$buf); $this->handler->InModify($buf, $file); $this->pos[$file] = ftell($this->fds[$file]); } break; case $event['mask'] & IN_CREATE: //echo 'add files'; $this->addFiles(); break; case $event['mask'] & IN_DELETE: //echo 'dell files'; $this->deleteFiles(); break; } } } } } }