Completed
Push — master ( affb22...b4ef27 )
by Kris
15s queued 12s
created

ApacheErrorLogParser::__construct()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 99
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
eloc 58
c 4
b 1
f 0
dl 0
loc 99
rs 8.9163
cc 1
nc 1
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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.7.0
16
 * @copyright  2017-2021 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
 * 2.4 (with referer):  [Sat Oct 03 13:56:38.054651 2020] [authz_core:error] [pid 6257] [client 1.2.3.4:63032] AH01630: client denied by server configuration: /var/www/xxx.dommain.fr, referer: https://xxx.dommain.fr/
52
 * 2.4 (with 'F:'):     [Fri Jul 23 21:29:32.087762 2021] [php7:error] [pid 29504] sapi_apache2.c(356): [client 1.2.3.4:64950] script '/var/www/foo.php' not found or unable to stat
53
 * 2.4  ???             [Tue Oct 13 23:03:12.080268 2020] [proxy:error] [pid 29705] (20014)Internal error (specific information not available): [client 1.2.3.4:56450] AH01084: pass request body failed to [::1]:8080 (localhost)
54
 * 2.4  ???             [Thu Jul 22 08:19:23.627412 2021] [proxy_http:error] [pid 1723] (-102)Unknown error -102: [client 1.2.3.4:32840] AH01095: prefetch request body failed to 127.0.0.1:3000 (127.0.0.1) from 1.2.3.4 ()
55
 * @see https://httpd.apache.org/docs/2.2/mod/core.html#errorlog
56
 * @see https://httpd.apache.org/docs/2.4/mod/core.html#errorlogformat
57
 * @see https://github.com/fail2ban/fail2ban/issues/268
58
 */
