1 | <?php |
---|
2 | /** |
---|
3 | * Logging. |
---|
4 | * |
---|
5 | * Log messages to text files. |
---|
6 | * |
---|
7 | * PHP versions 4 and 5 |
---|
8 | * |
---|
9 | * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) |
---|
10 | * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org) |
---|
11 | * |
---|
12 | * Licensed under The MIT License |
---|
13 | * Redistributions of files must retain the above copyright notice. |
---|
14 | * |
---|
15 | * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org) |
---|
16 | * @link http://cakephp.org CakePHP(tm) Project |
---|
17 | * @package cake |
---|
18 | * @subpackage cake.cake.libs |
---|
19 | * @since CakePHP(tm) v 0.2.9 |
---|
20 | * @license MIT License (http://www.opensource.org/licenses/mit-license.php) |
---|
21 | */ |
---|
22 | /** |
---|
23 | * Set up error level constants to be used within the framework if they are not defined within the |
---|
24 | * system. |
---|
25 | * |
---|
26 | */ |
---|
27 | if (!defined('LOG_WARNING')) { |
---|
28 | define('LOG_WARNING', 3); |
---|
29 | } |
---|
30 | if (!defined('LOG_NOTICE')) { |
---|
31 | define('LOG_NOTICE', 4); |
---|
32 | } |
---|
33 | if (!defined('LOG_DEBUG')) { |
---|
34 | define('LOG_DEBUG', 5); |
---|
35 | } |
---|
36 | if (!defined('LOG_INFO')) { |
---|
37 | define('LOG_INFO', 6); |
---|
38 | } |
---|
39 | |
---|
40 | /** |
---|
41 | * Logs messages to configured Log adapters. One or more adapters can be configured |
---|
42 | * using CakeLogs's methods. If you don't configure any adapters, and write to the logs |
---|
43 | * a default FileLog will be autoconfigured for you. |
---|
44 | * |
---|
45 | * @package cake |
---|
46 | * @subpackage cake.cake.libs |
---|
47 | */ |
---|
48 | class CakeLog { |
---|
49 | |
---|
50 | /** |
---|
51 | * An array of connected streams. |
---|
52 | * Each stream represents a callable that will be called when write() is called. |
---|
53 | * |
---|
54 | * @var array |
---|
55 | * @access protected |
---|
56 | */ |
---|
57 | var $_streams = array(); |
---|
58 | |
---|
59 | /** |
---|
60 | * Get an instance |
---|
61 | * |
---|
62 | * @return void |
---|
63 | * @static |
---|
64 | */ |
---|
65 | function &getInstance() { |
---|
66 | static $instance = array(); |
---|
67 | if (!isset($instance[0])) { |
---|
68 | $instance[0] =& new CakeLog(); |
---|
69 | } |
---|
70 | return $instance[0]; |
---|
71 | } |
---|
72 | |
---|
73 | /** |
---|
74 | * Configure and add a new logging stream to CakeLog |
---|
75 | * You can use add loggers from app/libs use app.loggername, or any plugin/libs using plugin.loggername. |
---|
76 | * |
---|
77 | * ### Usage: |
---|
78 | * |
---|
79 | * {{{ |
---|
80 | * CakeLog::config('second_file', array( |
---|
81 | * 'engine' => 'FileLog', |
---|
82 | * 'path' => '/var/logs/my_app/' |
---|
83 | * )); |
---|
84 | * }}} |
---|
85 | * |
---|
86 | * Will configure a FileLog instance to use the specified path. All options that are not `engine` |
---|
87 | * are passed onto the logging adapter, and handled there. Any class can be configured as a logging |
---|
88 | * adapter as long as it implements a `write` method with the following signature. |
---|
89 | * |
---|
90 | * `write($type, $message)` |
---|
91 | * |
---|
92 | * For an explaination of these parameters, see CakeLog::write() |
---|
93 | * |
---|
94 | * @param string $key The keyname for this logger, used to remove the logger later. |
---|
95 | * @param array $config Array of configuration information for the logger |
---|
96 | * @return boolean success of configuration. |
---|
97 | * @static |
---|
98 | */ |
---|
99 | function config($key, $config) { |
---|
100 | if (empty($config['engine'])) { |
---|
101 | trigger_error(__('Missing logger classname', true), E_USER_WARNING); |
---|
102 | return false; |
---|
103 | } |
---|
104 | $self =& CakeLog::getInstance(); |
---|
105 | $className = $self->_getLogger($config['engine']); |
---|
106 | if (!$className) { |
---|
107 | return false; |
---|
108 | } |
---|
109 | unset($config['engine']); |
---|
110 | $self->_streams[$key] = new $className($config); |
---|
111 | return true; |
---|
112 | } |
---|
113 | |
---|
114 | /** |
---|
115 | * Attempts to import a logger class from the various paths it could be on. |
---|
116 | * Checks that the logger class implements a write method as well. |
---|
117 | * |
---|
118 | * @param string $loggerName the plugin.className of the logger class you want to build. |
---|
119 | * @return mixed boolean false on any failures, string of classname to use if search was successful. |
---|
120 | * @access protected |
---|
121 | */ |
---|
122 | function _getLogger($loggerName) { |
---|
123 | list($plugin, $loggerName) = pluginSplit($loggerName); |
---|
124 | |
---|
125 | if ($plugin) { |
---|
126 | App::import('Lib', $plugin . '.log/' . $loggerName); |
---|
127 | } else { |
---|
128 | if (!App::import('Lib', 'log/' . $loggerName)) { |
---|
129 | App::import('Core', 'log/' . $loggerName); |
---|
130 | } |
---|
131 | } |
---|
132 | if (!class_exists($loggerName)) { |
---|
133 | trigger_error(sprintf(__('Could not load logger class %s', true), $loggerName), E_USER_WARNING); |
---|
134 | return false; |
---|
135 | } |
---|
136 | if (!is_callable(array($loggerName, 'write'))) { |
---|
137 | trigger_error( |
---|
138 | sprintf(__('logger class %s does not implement a write method.', true), $loggerName), |
---|
139 | E_USER_WARNING |
---|
140 | ); |
---|
141 | return false; |
---|
142 | } |
---|
143 | return $loggerName; |
---|
144 | } |
---|
145 | |
---|
146 | /** |
---|
147 | * Returns the keynames of the currently active streams |
---|
148 | * |
---|
149 | * @return array Array of configured log streams. |
---|
150 | * @access public |
---|
151 | * @static |
---|
152 | */ |
---|
153 | function configured() { |
---|
154 | $self =& CakeLog::getInstance(); |
---|
155 | return array_keys($self->_streams); |
---|
156 | } |
---|
157 | |
---|
158 | /** |
---|
159 | * Removes a stream from the active streams. Once a stream has been removed |
---|
160 | * it will no longer have messages sent to it. |
---|
161 | * |
---|
162 | * @param string $keyname Key name of a configured stream to remove. |
---|
163 | * @return void |
---|
164 | * @access public |
---|
165 | * @static |
---|
166 | */ |
---|
167 | function drop($streamName) { |
---|
168 | $self =& CakeLog::getInstance(); |
---|
169 | unset($self->_streams[$streamName]); |
---|
170 | } |
---|
171 | |
---|
172 | /** |
---|
173 | * Configures the automatic/default stream a FileLog. |
---|
174 | * |
---|
175 | * @return void |
---|
176 | * @access protected |
---|
177 | */ |
---|
178 | function _autoConfig() { |
---|
179 | if (!class_exists('FileLog')) { |
---|
180 | App::import('Core', 'log/FileLog'); |
---|
181 | } |
---|
182 | $this->_streams['default'] =& new FileLog(array('path' => LOGS)); |
---|
183 | } |
---|
184 | |
---|
185 | /** |
---|
186 | * Writes the given message and type to all of the configured log adapters. |
---|
187 | * Configured adapters are passed both the $type and $message variables. $type |
---|
188 | * is one of the following strings/values. |
---|
189 | * |
---|
190 | * ### Types: |
---|
191 | * |
---|
192 | * - `LOG_WARNING` => 'warning', |
---|
193 | * - `LOG_NOTICE` => 'notice', |
---|
194 | * - `LOG_INFO` => 'info', |
---|
195 | * - `LOG_DEBUG` => 'debug', |
---|
196 | * - `LOG_ERR` => 'error', |
---|
197 | * - `LOG_ERROR` => 'error' |
---|
198 | * |
---|
199 | * ### Usage: |
---|
200 | * |
---|
201 | * Write a message to the 'warning' log: |
---|
202 | * |
---|
203 | * `CakeLog::write('warning', 'Stuff is broken here');` |
---|
204 | * |
---|
205 | * @param string $type Type of message being written |
---|
206 | * @param string $message Message content to log |
---|
207 | * @return boolean Success |
---|
208 | * @access public |
---|
209 | * @static |
---|
210 | */ |
---|
211 | function write($type, $message) { |
---|
212 | if (!defined('LOG_ERROR')) { |
---|
213 | define('LOG_ERROR', 2); |
---|
214 | } |
---|
215 | if (!defined('LOG_ERR')) { |
---|
216 | define('LOG_ERR', LOG_ERROR); |
---|
217 | } |
---|
218 | $levels = array( |
---|
219 | LOG_WARNING => 'warning', |
---|
220 | LOG_NOTICE => 'notice', |
---|
221 | LOG_INFO => 'info', |
---|
222 | LOG_DEBUG => 'debug', |
---|
223 | LOG_ERR => 'error', |
---|
224 | LOG_ERROR => 'error' |
---|
225 | ); |
---|
226 | |
---|
227 | if (is_int($type) && isset($levels[$type])) { |
---|
228 | $type = $levels[$type]; |
---|
229 | } |
---|
230 | $self =& CakeLog::getInstance(); |
---|
231 | if (empty($self->_streams)) { |
---|
232 | $self->_autoConfig(); |
---|
233 | } |
---|
234 | $keys = array_keys($self->_streams); |
---|
235 | foreach ($keys as $key) { |
---|
236 | $logger =& $self->_streams[$key]; |
---|
237 | $logger->write($type, $message); |
---|
238 | } |
---|
239 | return true; |
---|
240 | } |
---|
241 | |
---|
242 | /** |
---|
243 | * An error_handler that will log errors to file using CakeLog::write(); |
---|
244 | * You can control how verbose and what type of errors this error_handler will |
---|
245 | * catch using `Configure::write('log', $value)`. See core.php for more information. |
---|
246 | * |
---|
247 | * |
---|
248 | * @param integer $code Code of error |
---|
249 | * @param string $description Error description |
---|
250 | * @param string $file File on which error occurred |
---|
251 | * @param integer $line Line that triggered the error |
---|
252 | * @param array $context Context |
---|
253 | * @return void |
---|
254 | */ |
---|
255 | function handleError($code, $description, $file = null, $line = null, $context = null) { |
---|
256 | if ($code === 2048 || $code === 8192 || error_reporting() === 0) { |
---|
257 | return; |
---|
258 | } |
---|
259 | switch ($code) { |
---|
260 | case E_PARSE: |
---|
261 | case E_ERROR: |
---|
262 | case E_CORE_ERROR: |
---|
263 | case E_COMPILE_ERROR: |
---|
264 | case E_USER_ERROR: |
---|
265 | $error = 'Fatal Error'; |
---|
266 | $level = LOG_ERROR; |
---|
267 | break; |
---|
268 | case E_WARNING: |
---|
269 | case E_USER_WARNING: |
---|
270 | case E_COMPILE_WARNING: |
---|
271 | case E_RECOVERABLE_ERROR: |
---|
272 | $error = 'Warning'; |
---|
273 | $level = LOG_WARNING; |
---|
274 | break; |
---|
275 | case E_NOTICE: |
---|
276 | case E_USER_NOTICE: |
---|
277 | $error = 'Notice'; |
---|
278 | $level = LOG_NOTICE; |
---|
279 | break; |
---|
280 | default: |
---|
281 | return; |
---|
282 | break; |
---|
283 | } |
---|
284 | $message = $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'; |
---|
285 | CakeLog::write($level, $message); |
---|
286 | } |
---|
287 | } |
---|
288 | |
---|
289 | if (!defined('DISABLE_DEFAULT_ERROR_HANDLING')) { |
---|
290 | $cakeLog =& CakeLog::getInstance(); |
---|
291 | if (PHP5) { |
---|
292 | set_error_handler(array($cakeLog, 'handleError'), error_reporting()); |
---|
293 | } else { |
---|
294 | set_error_handler(array($cakeLog, 'handleError')); |
---|
295 | } |
---|
296 | } |
---|