Wikini

DiscussionsDebogageDeWikiNi

PagePrincipale :: DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur :: Vous êtes ec2-44-220-251-236.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):



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]