1 | <?php |
||
12 | class TailReader implements ReaderInterface |
||
13 | { |
||
14 | protected $file; |
||
15 | protected $error_file; |
||
16 | protected $handle; |
||
17 | protected $pipes; |
||
18 | protected $process; |
||
19 | |||
20 | 6 | public function configure($file) |
|
21 | { |
||
22 | 6 | if (!file_exists($file)) { |
|
23 | 3 | throw new \RuntimeException("log file is not exists. file:" . $file); |
|
24 | } |
||
25 | 3 | $this->file = $file; |
|
26 | 3 | } |
|
27 | |||
28 | /** |
||
29 | * open stream |
||
30 | */ |
||
31 | 3 | public function open() |
|
32 | { |
||
33 | 3 | $command = "tail -F {$this->file}"; |
|
34 | $descriptors = array( |
||
35 | 3 | 0 => array("pipe", "r"), // stdin is a pipe that the child will read from |
|
36 | 3 | 1 => array("pipe", "w"), // stdout is a pipe that the child will write to |
|
37 | 3 | 2 => array("file", "/dev/null", "a") // stderr is a file to write to |
|
38 | 3 | ); |
|
39 | |||
40 | 3 | $cwd = '/tmp'; |
|
41 | 3 | $this->process = proc_open($command, $descriptors, $this->pipes, $cwd); |
|
42 | 3 | $this->handle = $this->pipes[1]; |
|
43 | 3 | } |
|
44 | |||
45 | /** |
||
46 | * read from stream |
||
47 | * @param null $length |
||
48 | * @return bool|string If there is no more data to read, the process will be blocked |
||
49 | */ |
||
50 | 3 | public function read($length = null) |
|
51 | { |
||
52 | 3 | return fgets($this->handle); |
|
53 | } |
||
54 | |||
55 | /** |
||
56 | * close stream |
||
57 | * @return mixed |
||
58 | */ |
||
59 | 6 | public function close() |
|
60 | { |
||
61 | 6 | if(!is_resource($this->process)) { |
|
62 | 3 | return; |
|
63 | } |
||
64 | 3 | $status = proc_get_status($this->process); |
|
65 | 3 | if ($status['running'] == true) { //process ran too long, kill it |
|
66 | //close all pipes that are still open |
||
67 | 3 | @fclose($this->pipes[0]); //stdin |
|
|
|||
68 | 3 | @fclose($this->pipes[1]); //stdout |
|
69 | 3 | @fclose($this->pipes[2]); //stderr |
|
70 | //get the parent pid of the process we want to kill |
||
71 | 3 | $parent_pid = $status['pid']; |
|
72 | //use ps to get all the children of this process, and kill them |
||
73 | 3 | $pids = preg_split('/\s+/', `ps -o pid --no-heading --ppid $parent_pid`); |
|
74 | 3 | foreach ($pids as $pid) { |
|
75 | 3 | if (is_numeric($pid)) { |
|
76 | 3 | posix_kill($pid, 9); //9 is the SIGKILL signal |
|
77 | 3 | } |
|
78 | 3 | } |
|
79 | |||
80 | 3 | proc_close($this->process); |
|
81 | 3 | } |
|
82 | 3 | } |
|
83 | |||
84 | 6 | public function __destruct() |
|
88 | } |
If you suppress an error, we recommend checking for the error condition explicitly: