Wikini

DiscussionsDebogageDeWikiNi

PagePrincipale :: DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur :: Vous êtes ec2-54-226-4-91.compute-1.amazonaws.com

Débogage SQL

Pour l'activer, il faut la paramétrer dans le fichier de configuration : "debug" => "yes",

Exemple de sortie :
Query log :
select * from wikini_pages where tag = 'ActualitesDeWikini' and latest = 'Y' limit 1 (0.0018)
select * from wikini_pages where tag = 'DerniersChangements' and latest = 'Y' limit 1 (0.0016)
select * from wikini_pages where tag = 'DerniersCommentaires' and latest = 'Y' limit 1 (0.0015)
select * from wikini_pages where tag = 'ParametresUtilisateur' and latest = 'Y' limit 1 (0.0015)
select * from wikini_acls where page_tag = 'ActualitesDeWikini' and privilege = 'read' limit 1 (0.0011)
select * from wikini_pages where tag = 'WikiNi' and latest = 'Y' limit 1 (0.0025)
select * from wikini_pages where tag = 'WikiniChangeLog' and latest = 'Y' limit 1 (0.0016)
select * from wikini_pages where tag = 'ActualitesDeWikiniPointNet' and latest = 'Y' limit 1 (0.0018)
select * from wikini_pages where tag = 'DifferencesEntreWikiNi01103EtWikiNi041' and latest = 'Y' limit 1 (0.0017)
select * from wikini_pages where tag = 'SitesUtilisantWikini' and latest = 'Y' limit 1 (0.0025)
select * from wikini_pages where tag = 'WikiniEtLesFluxRSS' and latest = 'Y' limit 1 (0.0018)
select * from wikini_pages where tag = 'WakkaFr' and latest = 'Y' limit 1 (0.0018)
select * from wikini_pages where tag = 'UneMacroPourWord' and latest = 'Y' limit 1 (0.0016)
select * from wikini_pages where comment_on = 'ActualitesDeWikini' and latest = 'Y' order by time (0.0021)
select * from wikini_acls where page_tag = 'ActualitesDeWikini' and privilege = 'write' limit 1 (0.0011)
select * from wikini_pages where tag = 'CharlesNepote' and latest = 'Y' limit 1 (0.0027)
0.0286 s (total SQL time)
0.0627 s (total time)
SQL time represent : 45.64% of total time


Proposition de nouvelle sortie

Query log :

01 -- 0.0018 s : select * from wikini_pages where tag = 'ActualitesDeWikini' and latest = 'Y' limit 1

02 -- 0.0016 s : select * from wikini_pages where tag = 'DerniersChangements' and latest = 'Y' limit 1

03 -- 0.0015 s : select * from wikini_pages where tag = 'DerniersCommentaires' and latest = 'Y' limit 1

04 -- 0.0015 s : select * from wikini_pages where tag = 'ParametresUtilisateur' and latest = 'Y' limit 1

05 -- 0.0011 s : select * from wikini_acls where page_tag = 'ActualitesDeWikini' and privilege = 'read' limit 1

06 -- 0.0017 s : select * from wikini_pages where tag = 'DifferencesEntreWikiNi01103EtWikiNi041' and latest = 'Y' limit 1

07 -- 0.0021 s : select * from wikini_pages where comment_on = 'ActualitesDeWikini' and latest = 'Y' order by time

08 -- 0.0011 s : select * from wikini_acls where page_tag = 'ActualitesDeWikini' and privilege = 'write' limit 1

09 -- 0.0027 s : select * from wikini_pages where tag = 'CharlesNepote' and latest = 'Y' limit 1

--------------

0.0286 s (total SQL time)

0.0627 s (total time)

SQL time represent : 45.64% of total time


Le nouveautés :
Si personne n'y voit d'inconvénient, je passe dans le CVS mettons jeudi 20 janvier.
-- CharlesNepote

Pour ce genre de données ce n'est pas mieux d'utiliser un tableau ? Ce que tu proposes donne pas mal mais quand une requête s'étalera sur plusieurs lignes la lisibilité en sera perturbée... (ce qui est déjà le cas actuellement) -- LordFarquaad

