Passed
Push — 1.0.0-dev ( 7e13dc...c7a39c )
by nguereza
06:11
created

Log::writeLog()   F

Complexity

Conditions 16
Paths 533

Size

Total Lines 78
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 16
eloc 42
c 1
b 1
f 0
nc 533
nop 2
dl 0
loc 78
rs 2.0486

How to fix   Long Method    Complexity   

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
2
	defined('ROOT_PATH') || exit('Access denied');
3
	/**
4
	 * TNH Framework
5
	 *
6
	 * A simple PHP framework using HMVC architecture
7
	 *
8
	 * This content is released under the GNU GPL License (GPL)
9
	 *
10
	 * Copyright (C) 2017 Tony NGUEREZA
11
	 *
12
	 * This program is free software; you can redistribute it and/or
13
	 * modify it under the terms of the GNU General Public License
14
	 * as published by the Free Software Foundation; either version 3
15
	 * of the License, or (at your option) any later version.
16
	 *
17
	 * This program is distributed in the hope that it will be useful,
18
	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
	 * GNU General Public License for more details.
21
	 *
22
	 * You should have received a copy of the GNU General Public License
23
	 * along with this program; if not, write to the Free Software
24
	 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25
	*/
26
27
	class Log{
28
		
29
		/**
30
		 * The defined constante for Log level
31
		 */
32
		const NONE = 99999999;
33
		const FATAL = 500;
34
		const ERROR = 400;
35
		const WARNING = 300;
36
		const INFO = 200;
37
		const DEBUG = 100;
38
		const ALL = -99999999;
39
40
		/**
41
		 * The logger name
42
		 * @var string
43
		 */
44
		private $logger = 'ROOT_LOGGER';
45
		
46
		/**
47
		 * List of valid log level to be checked for the configuration
48
		 * @var array
49
		 */
50
		private static $validConfigLevel = array('off', 'none', 'fatal', 'error', 'warning', 'warn', 'info', 'debug', 'all');
51
52
		/**
53
		 * Create new Log instance
54
		 */
55
		public function __construct(){
56
		}
57
58
		/**
59
		 * Set the logger to identify each message in the log
60
		 * @param string $logger the logger name
61
		 */
62
		public  function setLogger($logger){
63
			$this->logger = $logger;
64
		}
65
66
		/**
67
		 * Save the fatal message in the log
68
		 * @see Log::writeLog for more detail
69
		 * @param  string $message the log message to save
70
		 */
71
		public function fatal($message){
72
			$this->writeLog($message, self::FATAL);
73
		} 
74
		
75
		/**
76
		 * Save the error message in the log
77
		 * @see Log::writeLog for more detail
78
		 * @param  string $message the log message to save
79
		 */
80
		public function error($message){
81
			$this->writeLog($message, self::ERROR);
82
		} 
83
84
		/**
85
		 * Save the warning message in the log
86
		 * @see Log::writeLog for more detail
87
		 * @param  string $message the log message to save
88
		 */
89
		public function warning($message){
90
			$this->writeLog($message, self::WARNING);
91
		} 
92
		
93
		/**
94
		 * Save the info message in the log
95
		 * @see Log::writeLog for more detail
96
		 * @param  string $message the log message to save
97
		 */
98
		public function info($message){
99
			$this->writeLog($message, self::INFO);
100
		} 
101
		
102
		/**
103
		 * Save the debug message in the log
104
		 * @see Log::writeLog for more detail
105
		 * @param  string $message the log message to save
106
		 */
107
		public function debug($message){
108
			$this->writeLog($message, self::DEBUG);
109
		} 
110
		
111
		
112
		/**
113
		 * Save the log message
114
		 * @param  string $message the log message to be saved
115
		 * @param  integer|string $level   the log level in integer or string format, if is string will convert into integer
116
		 * to allow check the log level threshold.
117
		 */
118
		public function writeLog($message, $level = self::INFO){
119
			$configLogLevel = get_config('log_level');
120
			if(! $configLogLevel){
121
				//so means no need log just stop here
122
				return;
123
			}
124
			//check config log level
125
			if(! self::isValidConfigLevel($configLogLevel)){
126
				//NOTE: here need put the show_error() "logging" to false to prevent loop
127
				show_error('Invalid config log level [' . $configLogLevel . '], the value must be one of the following: ' . implode(', ', array_map('strtoupper', self::$validConfigLevel)), $title = 'Log Config Error', $logging = false);	
128
			}
129
			
130
			//check if config log_logger_name is set
131
			if($this->logger){
132
				$configLoggerName = get_config('log_logger_name', '');
133
				if($configLoggerName){
134
					if (is_array($configLoggerName)){
135
						//for best comparaison put all string to lowercase
136
						$configLoggerName = array_map('strtolower', $configLoggerName);
137
						if(! in_array(strtolower($this->logger), $configLoggerName)){
138
							return;
139
						}
140
					}
141
					else if(strtolower($this->logger) !== strtolower($configLoggerName)){
142
						return; 
143
					}
144
				}
145
			}
146
			
147
			//if $level is not an integer
148
			if(! is_numeric($level)){
149
				$level = self::getLevelValue($level);
150
			}
151
			
152
			//check if can logging regarding the log level config
153
			$configLevel = self::getLevelValue($configLogLevel);
154
			if($configLevel > $level){
155
				//can't log
156
				return;
157
			}
158
			
159
			$logSavePath = get_config('log_save_path');
160
			if(! $logSavePath){
161
				$logSavePath = LOGS_PATH;
162
			}
163
			
164
			if(! is_dir($logSavePath) || !is_writable($logSavePath)){
165
				//NOTE: here need put the show_error() "logging" to false to prevent loop
166
				show_error('Error : the log dir does not exists or is not writable', $title = 'Log directory error', $logging = false);
167
			}
168
			
169
			$path = $logSavePath . 'logs-' . date('Y-m-d') . '.log';
170
			if(! file_exists($path)){
171
				touch($path);
172
			}
173
			//may be at this time helper user_agent not yet included
174
			require_once CORE_FUNCTIONS_PATH . 'function_user_agent.php';
175
			
176
			///////////////////// date //////////////
177
			$timestampWithMicro = microtime(true);
178
			$microtime = sprintf('%06d', ($timestampWithMicro - floor($timestampWithMicro)) * 1000000);
179
			$dateTime = new DateTime(date('Y-m-d H:i:s.' . $microtime, $timestampWithMicro));
180
			$logDate = $dateTime->format('Y-m-d H:i:s.u'); 
181
			//ip
182
			$ip = get_ip();
183
			//level name
184
			$levelName = self::getLevelName($level);
0 ignored issues
show
Bug introduced by
It seems like $level can also be of type string; however, parameter $level of Log::getLevelName() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

184
			$levelName = self::getLevelName(/** @scrutinizer ignore-type */ $level);
Loading history...
185
			
186
			//debug info
187
			$dtrace = debug_backtrace();
188
			$fileInfo = $dtrace[0]['file'] == __FILE__ ? $dtrace[1] : $dtrace[0];
189
			
190
			$str = $logDate . ' [' . str_pad($levelName, 7 /*warning len*/) . '] ' . ' [' . str_pad($ip, 15) . '] ' . $this->logger . ' : ' . $message . ' ' . '[' . $fileInfo['file'] . '::' . $fileInfo['line'] . ']' . "\n";
191
			$fp = fopen($path, 'a+');
192
			if(is_resource($fp)){
193
				flock($fp, LOCK_EX); // exclusive lock, will get released when the file is closed
194
				fwrite($fp, $str);
195
				fclose($fp);
196
			}
197
		}		
198
		
199
		/**
200
		 * Check if the given log level is valid
201
		 *
202
		 * @param  string  $level the log level
203
		 *
204
		 * @return boolean        true if the given log level is valid, false if not
205
		 */
206
		private static function isValidConfigLevel($level){
207
			$level = strtolower($level);
208
			return in_array($level, self::$validConfigLevel);
209
		}
210
211
		/**
212
		 * Get the log level number for the given level string
213
		 * @param  string $level the log level in string format
214
		 * @return int        the log level in integer format using the predefinied constants
215
		 */
216
		private static function getLevelValue($level){
217
			$level = strtolower($level);
218
			$value = self::NONE;
219
			
220
			//the default value is NONE, so means no need test for NONE
221
			if($level == 'fatal'){
222
				$value = self::FATAL;
223
			}
224
			else if($level == 'error'){
225
				$value = self::ERROR;
226
			}
227
			else if($level == 'warning' || $level == 'warn'){
228
				$value = self::WARNING;
229
			}
230
			else if($level == 'info'){
231
				$value = self::INFO;
232
			}
233
			else if($level == 'debug'){
234
				$value = self::DEBUG;
235
			}
236
			else if($level == 'all'){
237
				$value = self::ALL;
238
			}
239
			return $value;
240
		}
241
242
		/**
243
		 * Get the log level string for the given log level integer
244
		 * @param  integer $level the log level in integer format
245
		 * @return string        the log level in string format
246
		 */
247
		private static function getLevelName($level){
248
			$value = '';
249
			
250
			//the default value is NONE, so means no need test for NONE
251
			if($level == self::FATAL){
252
				$value = 'FATAL';
253
			}
254
			else if($level == self::ERROR){
255
				$value = 'ERROR';
256
			}
257
			else if($level == self::WARNING){
258
				$value = 'WARNING';
259
			}
260
			else if($level == self::INFO){
261
				$value = 'INFO';
262
			}
263
			else if($level == self::DEBUG){
264
				$value = 'DEBUG';
265
			}
266
			//no need for ALL
267
			return $value;
268
		}
269
270
	}
271