~horux-dev/horux-webcli/thfo

« back to all changes in this revision

Viewing changes to yii/framework/logging/CLogger.php

  • Committer: Thierry Forchelet
  • Date: 2011-02-25 13:30:15 UTC
  • Revision ID: thierry.forchelet@letux.ch-20110225133015-zxyj9w7sqv8ly971
Initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * CLogger class file
 
4
 *
 
5
 * @author Qiang Xue <qiang.xue@gmail.com>
 
6
 * @link http://www.yiiframework.com/
 
7
 * @copyright Copyright &copy; 2008-2011 Yii Software LLC
 
8
 * @license http://www.yiiframework.com/license/
 
9
 */
 
10
 
 
11
/**
 
12
 * CLogger records log messages in memory.
 
13
 *
 
14
 * CLogger implements the methods to retrieve the messages with
 
15
 * various filter conditions, including log levels and log categories.
 
16
 *
 
17
 * @author Qiang Xue <qiang.xue@gmail.com>
 
18
 * @version $Id: CLogger.php 2799 2011-01-01 19:31:13Z qiang.xue $
 
19
 * @package system.logging
 
20
 * @since 1.0
 
21
 */
 
22
class CLogger extends CComponent
 
23
{
 
24
        const LEVEL_TRACE='trace';
 
25
        const LEVEL_WARNING='warning';
 
26
        const LEVEL_ERROR='error';
 
27
        const LEVEL_INFO='info';
 
28
        const LEVEL_PROFILE='profile';
 
29
 
 
30
        /**
 
31
         * @var integer how many messages should be logged before they are flushed to destinations.
 
32
         * Defaults to 10,000, meaning for every 10,000 messages, the {@link flush} method will be
 
33
         * automatically invoked once. If this is 0, it means messages will never be flushed automatically.
 
34
         * @since 1.1.0
 
35
         */
 
36
        public $autoFlush=10000;
 
37
        /**
 
38
         * @var array log messages
 
39
         */
 
40
        private $_logs=array();
 
41
        /**
 
42
         * @var integer number of log messages
 
43
         */
 
44
        private $_logCount=0;
 
45
        /**
 
46
         * @var array log levels for filtering (used when filtering)
 
47
         */
 
48
        private $_levels;
 
49
        /**
 
50
         * @var array log categories for filtering (used when filtering)
 
51
         */
 
52
        private $_categories;
 
53
        /**
 
54
         * @var array the profiling results (category, token => time in seconds)
 
55
         * @since 1.0.6
 
56
         */
 
57
        private $_timings;
 
58
 
 
59
        /**
 
60
         * Logs a message.
 
61
         * Messages logged by this method may be retrieved back via {@link getLogs}.
 
62
         * @param string $message message to be logged
 
63
         * @param string $level level of the message (e.g. 'Trace', 'Warning', 'Error'). It is case-insensitive.
 
64
         * @param string $category category of the message (e.g. 'system.web'). It is case-insensitive.
 
65
         * @see getLogs
 
66
         */
 
67
        public function log($message,$level='info',$category='application')
 
68
        {
 
69
                $this->_logs[]=array($message,$level,$category,microtime(true));
 
70
                $this->_logCount++;
 
71
                if($this->autoFlush>0 && $this->_logCount>=$this->autoFlush)
 
72
                        $this->flush();
 
73
        }
 
74
 
 
75
        /**
 
76
         * Retrieves log messages.
 
77
         *
 
78
         * Messages may be filtered by log levels and/or categories.
 
79
         * A level filter is specified by a list of levels separated by comma or space
 
80
         * (e.g. 'trace, error'). A category filter is similar to level filter
 
81
         * (e.g. 'system, system.web'). A difference is that in category filter
 
82
         * you can use pattern like 'system.*' to indicate all categories starting
 
83
         * with 'system'.
 
84
         *
 
85
         * If you do not specify level filter, it will bring back logs at all levels.
 
86
         * The same applies to category filter.
 
87
         *
 
88
         * Level filter and category filter are combinational, i.e., only messages
 
89
         * satisfying both filter conditions will be returned.
 
90
         *
 
91
         * @param string $levels level filter
 
92
         * @param string $categories category filter
 
93
         * @return array list of messages. Each array elements represents one message
 
94
         * with the following structure:
 
95
         * array(
 
96
         *   [0] => message (string)
 
97
         *   [1] => level (string)
 
98
         *   [2] => category (string)
 
99
         *   [3] => timestamp (float, obtained by microtime(true));
 
100
         */
 
101
        public function getLogs($levels='',$categories='')
 
102
        {
 
103
                $this->_levels=preg_split('/[\s,]+/',strtolower($levels),-1,PREG_SPLIT_NO_EMPTY);
 
104
                $this->_categories=preg_split('/[\s,]+/',strtolower($categories),-1,PREG_SPLIT_NO_EMPTY);
 
105
                if(empty($levels) && empty($categories))
 
106
                        return $this->_logs;
 
107
                else if(empty($levels))
 
108
                        return array_values(array_filter(array_filter($this->_logs,array($this,'filterByCategory'))));
 
109
                else if(empty($categories))
 
110
                        return array_values(array_filter(array_filter($this->_logs,array($this,'filterByLevel'))));
 
111
                else
 
112
                {
 
113
                        $ret=array_values(array_filter(array_filter($this->_logs,array($this,'filterByLevel'))));
 
114
                        return array_values(array_filter(array_filter($ret,array($this,'filterByCategory'))));
 
115
                }
 
116
        }
 
117
 
 
118
        /**
 
119
         * Filter function used by {@link getLogs}
 
120
         * @param array $value element to be filtered
 
121
         * @return array valid log, false if not.
 
122
         */
 
123
        private function filterByCategory($value)
 
124
        {
 
125
                foreach($this->_categories as $category)
 
126
                {
 
127
                        $cat=strtolower($value[2]);
 
128
                        if($cat===$category || (($c=rtrim($category,'.*'))!==$category && strpos($cat,$c)===0))
 
129
                                return $value;
 
130
                }
 
131
                return false;
 
132
        }
 
133
 
 
134
        /**
 
135
         * Filter function used by {@link getLogs}
 
136
         * @param array $value element to be filtered
 
137
         * @return array valid log, false if not.
 
138
         */
 
139
        private function filterByLevel($value)
 
140
        {
 
141
                return in_array(strtolower($value[1]),$this->_levels)?$value:false;
 
142
        }
 
143
 
 
144
        /**
 
145
         * Returns the total time for serving the current request.
 
146
         * This method calculates the difference between now and the timestamp
 
147
         * defined by constant YII_BEGIN_TIME.
 
148
         * To estimate the execution time more accurately, the constant should
 
149
         * be defined as early as possible (best at the beginning of the entry script.)
 
150
         * @return float the total time for serving the current request.
 
151
         */
 
152
        public function getExecutionTime()
 
153
        {
 
154
                return microtime(true)-YII_BEGIN_TIME;
 
155
        }
 
156
 
 
157
        /**
 
158
         * Returns the memory usage of the current application.
 
159
         * This method relies on the PHP function memory_get_usage().
 
160
         * If it is not available, the method will attempt to use OS programs
 
161
         * to determine the memory usage. A value 0 will be returned if the
 
162
         * memory usage can still not be determined.
 
163
         * @return integer memory usage of the application (in bytes).
 
164
         */
 
165
        public function getMemoryUsage()
 
166
        {
 
167
                if(function_exists('memory_get_usage'))
 
168
                        return memory_get_usage();
 
169
                else
 
170
                {
 
171
                        $output=array();
 
172
                        if(strncmp(PHP_OS,'WIN',3)===0)
 
173
                        {
 
174
                                exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST',$output);
 
175
                                return isset($output[5])?preg_replace('/[\D]/','',$output[5])*1024 : 0;
 
176
                        }
 
177
                        else
 
178
                        {
 
179
                                $pid=getmypid();
 
180
                                exec("ps -eo%mem,rss,pid | grep $pid", $output);
 
181
                                $output=explode("  ",$output[0]);
 
182
                                return isset($output[1]) ? $output[1]*1024 : 0;
 
183
                        }
 
184
                }
 
185
        }
 
186
 
 
187
        /**
 
188
         * Returns the profiling results.
 
189
         * The results may be filtered by token and/or category.
 
190
         * If no filter is specified, the returned results would be an array with each element
 
191
         * being array($token,$category,$time).
 
192
         * If a filter is specified, the results would be an array of timings.
 
193
         * @param string $token token filter. Defaults to null, meaning not filtered by token.
 
194
         * @param string $category category filter. Defaults to null, meaning not filtered by category.
 
195
         * @param boolean $refresh whether to refresh the internal timing calculations. If false,
 
196
         * only the first time calling this method will the timings be calculated internally.
 
197
         * @return array the profiling results.
 
198
         * @since 1.0.6
 
199
         */
 
200
        public function getProfilingResults($token=null,$category=null,$refresh=false)
 
201
        {
 
202
                if($this->_timings===null || $refresh)
 
203
                        $this->calculateTimings();
 
204
                if($token===null && $category===null)
 
205
                        return $this->_timings;
 
206
                $results=array();
 
207
                foreach($this->_timings as $timing)
 
208
                {
 
209
                        if(($category===null || $timing[1]===$category) && ($token===null || $timing[0]===$token))
 
210
                                $results[]=$timing[2];
 
211
                }
 
212
                return $results;
 
213
        }
 
214
 
 
215
        private function calculateTimings()
 
216
        {
 
217
                $this->_timings=array();
 
218
 
 
219
                $stack=array();
 
220
                foreach($this->_logs as $log)
 
221
                {
 
222
                        if($log[1]!==CLogger::LEVEL_PROFILE)
 
223
                                continue;
 
224
                        list($message,$level,$category,$timestamp)=$log;
 
225
                        if(!strncasecmp($message,'begin:',6))
 
226
                        {
 
227
                                $log[0]=substr($message,6);
 
228
                                $stack[]=$log;
 
229
                        }
 
230
                        else if(!strncasecmp($message,'end:',4))
 
231
                        {
 
232
                                $token=substr($message,4);
 
233
                                if(($last=array_pop($stack))!==null && $last[0]===$token)
 
234
                                {
 
235
                                        $delta=$log[3]-$last[3];
 
236
                                        $this->_timings[]=array($message,$category,$delta);
 
237
                                }
 
238
                                else
 
239
                                        throw new CException(Yii::t('yii','CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
 
240
                                                array('{token}'=>$token)));
 
241
                        }
 
242
                }
 
243
 
 
244
                $now=microtime(true);
 
245
                while(($last=array_pop($stack))!==null)
 
246
                {
 
247
                        $delta=$now-$last[3];
 
248
                        $this->_timings[]=array($last[0],$last[2],$delta);
 
249
                }
 
250
        }
 
251
 
 
252
        /**
 
253
         * Removes all recorded messages from the memory.
 
254
         * This method will raise an {@link onFlush} event.
 
255
         * The attached event handlers can process the log messages before they are removed.
 
256
         * @since 1.1.0
 
257
         */
 
258
        public function flush()
 
259
        {
 
260
                $this->onFlush(new CEvent($this));
 
261
                $this->_logs=array();
 
262
                $this->_logCount=0;
 
263
        }
 
264
 
 
265
        /**
 
266
         * Raises an <code>onFlush</code> event.
 
267
         * @param CEvent $event the event parameter
 
268
         * @since 1.1.0
 
269
         */
 
270
        public function onFlush($event)
 
271
        {
 
272
                $this->raiseEvent('onFlush', $event);
 
273
        }
 
274
}