Calcul du temps total

Il faudrait changer le calcul du t_end (je ne sais pas si tu l'as fait...): on a à notre disposition la méthode GetMicroTime?(), autant l'utiliser... Il faudrait peut-être aussi calculer le temps de debugging, pour voir s'il n'influe pas sur le temps total (ça doit être minime mais bon, on sait jamais...) -- LordFarquaad

Nombre d'enregistrements retournés ou affectés

Sinon je ne sais pas si ça serait fort utile mais le nombre d'enregistrements retournés ou affectés pourrait être intéressant (je pense à ça surtout pour les requêtes comme la purge). Cf les fonctions mysql_num_rows (uniquement pour les SELECT) et mysql_affected_rows (uniquement pour les mises à jour). L'inconvéniant est qu'il faut voir si la requête est un SELECT ou non... Je pense que le mieux serait un 0 === stripos($query, 'select') (ou false !== mais on sait jamais qu'il y ait le mot "select" plus loin...) pour le savoir. -- LordFarquaad

En cas de plantage du script

Ah et puis sinon il faudrait changer le fait que l'exécution s'interrompt complètement à la moindre erreur, et à ce moment là l'erreur pourrait s'afficher dans le query log. -- LordFarquaad

Remarques diverses à reclasser ailleurs ;)

Au fait, tant que j'y suis: la méthode LoadSingle() laisse penser qu'elle est plus optimisée que LoadAll(), or ce n'est pas du tout le cas... et si on ajoutait un paramètre $limit à cette dernière ? [tiens le if dans LoadAll() ne sert strictement à rien vu que Query() tue le script dans le cas contraire...] -- LordFarquaad

Proposition de nouvelles options

On pourrait rafiner le débogage SQL de la manière suivante :

