Exemple #1
0
/**
 * 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;
}
Exemple #2
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;
            }
        }
    }
}
Exemple #3
0
 /**
  * Clear all watching.
  *
  * @return void
  */
 public function clearWatch()
 {
     foreach ($this->watchDir as $wd) {
         inotify_rm_watch($this->inotify, $wd);
     }
     $this->watchDir = [];
 }
Exemple #4
0
 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);
             }
         }
     }
 }
Exemple #5
0
 /**
  * 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();
         }
     }
 }
Exemple #6
0
 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]);
         }
     }
 }
Exemple #7
0
 /**
  * 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;
 }
Exemple #8
0
<?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);
 }
Exemple #10
0
 /**
  * 删除某个文件的监控
  * @param string $file
  */
 public static function delFile($file)
 {
     return inotify_rm_watch(self::$inotifyFd, $file);
 }
Exemple #11
0
 /**
  * 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();
 }
Exemple #12
0
 private function shutdownInotify($inotify, array $watches)
 {
     foreach ($watches as $watch) {
         /** @noinspection PhpUndefinedFunctionInspection */
         inotify_rm_watch($inotify, $watch);
     }
     fclose($inotify);
 }
Exemple #13
0
 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]);
     }
 }
Exemple #14
0
 /**
  * 清理所有inotify监听
  */
 function clearWatch()
 {
     foreach ($this->watchFiles as $wd) {
         inotify_rm_watch($this->inotify, $wd);
     }
     $this->watchFiles = array();
 }
Exemple #15
0
 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);
 }
Exemple #17
0
 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;
 }