Completed
Push — master ( 00a7e0...6e1d06 )
by Kris
26s queued 10s
created

ApacheErrorLogParser   A

Complexity

Total Complexity 3

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 3
eloc 50
c 1
b 0
f 0
dl 0
loc 135
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 80 1
A setFormat() 0 7 2
1
<?php declare(strict_types=1);
2
3
/** 
4
 *  ___                      _
5
 * | _ \ __ _  _ _  ___ ___ | | ___  __ _
6
 * |  _// _` || '_|(_-</ -_)| |/ _ \/ _` |
7
 * |_|  \__,_||_|  /__/\___||_|\___/\__, |
8
 *                                  |___/
9
 * 
10
 * (c) Kristuff <[email protected]>
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 *
15
 * @version    0.3.0
16
 * @copyright  2017-2020 Kristuff
17
 */
18
19
namespace Kristuff\Parselog\Software;
20
21
use Kristuff\Parselog\Core\LogEntryFactoryInterface;
22
23
/**
24
 * ApacheErrorLogParser 
25
 * 
26
 * The directive ErrorLogFormat is documented in version 2.4, but not in 2.2
27
 * 
28
 * Changes between 2.2/2.4:
29
 * - time field includes milliseconds in apache 2.4
30
 * - client field includes port number in apache 2.4
31
 * - note sure about pid/tid in apache 2.2
32
 * 
33
 * Example (default in 2.4): 
34
 * ErrorLogFormat "[%t] [%l] [pid %P] %F: %E: [client %a] %M"
35
 * 
36
 * Example (similar to the 2.2.x format):
37
 * ErrorLogFormat "[%t] [%l] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
38
 * 
39
 * #Example (default format for threaded MPMs):
40
 * ErrorLogFormat "[%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
41
 * 
42
 * Note that depending on error, some field may be missing from output.
43
 * 
44
 * 2.2:                 [Wed Oct 11 14:32:52 2000] [error] [client 127.0.0.1] client denied by server configuration: /export/home/live/ap/htdocs/test
45
 * 2.4:                 [Thu Jun 27 11:55:44.569531 2013] [core:info] [pid 4101:tid 2992634688] [client 1.2.3.4:46652]
46
 * 2.4:                 [Thu Oct 01 14:01:53.127021 2020] [reqtimeout:info] [pid 21290] [client 1.2.3.4:63044] AH01382: Request header read timeout
47
 * 2.4:                 [Sun Sep 27 00:00:48.784450 2020] [mpm_prefork:notice] [pid 747] AH00163: Apache/2.4.38 (Debian) OpenSSL/1.1.1d configured -- resuming normal operations
48
 * 2.4 (with client):   [Thu Jun 27 11:55:44.569531 2013] [core:info] [pid 4101:tid 2992634688] [client 1.2.3.4:46652] AH00128: File does not exist: <path>
49
 * 2.4 (no client):     [Fri Sep 25 20:23:41.378709 2020] [mpm_prefork:notice] [pid 10578] AH00169: caught SIGTERM, shutting down
50
 * 2.4 (perfork):       [Mon Dec 23 07:49:01.981912 2013] [:error] [pid 3790] [client 1.2.3.4:46301] script '/var/www/timthumb.php' not found or unable to
51
 * 
52
 * @see https://httpd.apache.org/docs/2.2/mod/core.html#errorlog
53
 * @see https://httpd.apache.org/docs/2.4/mod/core.html#errorlogformat
54
 * @see https://github.com/fail2ban/fail2ban/issues/268
55
 */