Conversation entre CharlesNepote et LordFarquaad en réflexion à ce sujet (à poursuivre):
[0:10:03] <charles.nepote@jabber.org> ça veut donc dire que le programmeur est obligé de modifier le noyau (créer une constante) à chaque fois qu'il veut créer une nouvelle caétgorie ?
[0:11:17] <Lord Farquaad> ah ouais évidemment...
[0:11:35] <Lord Farquaad> mais je trouve plus clair de définir clairement des constantes d'abord
[0:12:01] <Lord Farquaad> que de devoir aller triffouiller le code pour savoir quelle chaine il faut utiliser pour activer/désactiver telle option
[0:12:35] <Lord Farquaad> si c'est pour aller mettre un commentaire quelque part avec la liste des options possibles, ça revient au même que d'utiliser des constantes...
[0:15:35] <charles.nepote@jabber.org> typiquement ce qui m'intéresse, en tant que développeur wikini d'une action, d'un handler ou de toute autre chose, c'est de pouvoir insérer dans le code du fichier sur lequel je travaille une information de débogage qui me sera ensuite affichée proprement dans la page (et pas n'importe où) ; je n'ai pas du tout envie de toucher au noyau, m'obligeant à restaurer régulièrement la version CVS
[0:18:14] <charles.nepote@jabber.org> Techniquement, ta solution est très intéressante, mais fonctionnellement je la trouve peu pratique et plus diificile à mettre en oeuvre que mon simple if($wiki->GetConfigValue("debug_process") == "yes") $wiki->processLog .= "<li>[formatter found] ".htmlspecialchars($things[1]) . "</li>\n";
[0:19:31] <Lord Farquaad> oui mais le débogage se fera de façon assez générique non ?
[0:19:45] <Lord Farquaad> il ne doit pas y avoir un type de débogage différent pour chaque action/handler
[0:21:00] <Lord Farquaad> donc si on définit une constante générale, par exemple DEBUG_ACTIONS, et qu'on définit une méthode ou quelque chose du genre pour que les actions puissent enrégistrer des informations de débogage, cela me parait très bien...
[0:21:06] <Lord Farquaad> idem pour les handlers etc.
[0:21:43] <charles.nepote@jabber.org> pourquoi pas : personnellement j'aimerai éventuellement définir une classe d'information de débogage pour chaque action
[textsearch] bla bla
[0:22:33] <Lord Farquaad> pour chaque action ? c'est lourd quand même il me semble
[0:22:37] <charles.nepote@jabber.org> c'est tellement facile à utiliser, pourquoi s'en priver ?
[0:23:11] <charles.nepote@jabber.org> ça ne veut pas dire qu'on le fera, je veux simplement pouvoir le faire simplement
[0:23:11] <Lord Farquaad> oui mais je pense qu'il serait mieux d'utiliser quelque chose de plus générique, classe ou autre
[0:23:43] <Lord Farquaad> parce que sinon on va avoir des classes qui seront souvent très similaires pour plusieurs actions je pense
[0:24:52] <charles.nepote@jabber.org> regarde par exemple dans le formatter : on a réussi à déboguer rapidement le pb grace à cela ; j'aimerai également m'attaquer au problème des <li> : je pourrais créer une classe uniquement pour ce problème et ne plus l'utiliser une fois le pb résolu
[0:25:15] <Lord Farquaad> et on aura aussi certainement une présentation qui varie selon les actions (certes c'est réservé au développeur, mais si on veut se mettre à logger le debug dans un fichier, ça peut tout de même être utile de présenter tout de la même façon...)
[0:25:22] <Lord Farquaad> c'est pas un peu du bidouillage ça ? 
[0:27:46] <charles.nepote@jabber.org> en fait mon pb est principalement le suivant : lorsque tu insères un echo "xxx"; quelquepart dans un fichier pour le déboguer, cela va te l'afficher parfois n'importe où (si bien que parfois tu ne peu même pas savoir l'ordre des infos de debog) ; et bien moi je veux qu'il s'affiche proprement dans une liste en fin de document, c'est à peut près tout
[0:29:05] <Lord Farquaad> alors il n'y a pas de besoin d'avoir une classe différente pour chaque action, si ?
[0:30:13] <charles.nepote@jabber.org> je suis d'accord qu'il ya peut-être plus simple que mon $wiki->processLog .= "message" ;
du genre : $this->debug("Message", "classe de débogage");
[0:31:37] <charles.nepote@jabber.org> en fait il peut y avoir plusieurs classes pour chaque action selon les souhaits de débogage du développeur : il faut laisser le dév libre de déboguer ce qu'il souhaite ; il doit pouvoir déboguer de façon chirurgicale
[0:33:04] <Lord Farquaad> mais ça, ça ne dépend que de où il décide d'envoyer des informations au débogueur
[0:33:27] <charles.nepote@jabber.org> A y réfléchir, j'aime bien le principe du $this->debug("Message", "classe de débogage"); (le test conditionnel déterminant l'affichage des messages de telle classe pourvant être effectuée dans la méthode)
[0:36:22] <Lord Farquaad> tu testeras sur quoi ? le config['debug'] ? la méthode debug devrait-elle aller chercher dans la classe débogage la condition à vérifier ?
[0:36:29] <charles.nepote@jabber.org> je vais aller me coucher...
[0:36:48] <Lord Farquaad> je crois que je ne vais pas tarder non plus :-)
[0:37:17] <charles.nepote@jabber.org> tu fais un copier/coller sur le wiki ?
[0:38:12] <Lord Farquaad> ok


Solution 1

Pour améliorer le débogage des scripts, je propose d'améliorer légèrement les possibilités de débogage. En substance :

Exemple de sortie :
1. [formatter found] DerniersChangements
2. [formatter found] DerniersCommentaires
3. [formatter found] ParametresUtilisateur
4. [formatter found]
5. [formatter found]
6. [formatter found] =====
7. [formatter found] ""{{backlinks}}""
8. [formatter found] =====
9. [formatter found]
10. [formatter found]
11. [formatter found]
12. [formatter found] -
13. [formatter found]
14. [formatter found] -
15. [formatter found]


Le but c'est d'avoir à disposition du développeur une variable permettant de faire des tests :
Ca me parait plus propre que de faire nos propres bidouilles chacun dans son coin.
Avantages :
Inconvénient :

Il est éventuellement possible de rendre cette fonction disponible à tout moment en passant au script un paramètre : par exemple :
http://www.wikini.net/wakka.php?wiki=DiscussionsDebogageDeWikiNi&debug_process=1
Le débogage serait alors encore plus facile à mettre en oeuvre ; on pourrait notamment partiellement déboguer un site à distance sans forcément en avoir vu les sources.
-- CharlesNepote



Solution 2 : une méthode spécifique pour la constitution du log

[code non testé]

Dans wakka.config.php, indiquer :

Dans le noyau :
/* Test un débogage est demandé */
if (!empty($this->GetConfigValue?("debug"))) define ("WN_DEBUG", "true");
else define("WN_DEBUG", '')

/* Méthode */
function Debug($message, $category)
{
}

Usage du débogueur n'importe où dans les sources :
if (WN_DEBUG) $this->Debug("[Formatteur] Tel message", "Formatteur");

Affichage du log de débogage (/actions/footer.php) :
echo $this->debog;

Les avantages de cette méthode :
On ne peut pas avoir "all à l'exception d'une catégorie", mais ça ne me parait pas très important.
-- CharlesNepote

En fait je me pose une question quant à l'utilité de permettre de demander spécifiquement dans le debug de n'enregistrer celui-ci que pour une seule action/un seul handler ou autre module :
D'où l'intérêt pour moi de se contenter de catégories plus générales (DEBUG_ACTIONS, DEBUG_FORMATTERS, DEBUG_HANDLERS, DEBUG_WIKI, DEBUG_QUERIES, DEBUG_TIMES etc.) qui ne devraient, en toute logique, pas trop évoluer. Si un développeur indépendant a besoin d'une nouvelle, rien ne l'empêche de l'ajouter, si nous avons besoin d'une nouvelle, ce serait le fruit de discussions et cela ne posera pas de problème de compatibilité avec les versions antérieures (c'est juste une nouvelle constante...)
L'avantage des constantes entières est que justement on peut faire un "tout à l'exception de telle catégorie" (par exemple DEBUG_ALL & ~ DEBUG_QUERIES pour désactiver uniquement le débogage des requêtes)
Le paramètre $category prendrait donc comme valeur une de ces constantes (n'importe laquelle sauf DEBUG_ALL bien entendu)
Sinon je trouve que ce serait mieux de ne pas avoir à mettre dans le message quelle catégorie de debogage cela concerne, à mon sens ce serait à la méthode Debug de l'ajouter automatiquement. On pourrait aussi envisager qu'elle ne construise pas l'affichage directement mais que cela se fasse en fin d'exécution, regroupant éventuellement les données informations par type. Il suffirait pour cela de stocker les informations de débug dans un tableau du type:
array(
)
L'inconvéniant est alors qu'on n'a plus les informations dans l'ordre, mais par contre elles sont beaucoup mieux structurées...
-- LordFarquaad

A propos de tes propositions :
En bref, je ne suis pas du tout d'accord avec tes arguments et tes propositions.
Quelqu'un d'autre pour donner son avis ?
-- CharlesNepote


Solution 3 : Xdebug

Une seule reponse : XDebug qui permet d'avoir le tracage des fonctions et contient un profiler, tout ca en evitant de modifier le code php de WikiNi, et donc d'ajouter des tests inutiles. C'est une extension PHP facile à installer. Le resultat peut être afficher dans la page en rajoutant une ligne de code mais ce n'est pas obligatoire, les resultats peuvent être lu dans des fichiers texte. --GarfieldFr


Autre

Je viens de découvrir une fonction qui pourrait s'avérer très pratique pour le débuggage, existante depuis php 4.3.0: debug_backtrace(). Elle permet entre autre de lister tous les appels de fonctions/classes/fichiers à n'importe quel point du programme, c'est donc je pense assez semblable à Xdebug... (A priori son seul inconvéniant peut être lors d'appels récursifs, où le tableau retourné pourrait s'avérer très long, mais ça doit être pareil pour Xdebug)

Au fait, une petite fonction qui peut être utile pour étudier le comportement des fonctions récursives (je l'écris sur le tas, elle donc est peut-être buggée...), à adapter au besoin:
<?php
/**
* Fonction permettant le débuggage de fonctions récursives (entre autres) grâce à un pseudo-compteur interne
* et à l'enrégistrement d'informations à chaque appel.
* @param string $name Nom d'enrégistrement du debug. Si cette valeur n'est pas spécifiée (ou vaut false),
* la fonction tuera le script en affichant toutes les données qu'elle a enrégistrées au cours des appels précédents.
* @param mixed $info Informations de débug à stocker/afficher. Si elle n'est pas spécifiée (ou vaut false), aucune information ne sera stockée
* et le compteur interne ne sera pas incrémenté. (valeur par défaut)
* @param mixed $dieAtCallNb Indique le nombre d'appels après lequel la fonction debug_recur doit tuer l'exécution et afficher les données.
* (false = jamais, c'est la valeur par défaut) Ceci permet d'éviter les boucles infinies ou trop longues.
* Ex.: 0 tuera le script de toute façon, 1 lors du premier appel enrégistré, 10 lors du dixième appel etc.
* NB.: c'est la valeur passée à l'appel courant qui compte, et non celle passée lors du premier appel.
* @param bool $showAllOnDie Indique s'il faut afficher toutes les informations de tous les appels précédents de debug_recur pour tous les
* nom de débugs enrégistrés ou uniquement les informations du nom courant. (défaut: false)
* @return array Toutes les informations des appels précédents pour l'enrégistrement $name
* sous forme d'un tableau dont les éléments sont toutes les $info qui ont été passées au cours des appels de debug_recur pour $name.
* @exemple // appel classique, tue le script lors du 50e passage à cette ligne:
* debug_recur('MaFonction', array($param1DeMaFonction, $param2DeMaFonction), 50);
* // récupération des informations stockées:
* $infos = debug_recur('MaFonction', null, false, false, true);
* // tuer le script sans stocker d'informations mais en affichant les données stockées pour 'MaFonction':
* debug_recur('MaFonction', false, 0, false);
* // idem mais en affichant les données stockées lors de tous les appels précédents:
* debug_recur();
*/
function debug_recur($name false$info false$dieAtCallNb false$showAllOnDie  false){
    static 
$data = array();

    if(!
$name) {
        if(!isset(
$data[$name])) $data[$name] = array();
        
$a $data[$name]; // ce sera moins long que de le recopier à chaque fois...
        
if($info$a[] = $info;
    } else 
$showAllOnDie true// dans ce cas on ne se sert pas de $a après.

    
if(!$name || ($dieAtCallNb !== false && $dieAtCallNb >= count($a))) { // pseudo compteur: nombre d'éléments dans $a...
        
if($name) echo "\nMort subite: '$name' a été appelé au moins $dieAtCallNb fois.<br />\n"
        
echo "Pile d'informations enrégistrées:<br />\n";
        
ob_start();
        if(
$showAllOnDieprint_r($data);
        else 
print_r($a['infos']);
        
$output ob_get_content();
        
ob_end_flush();
        
$output str_replace("\t"'&nbsp;&nbsp;&nbps;&nbsp;'htmlentities($output));
        die(
nl2br($output));
    }

    return 
$a;
}
?>
(n'hésitez pas à modifier, je n'ai d'ailleurs pas vérifié qu'elle marchait mais j'ai assez confiance...) -- LordFarquaad

Débat sur les chaînes

Sinon pourquoi toujours utiliser des chaines, j'ai vu ça un peu partout sur WikiNi.net: ici "yes" ou "no", ailleurs "1" ou "0"... pourquoi ne pas utiliser ces magnifiques constantes baptisées true et false ? Dans ce cas-ci par exemple cela éviterait d'avait utiliser un == pour faire le test... -- LordFarquaad

Il n'y a pas de commentaire sur cette page. [Afficher commentaires/formulaire]