59
class ApacheErrorLogParser extends SoftwareLogParser
60
{
61
    /**
62
     */
63
    const FORMAT_APACHE_2_2_DEFAULT = '[%t] [%l] %E: [client %a] %M';
64
65
    /**
66
     */
67
    const FORMAT_APACHE_2_2_REFERER = '[%t] [%l] %E: [client %a] %M ,\ referer\ %{Referer}i';
68
69
    /**
70
     */
71
    const FORMAT_APACHE_2_2_EXTENDED = '[%t] [%l] %F: %E: [client %a] %M';
72
73
    /**
74
     */
75
    const FORMAT_APACHE_2_2_EXTENDED_REFERER = '[%t] [%l] %F: %E: [client %a] %M ,\ referer\ %{Referer}i';
76
77
    /**
78
     * 
79
     */
80
    const FORMAT_APACHE_2_4_DEFAULT = '[%{u}t] [%l] [pid %P] %E: [client %a] %M';
81
82
    /**
83
     * 
84
     */
85
    const FORMAT_APACHE_2_4_REFEFER = '[%{u}t] [%l] [pid %P] %E: [client %a] %M ,\ referer\ %{Referer}i';
86
87
    /**
88
     * 2_4_DEFAULT + %F:
89
     */
90
    const FORMAT_APACHE_2_4_EXTENDED = '[%{u}t] [%l] [pid %P] %F: %E: [client %a] %M';
91
92
    /**
93
     * 2_4_DEFAULT + %F + referer:
94
     */
95
    const FORMAT_APACHE_2_4_EXTENDED_REFERER = '[%{u}t] [%l] [pid %P] %F: %E: [client %a] %M ,\ referer\ %{Referer}i';
96
    
97
    /**
98
     * based on that example (default format for threaded MPMs)
99
     * ErrorLogFormat "[%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
100
     * @see https://httpd.apache.org/docs/2.4/fr/mod/core.html#errorlog
101
     */
102
    const FORMAT_APACHE_2_4_MPM = '[%{u}t] [%-m:%l] [pid %P] %E: [client %a] %M';
103
104
    /**
105
     * based on that example (default format for threaded MPMs)
106
     * ErrorLogFormat "[%{u}t] [%-m:%l] [pid %P:tid %T] %F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
107
     * @see https://httpd.apache.org/docs/2.4/fr/mod/core.html#errorlog
108
     * 
109
     * 2_4_NPM + %F:
110
     */
111
    const FORMAT_APACHE_2_4_MPM_EXTENDED = '[%{u}t] [%-m:%l] [pid %P] %F: %E: [client %a] %M';
112
113
    /**
114
     * based on that example (default format for threaded MPMs)
115
     * ErrorLogFormat "[%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
116
     * @see https://httpd.apache.org/docs/2.4/fr/mod/core.html#errorlog
117
     */
118
    const FORMAT_APACHE_2_4_MPM_REFERER = '[%{u}t] [%-m:%l] [pid %P] %E: [client %a] %M ,\ referer\ %{Referer}i';
119
120
    /**
121
     * based on that example (default format for threaded MPMs)
122
     * ErrorLogFormat "[%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
123
     * @see https://httpd.apache.org/docs/2.4/fr/mod/core.html#errorlog
124
     */
125
    const FORMAT_APACHE_2_4_MPM_EXTENDED_REFERER = '[%{u}t] [%-m:%l] [pid %P] %F: %E: [client %a] %M ,\ referer\ %{Referer}i';
126
127
    /**
128
     * 2_4_NPM + tid %T + %F: %E:
129
     */
130
    const FORMAT_APACHE_2_4_MPM_TID = '[%{u}t] [%-m:%l] [pid %P:tid %T] %F: %E: [client %a] %M';
131
 
132
    /**
133
     * based on that example (default format for threaded MPMs)
134
     * ErrorLogFormat "[%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
135
     * @see https://httpd.apache.org/docs/2.4/fr/mod/core.html#errorlog
136
     */
137
    const FORMAT_APACHE_2_4_MPM_TID_REFERER = '[%{u}t] [%-m:%l] [pid %P:tid %T] %F: %E: [client %a] %M ,\ referer\ %{Referer}i';
138
 
139
    /**
140
     * Constructor
141
     * 
142
     * @access public
143
     * @param string                    $format    
144
     * @param LogEntryFactoryInterface  $factory        
145
     * 
146
     * @return void
147
     */
148
    public function __construct(string $format = null, LogEntryFactoryInterface $factory = null)
149
    {
150
        $this->software           = 'Apache';
151
        $this->prettyName         = 'Apache Error';
152
        $this->defaultFormat      = self::FORMAT_APACHE_2_4_DEFAULT;
153
        
154
        // set 2.2 format by default. Will be changed to 2.4 format, ie:
155
        // $this->timeFormat        = 'D M d H:i:s.u Y';
156
        // , if the format contain %{u} insted of %t  
157
        $this->timeFormat        = 'D M d H:i:s Y';
158
159
        $this->addFormat('default',                         self::FORMAT_APACHE_2_4_DEFAULT);  
160
        $this->addFormat('apache2.2 default',               self::FORMAT_APACHE_2_2_DEFAULT);  
161
        $this->addFormat('apache2.2 extented',              self::FORMAT_APACHE_2_2_EXTENDED);  
162
        $this->addFormat('apache2.2 referer',               self::FORMAT_APACHE_2_2_REFERER);  
163
        $this->addFormat('apache2.2 extented referer',      self::FORMAT_APACHE_2_2_EXTENDED_REFERER);  
164
        $this->addFormat('apache2.4 default',               self::FORMAT_APACHE_2_4_DEFAULT);  
165
        $this->addFormat('apache2.4 extented',              self::FORMAT_APACHE_2_4_EXTENDED);  
166
        $this->addFormat('apache2.4 referer',               self::FORMAT_APACHE_2_4_REFEFER);  
167
        $this->addFormat('apache2.4 extented referer',      self::FORMAT_APACHE_2_4_EXTENDED_REFERER);  
168
        $this->addFormat('apache2.4 npm',                   self::FORMAT_APACHE_2_4_MPM);  
169
        $this->addFormat('apache2.4 npm extented',          self::FORMAT_APACHE_2_4_MPM_EXTENDED);  
170
        $this->addFormat('apache2.4 npm referer',           self::FORMAT_APACHE_2_4_MPM_REFERER);  
171
        $this->addFormat('apache2.4 npm extented referer ', self::FORMAT_APACHE_2_4_MPM_EXTENDED_REFERER);  
172
        $this->addFormat('apache2.4 npm tid',               self::FORMAT_APACHE_2_4_MPM_TID);  
173
        $this->addFormat('apache2.4 npm tid referer',       self::FORMAT_APACHE_2_4_MPM_TID_REFERER);  
174
175
        $this->addPath("/var/log/");
176
        $this->addPath("/var/log/apache/");
177
        $this->addPath("/var/log/apache2/");
178
        $this->addPath("/var/log/httpd/");
179
        $this->addPath("/usr/local/var/log/apache/");
180
        $this->addPath("/usr/local/var/log/apache2/");
181
        $this->addPath("/usr/local/var/log/httpd/");
182
        $this->addPath("/opt/local/apache/logs/");
183
        $this->addPath("/opt/local/apache2/logs/");
184
        $this->addPath("/opt/local/httpd/logs/");
185
        $this->addPath("C:/wamp/logs/");
186
187
        $this->addFile('error.log');
188
        $this->addFile('error_log');
189
        $this->addFile("apache_error.log"); 
190
191
        // ***************
192
        // define patterns
193
        // ***************
194
195
        $this->addNamedPattern('%%' , 'percent', '\%');
196
                
197
        // %t 	        The current time
198
        // %{u}t 	The current time including micro-seconds
199
        $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})\]';
