PageRenderTime 47ms CodeModel.GetById 2ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/js/yii/logging/CLogger.js

http://github.com/phpnode/YiiJS
JavaScript | 339 lines | 200 code | 6 blank | 133 comment | 52 complexity | 04c6c3ae30c3ae412449de058faeacc0 MD5 | raw file
  1/*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
  2/**
  3 * CLogger records log messages in memory.
  4 * 
  5 * CLogger implements the methods to retrieve the messages with
  6 * various filter conditions, including log levels and log categories.
  7 * 
  8 * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
  9 * @version $Id: CLogger.php 3137 2011-03-28 11:08:06Z mdomba $
 10 * @package system.logging
 11 * @since 1.0
 12 * @author Charles Pick
 13 * @class
 14 * @extends Yii.CComponent
 15 */
 16Yii.CLogger = function() {
 17};
 18Yii.CLogger.prototype = new Yii.CComponent();
 19Yii.CLogger.prototype.constructor =  Yii.CLogger;
 20/**
 21 * @const
 22 */
 23Yii.CLogger.prototype.LEVEL_TRACE = 'trace';
 24/**
 25 * @const
 26 */
 27Yii.CLogger.prototype.LEVEL_WARNING = 'warning';
 28/**
 29 * @const
 30 */
 31Yii.CLogger.prototype.LEVEL_ERROR = 'error';
 32/**
 33 * @const
 34 */
 35Yii.CLogger.prototype.LEVEL_INFO = 'info';
 36/**
 37 * @const
 38 */
 39Yii.CLogger.prototype.LEVEL_PROFILE = 'profile';
 40/**
 41 * @var {Integer} how many messages should be logged before they are flushed to destinations.
 42 * Defaults to 10,000, meaning for every 10,000 messages, the {@link flush} method will be
 43 * automatically invoked once. If this is 0, it means messages will never be flushed automatically.
 44 * @since 1.1.0
 45 */
 46Yii.CLogger.prototype.autoFlush = 10000;
 47/**
 48 * @var {Array} log messages
 49 */
 50Yii.CLogger.prototype._logs = [];
 51/**
 52 * @var {Integer} number of log messages
 53 */
 54Yii.CLogger.prototype._logCount = 0;
 55/**
 56 * @var {Array} log levels for filtering (used when filtering)
 57 */
 58Yii.CLogger.prototype._levels = null;
 59/**
 60 * @var {Array} log categories for filtering (used when filtering)
 61 */
 62Yii.CLogger.prototype._categories = null;
 63/**
 64 * @var {Array} the profiling results (category, token => time in seconds)
 65 * @since 1.0.6
 66 */
 67Yii.CLogger.prototype._timings = null;
 68/**
 69 * Logs a message.
 70 * Messages logged by this method may be retrieved back via {@link getLogs}.
 71 * @param {String} message message to be logged
 72 * @param {String} level level of the message (e.g. 'Trace', 'Warning', 'Error'). It is case-insensitive.
 73 * @param {String} category category of the message (e.g. 'system.web'). It is case-insensitive.
 74 * @see getLogs
 75 */
 76Yii.CLogger.prototype.log = function (message, level, category) {
 77		if (level === undefined) {
 78			level = 'info';
 79		}
 80		if (category === undefined) {
 81			category = 'application';
 82		}
 83		this._logs.push([message,level,category,php.microtime(true)]);
 84		this._logCount++;
 85		if(this.autoFlush>0 && this._logCount>=this.autoFlush) {
 86			this.flush();
 87		}
 88	};
 89/**
 90 * Retrieves log messages.
 91 * 
 92 * Messages may be filtered by log levels and/or categories.
 93 * A level filter is specified by a list of levels separated by comma or space
 94 * (e.g. 'trace, error'). A category filter is similar to level filter
 95 * (e.g. 'system, system.web'). A difference is that in category filter
 96 * you can use pattern like 'system.*' to indicate all categories starting
 97 * with 'system'.
 98 * 
 99 * If you do not specify level filter, it will bring back logs at all levels.
100 * The same applies to category filter.
101 * 
102 * Level filter and category filter are combinational, i.e., only messages
103 * satisfying both filter conditions will be returned.
104 * 
105 * @param {String} levels level filter
106 * @param {String} categories category filter
107 * @returns {Array} list of messages. Each array elements represents one message
108 * with the following structure:
109 * array(
110 *   [0] => message (string)
111 *   [1] => level (string)
112 *   [2] => category (string)
113 *   [3] => timestamp (float, obtained by microtime(true));
114 */
115Yii.CLogger.prototype.getLogs = function (levels, categories) {
116		var ret, self;
117		if (levels === undefined) {
118			levels = '';
119			this._levels = [];
120		}
121		else {
122			this._levels=levels.toLowerCase().split(/[\s,]+/);
123		}
124		if (categories === undefined) {
125			categories = '';
126			this._categories = [];
127		}
128		else {
129			this._categories=categories.toLowerCase().split(/[\s,]+/);	
130		}
131		
132		
133		self = this;
134		if(php.empty(levels) && php.empty(categories)) {
135			return this._logs;
136		}		
137		else if(php.empty(levels)) {
138			
139			return Yii.filter(this._logs,function(value, k, arr) {
140				var matched = false, cat = value[2].toLowerCase(), c;
141				Yii.forEach(self._categories, function(i, category) {
142					if(cat===category || ((c=php.rtrim(category,'.*'))!==category && php.strpos(cat,c)===0)) {
143						matched = true;
144						return false;
145					}
146				});
147				return matched ? value : false;
148			});
149			
150		}
151		else if(php.empty(categories)) {
152			return Yii.filter(this._logs,function(value, k, arr) {
153				var matched = false, matchLevel = value[1].toLowerCase();
154				Yii.forEach(self._levels, function(i, level) {
155					if (level === matchLevel) {
156						matched = true;
157						return false;
158					}
159				});
160				return matched ? value : false;
161			});
162		}
163		else {
164			return Yii.filter(Yii.filter(this._logs,function(value, k, arr) {
165				var matched = false, cat = value[2].toLowerCase(), c;
166				Yii.forEach(self._categories, function(i, category) {
167					if(cat===category || ((c=php.rtrim(category,'.*'))!==category && php.strpos(cat,c)===0)) {
168						matched = true;
169						return false;
170					}
171				});
172				return matched ? value : false;
173			}), function(value, k, arr) {
174				var matched = false, matchLevel = value[1].toLowerCase();
175				Yii.forEach(self._levels, function(i, level) {
176					if (level === matchLevel) {
177						matched = true;
178						return false;
179					}
180				});
181				return matched ? value : false;
182			});
183			
184		}
185	};
186/**
187 * Filter function used by {@link getLogs}
188 * @param {Array} value element to be filtered
189 * @returns {Array} valid log, false if not.
190 */
191Yii.CLogger.prototype.filterByCategory = function (value) {
192		var i, cat, category, c;
193		for (i in this._categories) {
194			if (this._categories.hasOwnProperty(i)) {
195				category = this._categories[i];
196				cat=value[2].toLowerCase();
197				if(cat===category || ((c=php.rtrim(category,'.*'))!==category && php.strpos(cat,c)===0)) {
198					return value;
199				}
200			}
201		}
202		return false;
203	};
204/**
205 * Filter function used by {@link getLogs}
206 * @param {Array} value element to be filtered
207 * @returns {Array} valid log, false if not.
208 */
209Yii.CLogger.prototype.filterByLevel = function (value) {
210		var matched = false, matchLevel = value[1].toLowerCase();
211		
212		Yii.forEach(this._levels, function(i, level) {
213			console.log(level);
214			if (level === matchLevel) {
215				matched = true;
216				return false;
217			}
218		});
219		return matched ? value : false;
220	};
221/**
222 * Returns the total time for serving the current request.
223 * This method calculates the difference between now and the timestamp
224 * defined by constant YII_BEGIN_TIME.
225 * To estimate the execution time more accurately, the constant should
226 * be defined as early as possible (best at the beginning of the entry script.)
227 * @returns {Float} the total time for serving the current request.
228 */
229Yii.CLogger.prototype.getExecutionTime = function () {
230		return php.microtime(true)-YII_BEGIN_TIME;
231	};
232/**
233 * Not Available in JavaScript, always returns 0
234 * @returns {Integer} memory usage of the application (in bytes).
235 */
236Yii.CLogger.prototype.getMemoryUsage = function () {
237		return 0;
238	};
239/**
240 * Returns the profiling results.
241 * The results may be filtered by token and/or category.
242 * If no filter is specified, the returned results would be an array with each element
243 * being array($token,$category,$time).
244 * If a filter is specified, the results would be an array of timings.
245 * @param {String} token token filter. Defaults to null, meaning not filtered by token.
246 * @param {String} category category filter. Defaults to null, meaning not filtered by category.
247 * @param {Boolean} refresh whether to refresh the internal timing calculations. If false,
248 * only the first time calling this method will the timings be calculated internally.
249 * @returns {Array} the profiling results.
250 * @since 1.0.6
251 */
252Yii.CLogger.prototype.getProfilingResults = function (token, category, refresh) {
253		var results, i, timing;
254		if (token === undefined) {
255			token = null;
256		}
257		if (category === undefined) {
258			category = null;
259		}
260		if (refresh === undefined) {
261			refresh = false;
262		}
263		if(this._timings===null || refresh) {
264			this.calculateTimings();
265		}
266		if(token===null && category===null) {
267			return this._timings;
268		}
269		results=[];
270		for (i in this._timings) {
271			if (this._timings.hasOwnProperty(i)) {
272				timing = this._timings[i];
273				if((category===null || timing[1]===category) && (token===null || timing[0]===token)) {
274					results.push(timing[2]);
275				}
276			}
277		}
278		return results;
279	};
280Yii.CLogger.prototype.calculateTimings = function () {
281		var stack, i, log, message, level, category, timestamp, token, last, delta, now;
282		this._timings=[];
283		stack=[];
284		for (i in this._logs) {
285			if (this._logs.hasOwnProperty(i)) {
286				log = this._logs[i];
287				if(log[1]!==Yii.CLogger.prototype.LEVEL_PROFILE) {
288					continue;
289				}
290				message = log[0];
291				level = log[1];
292				category = log[2];
293				timestamp = log[3];
294				if(!php.strncasecmp(message,'begin:',6)) {
295					log[0]=message.slice(6);
296					stack.push(log);
297				}
298				else if(!php.strncasecmp(message,'end:',4)) {
299					token=message.slice(4);
300					if((last=php.array_pop(stack))!==null && last[0]===token) {
301						delta=log[3]-last[3];
302						this._timings.push([message,category,delta]);
303					}
304					else {
305						throw new Yii.CException(Yii.t('yii','CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
306							{'{token}':token}));
307					}
308				}
309			}
310		}
311		now=php.microtime(true);
312		while((last=php.array_pop(stack))!==null) {
313			delta=now-last[3];
314			this._timings.push([last[0],last[2],delta]);
315		}
316	};
317/**
318 * Removes all recorded messages from the memory.
319 * This method will raise an {@link onFlush} event.
320 * The attached event handlers can process the log messages before they are removed.
321 * @param {Boolean} dumpLogs whether to process the logs
322 * @since 1.1.0
323 */
324Yii.CLogger.prototype.flush = function (dumpLogs) {
325		if (dumpLogs === undefined) {
326			dumpLogs = false;
327		}
328		this.onFlush(new Yii.CEvent(this, {'dumpLogs':dumpLogs}));
329		this._logs=[];
330		this._logCount=0;
331	};
332/**
333 * Raises an <code>onFlush</code> event.
334 * @param {Yii.CEvent} event the event parameter
335 * @since 1.1.0
336 */
337Yii.CLogger.prototype.onFlush = function (event) {
338		this.raiseEvent('onFlush', event);
339	}