Completed
Push — master ( 130f0c...84b420 )
by Hu
02:48
created

TailReader   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 82
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 95%

Importance

Changes 5
Bugs 1 Features 3
Metric Value
c 5
b 1
f 3
dl 0
loc 82
wmc 11
lcom 1
cbo 0
ccs 38
cts 40
cp 0.95
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 7 2
A open() 0 13 1
A info() 0 4 1
A read() 0 4 1
B close() 0 24 5
A __destruct() 0 4 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: Jenner
5
 * Date: 2015/10/14
6
 * Time: 9:52
7
 */
8
9
namespace Jenner\LogMonitor\Reader;
10
11
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
    public function info()
46
    {
47
        return $this->file;
48
    }
49
50
    /**
51
     * read from stream
52
     * @param null $length
53
     * @return bool|string If there is no more data to read, the process will be blocked
54
     */
55 3
    public function read($length = null)
56
    {
57 3
        return fgets($this->handle);
58
    }
59
60
    /**
61
     * close stream
62
     * @return mixed
63
     */
64 6
    public function close()
65
    {
66 6
        if(!is_resource($this->process)) {
67 3
            return;
68
        }
69 3
        $status = proc_get_status($this->process);
70 3
        if ($status['running'] == true) { //process ran too long, kill it
71
            //close all pipes that are still open
72 3
            @fclose($this->pipes[0]); //stdin
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
73 3
            @fclose($this->pipes[1]); //stdout
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
74 3
            @fclose($this->pipes[2]); //stderr
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
75
            //get the parent pid of the process we want to kill
76 3
            $parent_pid = $status['pid'];
77
            //use ps to get all the children of this process, and kill them
78 3
            $pids = preg_split('/\s+/', `ps -o pid --no-heading --ppid $parent_pid`);
79 3
            foreach ($pids as $pid) {
80 3
                if (is_numeric($pid)) {
81 3
                    posix_kill($pid, 9); //9 is the SIGKILL signal
82 3
                }
83 3
            }
84
85 3
            proc_close($this->process);
86 3
        }
87 3
    }
88
89 6
    public function __destruct()
90
    {
91 6
        $this->close();
92
    }
93
}