1  //!-- UTF8
     2  /*
     3  	Oregano Multiuser Server - Version 1.2.0 - January 4th, 2005
     4  
     5  	Web:  www.oregano-server.org
     6  	Mail: info@oregano-server.org
     7  
     8  	Copyright 2003 - 2004 - 2004 Jens Halm / Cologne, Germany
     9  
    10      This library is free software; you can redistribute it and/or
    11      modify it under the terms of the GNU Lesser General Public
    12      License as published by the Free Software Foundation; either
    13      version 2.1 of the License, or (at your option) any later version.
    14  
    15      This library is distributed in the hope that it will be useful,
    16      but WITHOUT ANY WARRANTY; without even the implied warranty of
    17      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    18      Lesser General Public License for more details.
    19  
    20      You should have received a copy of the GNU Lesser General Public
    21      License along with this library; if not, write to the Free Software
    22      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    23  */
    24  
    25  /*
    26  -------------------------------------------
    27  	Classe Log
    28  
    29  	@description :
    30  	Singleton qui les log en fonction de niveaux.
    31  
    32  
    33  	@author Jens Halm copyright http://www.spicefactory.org/
    34  	@author erixtekila copyleft http://www.v-i-a.net  
    35  -------------------------------------------
    36  	version history :
    37  	1.2.0 : 04/02/05
    38  			- Portage en actionscript 2 pour le
    39  			compile time type checking
    40  			- Les LOG_LEVEL sont construits dans le constructeur 
    41  			plutôt que dans le prototype.
    42  			- Correction de warnEnabled par errorEnabled à l'intérieur de error()
    43  			- Suppression de l'implémenation en Singleton.
    44  	1.2.0 : 08/03/05
    45  			- Singleton et gestion (activation) interne des logs
    46  -------------------------------------------
    47  */
    48  
    49  import org.omus.util.iObservable;
    50  import org.omus.util.EventDispatcher;
    51  //import org.omus.util._Error;
    52  
    53  import org.omus.msg.Message;
    54  import org.omus.msg.EnvelopeFactory;
    55  
    56  import org.omus.core.Session;
    57  import org.omus.core.User;
    58  
    59  /**
    60   *	Cette classe gère le log des messages de l'application
    61   *	et les envoie dans la base de données.
    62   *	Plusieurs niveaux y sont implémentés et permettent un audit
    63   *	des messages plus ou moins fin :
    64   *	DEBUG, INFO, WARN et ERROR
    65   *	En fonction du niveau choisi dans <oregano-dev> du fichier config.xml,
    66   *	les logs seront enregistrés côté serveur.
    67   *	<p>
    68   *	Evénements auxquels s'abonner :
    69   *	<ul><li>
    70   *	_event onLog		Généré lors d'un nouvel enregistrement.
    71   *	</li></ul></p>
    72   *
    73   *	Cette classe est implémentée en suivant le modèle Singleton.
    74   *	Un accès global à son instance est obtenu graçe à la méthode getInstance.
    75   *	Elle est aggrémentée par composition des méthodes des sources d'événements (EventDispatcher).
    76   *	@see org.omus.util.EventDispatcher
    77   *	@see org.omus.util.iObservable
    78   *
    79   *	@author Jens Halm copyright http://www.spicefactory.org/
    80   *	@author erixtekila copyleft http://www.v-i-a.net 
    81   *	@version 1.2.0
    82   */
    83  class org.omus.util.Log implements iObservable
    84  {
    85  	//--------------------
    86  	// PROPRIETES
    87  	//--------------------
    88  	/**
    89  	 *	Categorie de niveau de log (Super user ou user) .
    90  	 */
    91  	public var category:Number;
    92  	
    93  	/**
    94  	 *	Niveau de log.
    95  	 */
    96  	public var logLevel:Number;
    97  	
    98  	/**
    99  	 *	
   100  	 */
   101  	private var logCache:Array;	
   102  	
   103  	/**
   104  	 *	Référence au système de génération d'événements.
   105  	 */
   106  	private var _eventSource:EventDispatcher;
   107  	
   108  	/**
   109  	 *	Catégorie Super User
   110  	 */
   111  	public static var CLIENT_OMUS:Number = 9;
   112  	/**
   113  	 *	Catégorie User
   114  	 */
   115  	public static var CLIENT_DEV:Number = 10;
   116  	
   117  	/**
   118  	 *	Niveaux de log
   119  	 */
   120  	private var LEVEL_DEBUG:Number;
   121  	private var LEVEL_INFO:Number;
   122  	private var LEVEL_WARN:Number;
   123  	private var LEVEL_ERROR:Number;
   124  	private var LEVEL_OFF:Number;
   125  	
   126  	/**
   127  	 *	Permet l'énumération des propriétés dans le log.
   128  	 */
   129  	public static var enablePropLog:Boolean = true;
   130  	
   131  	/**
   132  	 *	Référence à l'unique instance de la classe permise.
   133  	 */
   134  	private static var _instance:Log;
   135  	
   136  	//--------------------
   137  	// CONSTRUCTEUR
   138  	//--------------------
   139  	/**
   140  	 *	L'objet User dispose des méthodes d'EventDispatcher par composition.
   141  	 *
   142  	 *	@param cat		Le niveau de log.
   143  	 *	@see org.omus.util.EventDispatcher
   144  	 *	@see org.omus.util.iObservable
   145  	 */
   146  	private function Log(cat:Number)
   147  	{	
   148  		// Composition avec EventDispatcher
   149  		_eventSource = new EventDispatcher();
   150  		
   151  		// Code des niveaux de log
   152  		this.LEVEL_DEBUG = 4;
   153  		this.LEVEL_INFO = 3;
   154  		this.LEVEL_WARN = 2;
   155  		this.LEVEL_ERROR = 1;
   156  		this.LEVEL_OFF = 0;
   157  		
   158  		category = cat;
   159  		logLevel = LEVEL_DEBUG;
   160  		logCache = new Array();
   161  		
   162  		// trace(this+ " installé.");
   163  	}
   164  	
   165  	
   166  	//--------------------
   167  	// METHODES PUBLIQUES
   168  	//--------------------
   169  	/**
   170  	 *	Utilisé dans un contexte littéral
   171  	 *	@return	Une chaine définissant l'objet
   172  	 */
   173  	public function toString():String
   174  	{
   175  		return "[Objet Log]";
   176  	}
   177  	
   178  	/**
   179  	 *	Mode Debug actif
   180  	 *
   181  	 *	@return Un booléen donnant le résultat de l'opération
   182  	 */
   183  	public function debugEnabled ():Boolean
   184  	{
   185  		return (logLevel >= LEVEL_DEBUG);
   186  	}
   187  	
   188  	/**
   189  	 *	Mode Info actif
   190  	 *
   191  	 *	@return Un booléen donnant le résultat de l'opération
   192  	 */
   193  	public function infoEnabled ():Boolean
   194  	{
   195  		return (logLevel >= LEVEL_INFO);
   196  	}
   197  
   198  	
   199  	/**
   200  	 *	Mode Warn actif
   201  	 *
   202  	 *	@return Un booléen donnant le résultat de l'opération
   203  	 */
   204  	public function warnEnabled ():Boolean
   205  	{
   206  		return (logLevel >= LEVEL_WARN);
   207  	}
   208  
   209  	/**
   210  	 *	Mode Error actif
   211  	 *
   212  	 *	@return Un booléen donnant le résultat de l'opération
   213  	 */
   214  	public function errorEnabled ():Boolean
   215  	{
   216  		return (logLevel >= LEVEL_ERROR);
   217  	}
   218  	
   219  	/**
   220  	 *	Envoie un message de niveau Debug
   221  	 *
   222  	 *	@param errCode		Code d'erreur.
   223  	 *	@param info			Message personnalisé.
   224  	 */
   225  	public function debug (errCode:String, info:String):Void
   226  	{
   227  		if (debugEnabled())
   228  		{
   229  			logLocal("DEBUG", errCode, info);
   230  			logRemote(LEVEL_DEBUG, errCode, info);
   231  		}
   232  	}
   233  	
   234  	/**
   235  	 *	Envoie un message de niveau Info
   236  	 *
   237  	 *	@param errCode		Code d'erreur.
   238  	 *	@param info			Message personnalisé.
   239  	 */
   240  	public function info (errCode:String, info:String):Void
   241  	{
   242  		if (infoEnabled())
   243  		{
   244  			logLocal("INFO", errCode, info);
   245  			logRemote(LEVEL_INFO, errCode, info);
   246  		}
   247  	}
   248  
   249  	/**
   250  	 *	Envoie un message de niveau Warn
   251  	 *
   252  	 *	@param errCode		Code d'erreur.
   253  	 *	@param info			Message personnalisé.
   254  	 */
   255  	public function warn (errCode:String, info:String):Void
   256  	{
   257  		if (warnEnabled())
   258  		{
   259  			logLocal("WARN", errCode, info);
   260  			logRemote(LEVEL_WARN, errCode, info);
   261  		}
   262  	}
   263  
   264  	/**
   265  	 *	Envoie un message de niveau Error
   266  	 *
   267  	 *	@param errCode		Code d'erreur.
   268  	 *	@param info			Message personnalisé.
   269  	 */
   270  	public function error (errCode:String, info:String):Void
   271  	{
   272  		if (errorEnabled())
   273  		{
   274  			logLocal("ERROR", errCode, info);
   275  			logRemote(LEVEL_ERROR, errCode, info);
   276  		}
   277  	}
   278  	
   279  	/**
   280  	 *	Soumet les messages en local.
   281  	 *	Génère un événement onLog aux observateurs.
   282  	 *
   283  	 *	@param levelStr		Niveau du message.
   284  	 *	@param errCode		Code d'erreur.
   285  	 *	@param info			Message personnalisé.
   286  	 */
   287  	public function logLocal (levelStr:String, errCode:String, info:String):Void
   288  	{
   289  		// Plus haut niveau, rajoute cld à l'erreur.
   290  		if (category == org.omus.util.Log.CLIENT_DEV) errCode = "cld-" + errCode;
   291  		//? Formatage dans la sortie ?
   292  		levelStr += (levelStr.length == 4) ? " #" : " " ;
   293  		var logStr = "\n##### " + levelStr + "############################################\n\n";
   294  		logStr += "error code  - " + errCode + "\ndescription - " + org.omus.util._Error.desc[errCode];
   295  		if (info != undefined && info.length > 0) {
   296  			logStr += "\n\n===== additional info ==================================\n\n" + info;
   297  		}
   298  		logStr += "\n\n########################################################\n\n";
   299  		
   300  		// Sortie 
   301  		trace (logStr); 
   302  		// Broadcast
   303  		fireEvent("", "onLog", "\n" + logStr);
   304  	}
   305  	
   306  	/**
   307  	 *	Soumet les messages au serveur.
   308  	 *
   309  	 *	@param level		Le niveau en numérique.
   310  	 *	@param errCode		Code d'erreur.
   311  	 *	@param info			Message personnalisé.
   312  	 */
   313  	public function logRemote (level:Number, errCode:String, info:String):Void
   314  	{
   315  		if (category == org.omus.util.Log.CLIENT_DEV) errCode = "cld-" + errCode;
   316  		// Message
   317  		var msg = new Message("");
   318  		var attach = msg.getAttachment();
   319  		attach.level = level;
   320  		attach.category = this.category;
   321  		attach.errorCode = errCode;
   322  		attach.info = info + "\nplayer version: " + System.capabilities.version;
   323  		
   324  		// Message conservé jusqu'à reconnection ?
   325  		// TODO : Accès Singleton
   326  		var session = Session.getInstance();
   327  		var user = User.getInstance();
   328  		var envFactory = EnvelopeFactory.getInstance();
   329  		
   330  		if (session.isConnected()) {
   331  			attach.info += "\nusername: " + user.getName();
   332  			session.sendMessage(envFactory.getOutgoing(msg, "log"));
   333  		} else {
   334  			logCache.push(msg);
   335  		}
   336  	}
   337  	
   338  	/**
   339  	 *	Envoi les logs conservés dans le cache utilisateur.
   340  	 */
   341  	public function sendCache ():Void
   342  	{
   343  		// TODO : Accès Singleton
   344  		var envFactory = EnvelopeFactory.getInstance();
   345  		var session = Session.getInstance();
   346  		var user = User.getInstance();
   347  		
   348  		// Autant de message que sauvegardés.
   349  		var len = logCache.length;
   350  		for (var i = 0; i < len; i++)
   351  		{
   352  			var msg = logCache[i];
   353  			var attach = msg.getAttachment();
   354  			attach.info += "\nusername: " + user.getName();
   355  			var env = envFactory.getOutgoing(msg, "log");
   356  			session.sendMessage(env);
   357  		}
   358  		clearCache();
   359  	}
   360  	
   361  	/**
   362  	 *	Supprime les logs du cache.
   363  	 */
   364  	public function clearCache ():Void
   365  	{
   366  		logCache = new Array();
   367  	}
   368  
   369  	/**
   370  	 *	Définit le niveau de log.
   371  	 *	Appelé au login.
   372  	 *
   373  	 *	@param ll		Niveau de log.
   374  	 */
   375  	public function setLogLevel (ll:Number):Void
   376  	{
   377  		// called on login
   378  		logLevel = ll;
   379  	}
   380  	
   381  	//*** Implémentation de iObservable ***\
   382  	/**
   383  	 *	Notifie les observateurs d'un événement.
   384  	 *
   385  	 *	@param logLevel Une chaine caractérisant le niveau de logging de l'information.
   386  	 *	@param eventName Nom de l'événement.
   387  	 *	@param arg1		[option] Autant de paramètres de voulu.
   388  	 */
   389  	private function fireEvent (logLevel:String, eventName:String):Void
   390  	{
   391  		_eventSource.fireEvent.apply (_eventSource, arguments);
   392  	}
   393  	
   394  	/**
   395  	 *	Ajoute un nouvel observateur.
   396  	 * 
   397  	 *	@param		listener Référence de l'observateur.
   398  	 *	@return Un booléen indiquant la réussite de l'opération.
   399  	 */
   400  	public function addListener (listener:Object):Boolean
   401  	{
   402  		return _eventSource.addListener(listener);
   403  	}
   404  	
   405  	/**
   406  	 *	Supprime un observateur.
   407  	 *
   408  	 *	@param		listener Référence de l'observateur.
   409  	 *	@return Un booléen indiquant la réussite de l'opération.
   410  	 */
   411  	public function removeListener (listener:Object):Boolean
   412  	{
   413  		return _eventSource.removeListener(listener);
   414  	}
   415  	
   416  	/**
   417  	 *	Supprime tous les abonnés.
   418  	 */
   419  	public function removeAllListeners ():Void
   420  	{
   421  		_eventSource.removeAllListeners();
   422  	}
   423  	
   424  	/**
   425  	 *	Retourne le nombre d'observateurs.
   426  	 *
   427  	 *	@return Le nombre d'observateurs enregistrés.
   428  	 */
   429  	public function countListeners ():Number
   430  	{
   431  		return _eventSource.countListeners();
   432  	}
   433  	
   434  	//--------------------
   435  	// METHODES STATIQUES
   436  	//--------------------
   437  	/**
   438  	 *	Accès global à la référence du Singleton
   439  	 *	@return	Une référence à la classe
   440  	 */
   441  	public static function getInstance():Log
   442  	{
   443  		if(_instance == undefined)
   444  		{
   445  			// Flash MX, 2k4
   446  			if (typeof(_global.oregano) != "object") _global.oregano = new Object();
   447  			
   448  			// Gestion des Logs
   449  			// Logs internes soumis au serveur
   450  			_global.oregano.iLog = new Log(org.omus.util.Log.CLIENT_OMUS);
   451  			
   452  			// Protect from deleting
   453  			_global.ASSetPropFlags (_global, ["oregano"], 4);
   454  			_global.ASSetPropFlags (_global.oregano, ["iLog"], 4);
   455  			
   456  			_instance = new Log(org.omus.util.Log.CLIENT_DEV);
   457  		}
   458  		return _instance;
   459  	}
   460  	
   461  	/**
   462  	 *	Formate le log d'un objet
   463  	 *
   464  	 *	@param obj		Référence à l'objet.
   465  	 *	@param indent	Une chaine de séparation.
   466  	 *	@return La chaine formatée.
   467  	 */
   468  	public static function formatObject (obj:Object, indent:Number):String
   469  	{
   470  		var cnt = 0;
   471  		for (var each:String in obj) cnt++;
   472  		var s = "Object(" + cnt + "):";
   473  		for (var each:String in obj)
   474  		{
   475  			s += "\n";
   476  			for (var idx = 0; idx < indent; idx++) s += "  ";
   477  			s += each + " = " + org.omus.util.Log.format(obj[each], indent + 1);
   478  		}
   479  		return s;
   480  	}
   481  	
   482  	/**
   483  	 *	Formate le log d'un tableau
   484  	 *
   485  	 *	@param arr		Une référence aui tableau.
   486  	 *	@param indent	Une chaine de séparation.
   487  	 */
   488  	public static function formatArray (arr:Object, indent:Number):String
   489  	{
   490  		var s = "Array(" + arr.length + "):";
   491  		var len = arr.length;
   492  		for (var i = 0; i < len; i++)
   493  		{
   494  			s += "\n";
   495  			for (var idx = 0; idx < indent; idx++) s += "  ";
   496  			s += "[" + i + "] = " + org.omus.util.Log.format(arr[i], indent + 1);
   497  		}
   498  		return s;
   499  	}
   500  	
   501  	/**
   502  	 *	Formate une sortie de la hiérarchie d'un object soumis.
   503  	 *
   504  	 *	@param val		Valeur à logger.
   505  	 *	@param indent	Une chaine de séparation.
   506  	 */
   507  	public static function format (val:Object, indent:Number):String
   508  	{
   509  		if (typeof(val) != "object") return val.toString();
   510  		var proto = val.__proto__;
   511  		if (proto == Object.prototype) return org.omus.util.Log.formatObject(val, indent);
   512  		if (proto == Array.prototype) return org.omus.util.Log.formatArray(val, indent);
   513  		var constr = val.constructor.toString();
   514  		org.omus.util.Log.enablePropLog = false;
   515  		if (constr.substr(0, 5) == "org.omus." && typeof(val.format) == "function") return val.format(indent);
   516  		org.omus.util.Log.enablePropLog = true;
   517  		return val.toString();
   518  	}
   519  	
   520  	/**
   521  	 *	Utilisé dans un contexte littéral
   522  	 *	@return	Une chaine définissant l'objet
   523  	 */
   524  	public static function toLog():String
   525  	{
   526  		return "[Objet Log]";
   527  	}
   528  }
   529