200
        $this->addPattern('\[%{u}t\]', $datePattern);
201
        $this->addPattern('\[%t\]', $datePattern);
202
        $this->addPattern('%t', $datePattern);
203
        
204
        // %a 	Client IP address and port of the request (port is not registered by parser). 
205
        //      That column may be missing depending of error
206
        $clientIpPattern = '( \[client (?P<remoteIp>' . self::PATTERN_IP_ALL . ')(:[\d]+|)?\])?';
207
        $this->addPattern(' \[client %a\]' , $clientIpPattern);
208
        $this->addPattern(' \[%a\]' ,  $clientIpPattern);
209
        $this->addPattern(' %a' , $clientIpPattern);
210
211
        // %A 	Local IP-address and port
212
        //      That column may be missing depending of error
213
        $this->addNamedPattern('%A',  'localIP', self::PATTERN_IP_ALL, false);
214
        
215
        // %m 	Name of the module logging the message
216
        // %l 	Loglevel of the message
217
        $this->addPattern('\[%m:%l\]',  '\[(?<module>.+?)?:(?P<level>[\w]+)\]');
218
        $this->addPattern('\[%-m:%l\]', '\[(?<module>.+?)?:(?P<level>[\w]+)\]');
219
        $this->addPattern('\[%l\]',     '\[(?P<level>[\w:]+)\]');
220
        $this->addPattern('%l',         '\[(?P<level>[\w:]+)\]');
221
222
        // %P 	Process ID of current process (since apache 2.4?)
223
        // %T 	Thread ID of current thread
224
        $this->addPattern('\[pid %P:tid %T\]', '\[pid (?P<pid>\d+):tid (?P<tid>\d+)\]'); 
225
        $this->addPattern('%P %T',             '\[pid (?P<pid>\d+):tid (?P<tid>\d+)\]');
226
        $this->addPattern('\[pid %P\]', '\[pid (?P<pid>\d+)\]');
227
        $this->addPattern('\[%P\]',     '\[pid (?P<pid>\d+)\]');   
228
        $this->addPattern('%P',         '\[pid (?P<pid>\d+)\]');
229
        
230
        // %E 	APR/OS error status code and string
231
        //      That column may be missing depending of error
232
        $this->addPattern(' %E:', '( (?P<errorCode>\([\-\d]+\)[^\[]+):)?');              
233
234
        // %F 	Source file name and line number of the log call
235
        //$this->addPattern(' %F:', '( (?P<fileName>[^\*\s\|><\?]*[\/][^\*\s\|><\?]*):)?');              
236
        $this->addPattern(' %F:', '( (?P<fileName>[^ ]+\([\d]+\)):)?');              
237
238
        // %M 	The actual log message
239
        $this->addNamedPattern('%M',  'message', '.+?');
240
241
        // referer (may be empty)
242
        $this->addPattern(' , referer %{Referer}i',   '(, referer: (?P<referer>[^ ]+))?');
243
        $this->addPattern(', referer %{Referer}i',    '(, referer: (?P<referer>[^ ]+))?');
244
245
        // now let default constructor
246
        parent::__construct($format, $factory);
247
    } 
248
249
    /**
250
     * Sets the log format  
251
     * 
252
     * @access public
253
     * @param string    $format
254
     * 
255
     * @return void
256
     */
257
    public function setFormat(string $format): void
258
    {
259
        parent::setFormat($format);
260
261
        // set the correct time format
262
        if (strpos($this->logFormat, '%{u}t') !== false){
263
            $this->timeFormat = 'D M d H:i:s.u Y';
264
        }
265
    }
266
}