56
class ApacheErrorLogParser extends SoftwareLogParser
57
{
58
    /**
59
     * Inverted [client %a] %F: %E:
60
     * @see https://serverfault.com/questions/1036061/apache-error-log-format-how-to-find-current-format
61
     */
62
    const FORMAT_DEFAULT_APACHE_2_2 = '[%t] [%l] [client %a] %F: %E: %M';
63
64
    /**
65
     * Inverted [client %a] %F: %E:
66
     * @see https://serverfault.com/questions/1036061/apache-error-log-format-how-to-find-current-format
67
     */
68
    const FORMAT_DEFAULT_APACHE_2_4 = '[%{u}t] [%l] [pid %P] [client %a] %F: %E: %M';
69
    
70
    /**
71
     * #Example (default format for threaded MPMs)
72
     * ErrorLogFormat "[%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
73
     * Inverted [client %a] %F: %E:
74
     * @see https://serverfault.com/questions/1036061/apache-error-log-format-how-to-find-current-format
75
     */
76
    const FORMAT_MPM_APACHE_2_4 = '[%{u}t] [%-m:%l] [pid %P] [client %a] %F: %E: %M';
77
78
    /**
79
     * 
80
     * Inverted [client %a] %F: %E:
81
     * @see https://serverfault.com/questions/1036061/apache-error-log-format-how-to-find-current-format
82
     */
83
    const FORMAT_MPM_TID_APACHE_2_4 = '[%{u}t] [%-m:%l] [pid %P:tid %T] [client %a] %F: %E: %M';
84
     
85
    /**
86
     * Constructor
87
     * 
88
     * @access public
89
     * @param string                    $format    
90
     * @param LogEntryFactoryInterface  $factory        
91
     * 
92
     * @return void
93
     */
94
    public function __construct(string $format = null, LogEntryFactoryInterface $factory = null)
95
    {
96
        $this->software           = 'Apache';
97
        $this->prettyName         = 'Apache Error';
98
        $this->defaultFormat      = self::FORMAT_DEFAULT_APACHE_2_4;
99
        
100
        // 2.2 / 2.4
101
        $this->timeFormat        = 'D M d H:i:s Y';
102
        //$this->timeFormat        = 'D M d H:i:s.u Y';
103
104
        $this->addFormat('default', self::FORMAT_DEFAULT_APACHE_2_4);  
105
106
        $this->addPath("/var/log/");
107
        $this->addPath("/var/log/apache/");
108
        $this->addPath("/var/log/apache2/");
109
        $this->addPath("/var/log/httpd/");
110
        $this->addPath("/usr/local/var/log/apache/");
111
        $this->addPath("/usr/local/var/log/apache2/");
112
        $this->addPath("/usr/local/var/log/httpd/");
113
        $this->addPath("/opt/local/apache/logs/");
114
        $this->addPath("/opt/local/apache2/logs/");
115
        $this->addPath("/opt/local/httpd/logs/");
116
        $this->addPath("C:/wamp/logs/");
117
118
        $this->addFile('error.log');
119
        $this->addFile('error_log');
120
        $this->addFile("apache_error.log"); 
121
122
        // ***************
123
        // define patterns
124
        // ***************
125
126
        $this->addNamedPattern('%%' , 'percent', '\%');
127
                
128
        // %t 	        The current time
129
        // %{u}t 	The current time including micro-seconds
130
        $datePattern = '\[(?P<time>(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun) (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{2} \d{2}:\d{2}:\d{2}(?:\.\d{6}|) \d{4})\]';
131
        $this->addPattern('\[%{u}t\]', $datePattern);
132
        $this->addPattern('\[%t\]', $datePattern);
133
        $this->addPattern('%t', $datePattern);
134
        
135
        // %a 	Client IP address and port of the request (port is not registered by parser). 
136
        //      That column may be missing depending of error
137
        $clientIpPattern = '( \[client (?P<remoteIp>' . self::PATTERN_IP_ALL . ')(:[\d]+|)?\])?';
138
        $this->addPattern(' \[client %a\]' , $clientIpPattern);
139
        $this->addPattern(' \[%a\]' ,  $clientIpPattern);
140
        $this->addPattern(' %a' , $clientIpPattern);
141
142
        // %A 	Local IP-address and port
143
        //      That column may be missing depending of error
144
        $this->addNamedPattern('%A',  'localIP', self::PATTERN_IP_ALL, false);
145
        
146
        // %m 	Name of the module logging the message
147
        // %l 	Loglevel of the message
148
        $this->addPattern('\[%m:%l\]',  '\[(?<module>.+?)?:(?P<level>[\w]+)\]');
149
        $this->addPattern('\[%-m:%l\]', '\[(?<module>.+?)?:(?P<level>[\w]+)\]');
150
        $this->addPattern('\[%l\]',     '\[(?P<level>[\w:]+)\]');
151
        $this->addPattern('%l',         '\[(?P<level>[\w:]+)\]');
152
153
        // %P 	Process ID of current process (since apache 2.4?)
154
        // %T 	Thread ID of current thread
155
        $this->addPattern('\[pid %P:tid %T\]', '\[pid (?P<pid>\d+):tid (?P<tid>\d+)\]'); 
156
        $this->addPattern('%P %T',             '\[pid (?P<pid>\d+):tid (?P<tid>\d+)\]');
157
        $this->addPattern('\[pid %P\]', '\[pid (?P<pid>\d+)\]');
158
        $this->addPattern('\[%P\]',     '\[pid (?P<pid>\d+)\]');   
159
        $this->addPattern('%P',         '\[pid (?P<pid>\d+)\]');
160
        
161
        // %E 	APR/OS error status code and string
162
        //      That column may be missing depending of error
163
        //      note we match errorCode only, let error string in %M (message)  
164
        $this->addPattern(' %E:', '( (?P<errorCode>[\w\d]+):)?');              
165
166
        // %F 	Source file name and line number of the log call
167
        $this->addPattern(' %F:', '( (?P<fileName>[^\*\s\|><\?]*[\/][^\*\s\|><\?]*):)?');              
168
169
        // %M 	The actual log message
170
        $this->addNamedPattern('%M',  'message', '.+?');
171
        
172
        // now let default constructor
173
        parent::__construct($format, $factory);
174
    } 
175
176
     /**
177
     * Sets the log format  
178
     * 
179
     * @access public
180
     * @param string    $format
181
     * 
182
     * @return void
183
     */
184
    public function setFormat(string $format): void
185
    {
186
            parent::setFormat($format);
187
188
            // set the correct time format
189
            if (strpos($this->logFormat, '%{u}t') !== false){
190
                $this->timeFormat = 'D M d H:i:s.u Y';
191
            }
192
193
    }
194
195
}