Pour ma part, je considère les logs, les traces et le suivi des utilisateurs comme importants mais je distingue les 3.
Pour moi une trace sert au débuggage de l'application.
Les traces indiquent ce par quoi passe le code et permet de suivre toutes les actions.
Les traces sont stockés dans des fichiers textes horodatés et j'ai un fichier par Objet.
Voici un exemple de trace généré
Code PHP :
27/12/2007 11:21:45 | INFO | BuildingModel | 10 | [BuildingModel::__construct] ==> Begin
27/12/2007 11:21:45 | INFO | BuildingModel | 11 | [BuildingModel::__construct] ==> End
27/12/2007 11:21:47 | INFO | BuildingModel | 34 | [BuildingModel::loadBuildingByPlanet] ==> Begin
27/12/2007 11:21:47 | DEBUG | BuildingModel | 35 | [BuildingModel::loadBuildingByPlanet] ==> Paramater universe_id=[1]
27/12/2007 11:21:47 | DEBUG | BuildingModel | 36 | [BuildingModel::loadBuildingByPlanet] ==> Parameter planet_id=[1]
27/12/2007 11:21:47 | DEBUG | BuildingModel | 41 | [BuildingModel::loadBuildingByPlanet] ==> Query=[select b.id,a.building_id,a.building_level,b.category,b.img,b.effect_value,b.effect_formule,b.energy_value,b.energy_formule,b.time_value,b.time_formule from exodus_building_planet_1 a,admin_building b where b.universe_id=1 and a.building_id=b.building_id and a.planet_id=1 order by b.building_id]
27/12/2007 11:21:48 | INFO | BuildingModel | 44 | [BuildingModel::loadBuildingByPlanet] ==> End
27/12/2007 11:21:48 | INFO | BuildingModel | 51 | [BuildingModel::loadCostByBuilding] ==> Begin
27/12/2007 11:21:48 | DEBUG | BuildingModel | 52 | [BuildingModel::loadCostByBuilding] ==> Paramater universe_id=[1]
27/12/2007 11:21:48 | DEBUG | BuildingModel | 53 | [BuildingModel::loadCostByBuilding] ==> Parameter building_row_id=[1]
27/12/2007 11:21:48 | DEBUG | BuildingModel | 58 | [BuildingModel::loadCostByBuilding] ==> Query=[select ore_id,cost_value,cost_formule from admin_building_cost where ext_id=1 order by ore_id]
27/12/2007 11:21:48 | INFO | BuildingModel | 61 | [BuildingModel::loadCostByBuilding] ==> End
Et voici la classe "Tracer"
Code PHP :
class Tracer
{
private $path;
private $filename;
private $type;
function __construct($path,$filename,$type='D')
{
if( !is_string($path) ) throw new Exception('Invalid Parameter [path] : '.$path,2001);
if( !is_string($filename) ) throw new Exception('Invalid Parameter [filename] : '.$filename,2002);
if( !is_string($type) ) throw new Exception('Invalid Parameter [type] : '.$type,2003);
if( ( 'H' != $type ) && ( 'D' != $type ) ) throw new Exception('Unexpected Value [type] : '.$type,2004);
$this->path = $path;
$this->filename = $filename;
$this->type = $type;
}
public function trace($level,$file,$line,$mess)
{
if( $_GLOBALS['config']['debug'] )
{
if( !is_string($level) ) throw new Exception('Invalid Parameter [level] : '.$level,2008);
if( !is_string($mess) ) throw new Exception('Invalid Parameter [mess] : '.$mess,2009);
$name = $this->path.'/'.$this->filename.'-'.(('D'==$this->type)?date('Ymd'):date('YmdH')).'.txt';
$h = @fopen($name,'a');
if( false === $h ) throw new Exception('Impossible to open trace file : '.$name,2005);
$mess = sprintf("%s | %-7s | %s | %-5u | %s\n",date("d/m/Y H:i:s"),$level,$file,$line,$mess);
if( false === @fwrite($h, $mess)) throw new Exception('Impossible to write trace in '.$name.' ['.$mess.']',2006);
fclose($h);
}
}
}
Et voici dans le code comment les traces sont appellées
Code PHP :
public function loadBuildingByPlanet($universe_id,$planet_id)
{
$this->trace('INFO',basename(__CLASS__),__LINE__,'['.__METHOD__.'] ==> Begin');
$this->trace('DEBUG',basename(__CLASS__),__LINE__,'['.__METHOD__.'] ==> Paramater universe_id=['.$universe_id.']');
$this->trace('DEBUG',basename(__CLASS__),__LINE__,'['.__METHOD__.'] ==> Parameter planet_id=['.$planet_id.']');
if(!is_numeric($universe_id)) throw new Exception('Invalid Parameter ==> universe_id=['.$universe_id.']',14003);
if(!is_numeric($planet_id)) throw new Exception('Invalid Parameter ==> planet_id=['.$planet_id.']',14004);
$qry = "select b.id,a.building_id,a.building_level,b.category,b.img,b.effect_value,b.effect_formule,b.energy_value,b.energy_formule,b.time_value,b.time_formule from exodus_building_planet_".$universe_id." a,admin_building b where b.universe_id=".$universe_id." and a.building_id=b.building_id and a.planet_id=".$planet_id." order by b.building_id";
$this->trace('DEBUG',basename(__CLASS__),__LINE__,'['.__METHOD__.'] ==> Query=['.$qry.']');
$rows = $GLOBALS['db']->fetchArray($qry);
$this->trace('INFO',basename(__CLASS__),__LINE__,'['.__METHOD__.'] ==> End');
return $rows;
}
Et dans un fichier de configuration, il y a une variable qui permet d'activer ou non les traces ($_GLOBALS['config']['debug'] = true; ).
Quand le débuggage est fini et que l'application part en environnement de PROD, il vaut mieux commenter les appels aux traces pour améliorer les performances mais il vaut mieux pas les supprimer car en cas de bug, il suffit de décommenter pour suivre ce qui se passe.
D'un autre côté, j'ai les logs qui remontent des problèmes sur l'application en environnement de PROD.
Chaque comportement non prévu déclenche un processus d'alerte avec un niveau de criticité.
En fonction du niveau de la criticité, une réaction a lieu :
- envoi d'une exception
- log dans un fichier
- envoi d'un mail à l'administrateur
avec la possibilité de faire toutes les réactions à la fois.
Pour cela, j'utilise un design pattern : "Chain of Responsability" [
http://en.wikipedia.org/wiki/Chain-of-re...ty_pattern]
Le principe est en gros le suivant : si un alerte de niveau 1 est déclenché alors une exception est levée, si l'alerte est de nievau 2 alors on écrit dans un log et on lève une exception et si elle est de nievau 3 alors on effectue les 3 actions.
Pour finir, il y a le suivi des actions d'un utilisateur.
Là, pas de mystère, j'historise toutes les actions effectuées par les utilisateurs.
Chaque action représente un ordre envoyé au système, cette ordre est stockée et il contient une liste de paramètre dont la signification change selon la nature de l'ordre.
J'ai ensuite une interface de visualisation de ces historiques, en filtrant sur les joueurs et/ou le type d'ordre (construction, achat, attaque, déplacement,...)
Et au fianl, il vaut mieux prévoir un petit script à part déclenché par crontab qui va archiver/purger les traces et les historiques.