aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Bachelier <laurent@bachelier.name>2010-12-27 20:45:18 +0100
committerLaurent Bachelier <laurent@bachelier.name>2010-12-27 20:45:18 +0100
commitdc2f7e1cc4405d6fe9f904acdb21fad2edf55790 (patch)
tree74c8cf94a2ba80b275a375a5280af1b2cd400b35
parentAdd missing type in phpdoc (diff)
downloadsymfttpd-dc2f7e1cc4405d6fe9f904acdb21fad2edf55790.tar.xz
Add support for the -t/--tail option
It will display the contents of lighttpd's logs just like the UNIX tail command.
-rw-r--r--lib/Tail.php101
-rwxr-xr-xspawn15
2 files changed, 116 insertions, 0 deletions
diff --git a/lib/Tail.php b/lib/Tail.php
new file mode 100644
index 0000000..10d20a1
--- /dev/null
+++ b/lib/Tail.php
@@ -0,0 +1,101 @@
+<?php
+class Tail
+{
+ protected $path = null;
+ protected $first = true;
+ protected $pos = 0;
+
+ /**
+ * Follow a file
+ * @param string $path
+ *
+ * @author Laurent Bachelier <laurent@bachelier.name>
+ */
+ public function __construct($path)
+ {
+ $this->path = $path;
+ }
+
+ /**
+ * Read a new line a long as it is possible.
+ * Goes straight to the end the first time if the file exists.
+ * @return mixed a string (including line return), false (EOF) or null (failure)
+ *
+ * @author Laurent Bachelier <laurent@bachelier.name>
+ */
+ public function consume()
+ {
+ $first = $this->first;
+ $this->first = false;
+ if (!is_readable($this->path))
+ {
+
+ return null;
+ }
+ $fd = fopen($this->path, 'r');
+ if ($first)
+ {
+ fseek($fd, 0, SEEK_END);
+ }
+ else
+ {
+ fseek($fd, $this->pos, SEEK_SET);
+ // TODO handle file truncation
+ }
+ $line = fgets($fd);
+ $this->pos = ftell($fd);
+ fclose($fd);
+
+ return $line;
+ }
+}
+
+class MultiTail
+{
+ protected $tails = array();
+
+ /**
+ * Adds a Tail to watch
+ * @param string $name Unique name
+ * @param Tail $tail
+ *
+ * @author Laurent Bachelier <laurent@bachelier.name>
+ */
+ public function add($name, $tail)
+ {
+ $this->tails[$name] = $tail;
+ }
+
+ /**
+ * Calls consume() on every Tail and displays lines.
+ *
+ * @author Laurent Bachelier <laurent@bachelier.name>
+ */
+ public function consume()
+ {
+ foreach ($this->tails as $name => $tail)
+ {
+ while ($this->display($tail->consume(), $name));
+ }
+ }
+
+ /**
+ * Display a line from a Tail, if it is valid.
+ * @param mixed $line
+ * @param string $name Unique name of the Tail
+ * @return boolean Line validity
+ *
+ * @author Laurent Bachelier <laurent@bachelier.name>
+ */
+ public function display($line, $name)
+ {
+ if (is_string($line))
+ {
+ echo $name.': '.$line;
+
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/spawn b/spawn
index a467a87..277cb50 100755
--- a/spawn
+++ b/spawn
@@ -10,6 +10,7 @@ require dirname(__FILE__).'/lib/FileTools.php';
require dirname(__FILE__).'/lib/PosixTools.php';
require dirname(__FILE__).'/lib/MultiConfig.php';
require dirname(__FILE__).'/lib/Symfony.php';
+require dirname(__FILE__).'/lib/Tail.php';
$project_path = Symfony::getProjectPath();
$options = MultiConfig::get();
@@ -24,6 +25,7 @@ $options['log_dir'] = $project_path.'/log/lighttpd';
// hack: .sf files are not removed by symfony cc
$options['pidfile'] = $options['config_dir'].'/.sf';
$options['restartfile'] = $options['config_dir'].'/.symfttpd_restart';
+$options['tail'] = Argument::get('t', 'tail', false);
$options['fork'] = !Argument::get('s', '--single-process', false);
if ($options['fork'] && !function_exists('pcntl_fork'))
{
@@ -108,6 +110,14 @@ if (!$options['fork'])
}
else
{
+ if ($options['tail'])
+ {
+ $multitail = new MultiTail();
+ $multitail->add('lighttpd-access', new Tail($project_path.'/log/lighttpd/access.log'));
+ $multitail->add('lighttpd-error', new Tail($project_path.'/log/lighttpd/error.log'));
+ // We have to do it before the fork to capture the startup messages
+ $multitail->consume();
+ }
$pid = pcntl_fork();
if ($pid)
{
@@ -125,6 +135,11 @@ else
}
$prev_genconf = $genconf;
+ if ($options['tail'])
+ {
+ $multitail->consume();
+ }
+
// If the children is defunct, we are finished here
if (pcntl_waitpid($pid, $status, WNOHANG))
{