<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cloud Connected &#187; ligne de commande</title>
	<atom:link href="http://www.cloudconnected.fr/tag/ligne-de-commande/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.cloudconnected.fr</link>
	<description>Thoughts of a french web developer</description>
	<lastBuildDate>Wed, 01 Feb 2012 08:53:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Logs PHP avec syslog</title>
		<link>http://www.cloudconnected.fr/2009/03/13/logs-php-avec-syslog/</link>
		<comments>http://www.cloudconnected.fr/2009/03/13/logs-php-avec-syslog/#comments</comments>
		<pubDate>Fri, 13 Mar 2009 15:45:34 +0000</pubDate>
		<dc:creator>Rémi</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[ligne de commande]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.the-asw.com/?p=417</guid>
		<description><![CDATA[Pendant longtemps j&#8217;ai cherché comment uniformiser les logs de mes applications PHP, et plus particulièrement des nombreux scripts en ligne de commande qui s&#8217;exécutent régulièrement (oui, je suis un grand fan de PHP en ligne de commande) et des applis web quand elles génèrent une erreur. Pour aller droit au but : j&#8217;ai trouvé (mais [...]]]></description>
			<content:encoded><![CDATA[<p>Pendant longtemps j&#8217;ai cherché comment uniformiser les logs de mes applications PHP, et plus particulièrement des nombreux scripts en ligne de commande qui s&#8217;exécutent régulièrement (oui, je suis un grand fan de PHP en ligne de commande) et des applis web quand elles génèrent une erreur. Pour aller droit au but : j&#8217;ai trouvé (mais ça, vous vous en doutiez) et maintenant j&#8217;utilise du <code>syslog</code> partout. Mais patience, je vais y venir.</p>
<p>D&#8217;abord qu&#8217;est-ce que j&#8217;entends par &#8220;logs&#8221; ? Il y a bien sûr tous les messages d&#8217;erreurs, que ce soit des erreurs générées par PHP (genre &#8220;la base de données ne répond plus&#8221;) ou des erreurs générées manuellement (genre &#8220;c&#8217;est quoi ce bordel je devrais jamais tomber dans ce cas là&#8221;). Mais il y a également les messages d&#8217;informations sur l&#8217;état d&#8217;avancement du script en ligne de commande (que personne ne lit mais qui pourront peut-être être utile le jour où le script va faire n&#8217;importe quoi) ou encore les messages de debug (pratique pour le développement). Pour les applications web, toutes les erreurs génèrent un code HTTP 500 et une page d&#8217;erreur propre pour le client, mais j&#8217;aimerais bien pouvoir garder une trace de ce qui a foiré.</p>
<h3>Pour un script en ligne de commande</h3>
<p>Pour cette partie je vais essayer de détailler le plus possible, mais il vaut mieux être familier avec les systèmes Unix, car cela concerne exclusivement des scripts qui sont exécutés avec la SAPI CLI (plus d&#8217;infos <a href="http://fr3.php.net/manual/fr/features.commandline.php">dans la doc de PHP</a>).</p>
<h4>Affichage standard</h4>
<p>Au départ, reflexe de programmeur PHP, j&#8217;utilisais simplement les fonctions <code>echo</code> (ou <code>printf</code>), mais ça devient vite un casse-tête de filtrer les messages selon leur niveau d&#8217;importance. Et quand le script n&#8217;est pas lancé en ligne de commande (par exemple s&#8217;il est lancé via une cron), ces messages ne sont plus visibles. Il est cependant possible de les archiver en redirigeant le flux de sortie standard vers un fichier. Mais il faut penser faire la rotation de ce fichier de log manuellement (voir <code>logrotate</code>) et on se retrouve vite avec une multitude de fichiers de log éparpillés sur le disque, ce qui ne facilite pas la maintenance.</p>
<p>Exemple, <code>pouet.php</code> contient :</p>
<pre>echo "pouet\n";</pre>
<p>On redirige le flux :</p>
<pre>$ php pouet.php > /tmp/pouet</pre>
<p><span id="more-417"></span></p>
<h4>Choisir la sortie</h4>
<p>Pour améliorer un peu le filtrage des messages d&#8217;erreur, on peut utiliser <code>fprintf</code> (<a href="http://www.php.net/fprintf">voir la doc</a>) et utiliser les constantes <code>STDOUT</code> et <code>STDERR</code> pour envoyer les messages respectivement sur la sortie standard et sur la sortie d&#8217;erreur. Il est ainsi possible de rediriger les messages d&#8217;erreurs dans un fichier et les messages &#8220;standards&#8221; (information, debug, etc.) vers <code>/dev/null</code>. C&#8217;est un mécanisme très classique, mais c&#8217;est bien de savoir que PHP le propose nativement.</p>
<p>Exemple, <code>pouet2.php contient :</code></p>
<pre>
fprintf(STDOUT, "un message normal\n");
fprintf(STDERR, "un message d'erreur\n");
</pre>
<p>On peut rediriger l&#8217;un ou l&#8217;autre des flux pour filtrer les messages :</p>
<pre>
$ php pouet.php
un message normal
un message d'erreur
$ php pouet.php 1> /dev/null
un message d'erreur
$ php pouet.php 2> /dev/null
un message normal
</pre>
<p>Mais avec ce système il a toujours le problème de la maintenance des fichiers de logs. Donc au bout d&#8217;un moment j&#8217;ai décidé d&#8217;abonner mes méthodes de développeur PHP et d&#8217;aborder le problème sous un autre angle : comment fait-on dans les autres langages pour développer des scripts propres ? Réponse on utilise <code>syslog</code>, l&#8217;outil de log centralisé des systèmes Unix (voir <a href="http://fr.wikipedia.org/wiki/Syslog">la page sur Wikipedia</a>). &#8220;Oui mais PHP c&#8217;est fait pour faire du web, l&#8217;API n&#8217;existe surement pas&#8221;, me dis-je naïvement. Et bien comme quoi il en faut pas se fier aux clichés : PHP a fait beaucoup de progrès (je vous parlerais un jour des forks et autres trucs rigolos) et les fonctions syslog existent et fonctionnent très bien !</p>
<h4>Syslog</h4>
<p>Pour utiliser syslog, il faut d&#8217;abord faire appel à <code>define_syslog_variables</code> qui initialise toutes les variables utilisées dans les fonctions syslog et à la fonction <code>openlog</code> qui permet d&#8217;ouvrir la connexion avec l&#8217;historique système. Ensuite, la fonction <code>syslog</code> permet de logguer une chaine de caractère, tout simplement. Vous trouverez toutes les infos sur les docs des fonctions <a href="http://fr3.php.net/manual/fr/function.openlog.php">openlog</a> et <a href="http://fr3.php.net/manual/fr/function.syslog.php">syslog</a>.</p>
<p>Exemple :</p>
<pre>
// au début
define_syslog_variables();
openlog(basename(__FILE__), LOG_PID | LOG_PERROR, LOG_LOCAL0);

// à n'importe quel moment du script
syslog(LOG_ERR, 'Une erreur est survenue');
syslog(LOG_DEBUG, 'Un message de debug');

// à la fin du script, optionnel
closelog();
</pre>
<ul>
<li>Le premier paramètre de <code>openlog</code> est un identifiant qui sera ajouté au début de chaque ligne de log, pour s&#8217;y retrouver parmi tous les logs systèmes. En passant <code>basename(__FILE__)</code>, j&#8217;ajoute systématiquement le nom du fichier PHP.</li>
<li>L&#8217;option <code>LOG_PERROR</code> est très pratique pour le développement car elle permet d&#8217;envoyer une copie du message sur la sortie standard.</li>
<li>Le dernier paramètre de <code>openlog</code> permet de choisir la &#8220;facility&#8221; des logs. C&#8217;est purement du système, alors demandez à votre administrateur système. :-) En général il voudra que vous utilisiez les facility locales <code>LOG_LOCAL0</code> jusqu&#8217;à <code>LOG_LOCAL8</code> ou éventuellement <code>LOG_USER</code>.</li>
<li>Le premier paramètre de <code>syslog</code> détermine la priorité du message. Il y en a 8, de <code>LOG_DEBUG</code> (la plus basse) jusqu&#8217;à <code>LOG_EMERG</code> (la plus haute) ce qui laisse une grande marche de manœuvre pour classer ses messages.</li>
</ul>
<p>Ce système possède pas mal d&#8217;avantages : les logs sont centralisés dans <code>/var/log/syslog</code> (il  est ensuite possible de configurer syslog pour dispatcher les logs dans d&#8217;autres fichiers), la rotation est gérée automatiquement (comme tous les autres logs du système), il est possible de filtrer facilement les logs selon le niveau de priorité, et surtout l&#8217;utilisation pour le développeur est simple et uniforme dans tous les scripts.</p>
<h3>Pour une application web</h3>
<p>Une erreur qui se produit quelque part sur mes applications génère automatiquement une erreur HTTP 500 (Internal Server Error) avec une page d&#8217;erreur personnalisée. Bon, ça c&#8217;est le framework qui gère, et ce n&#8217;est pas le sujet de l&#8217;article. Donc depuis longtemps mon problème était le suivant : quoi afficher sur cette page pour ne pas donner trop d&#8217;infos à l&#8217;utilisateur mais en même temps lui donner suffisamment d&#8217;infos pour me permettre de comprendre/reproduire l&#8217;erreur si besoin ? Si j&#8217;affiche simplement &#8220;Erreur&#8221;, l&#8217;utilisateur va me dire &#8220;ça marche pas&#8221;, et je serais bien avancé. Si j&#8217;affiche toutes les informations de debug (par exemple le dump complet de l&#8217;exception avec message d&#8217;erreur, nom du fichier, numéro de la ligne, backtrace, etc.), ça donne beaucoup trop d&#8217;informations sur l&#8217;architecture de l&#8217;application.</p>
<p>La solution que j&#8217;ai choisie est de générer un ID unique pour l&#8217;erreur et de logguer avec cet ID toutes les informations qui me seront utiles. Ensuite, j&#8217;affiche uniquement cet ID à l&#8217;utilisateur, en lui demandant de le fournir pour toute correspondance ultérieure. Il n&#8217;y aura plus qu&#8217;à rechercher cet ID dans les logs (vive <code>grep</code>) pour retrouver les infos de debug nécessaires.</p>
<p>Pour générer l&#8217;ID, j&#8217;utilise la fonction <code>uniqid</code> de PHP. Pour logguer, vous l&#8217;aurez compris puisque c&#8217;est le sujet de cet article, j&#8217;utilise <code>syslog</code>. Pourquoi pas MySQL ? Parce que si l&#8217;erreur c&#8217;est justement que le serveur MySQL est injoignable je suis niqué&#8230; Il y a toujours la solution de passer par un fichier, mais il y a tous les problèmes de maintenance évoqués plus haut. Enfin il y a la solution d&#8217;envoyer un mail, mais vu que les mails ne sont pas un système très fiable, je préfère ne pas me reposer entièrement dessus (l&#8217;application envoit aussi un mail, mais c&#8217;est en plus).</p>
<p>Exemple, dans un handler d&#8217;erreur fictif :</p>
<pre>
function handleError($exception)
{
	// log de l'erreur dans syslog
	define_syslog_variables();
	// je ne log pas le PID (ça ne sert à rien)
	openlog('MON_APPLICATION', 0, LOG_LOCAL0);

	$error_id = uniqid();

	syslog(LOG_ERR, sprintf(
		'[%s] %s (file %s, line %s)',
		$error_id,
		$exception->getMessage(),
		$exception->getFile(),
		$exception->getLine()
	));
	closelog();

	// envoyer en plus un mail si besoin

	// afficher le template avec $error_id
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.cloudconnected.fr/2009/03/13/logs-php-avec-syslog/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clavier qwerty après passage à Woody</title>
		<link>http://www.cloudconnected.fr/2002/07/24/clavier-qwerty-apres-passage-a-woody/</link>
		<comments>http://www.cloudconnected.fr/2002/07/24/clavier-qwerty-apres-passage-a-woody/#comments</comments>
		<pubDate>Wed, 24 Jul 2002 19:34:00 +0000</pubDate>
		<dc:creator>Rémi</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[ligne de commande]]></category>

		<guid isPermaLink="false">http://pre.the-asw.com/?p=41</guid>
		<description><![CDATA[Maintenant que la Woody est stable je ne sais pas si il y toujours ce problème, mais à l&#8217;époque de la version Potato le apt-get -u dist-upgrade transformait le clavier azerty en qwerty après reboot&#8230; Ma petite histoire Je crois que tout est dit, j&#8217;ai mis à jour la Potato et je me suis retrouvé [...]]]></description>
			<content:encoded><![CDATA[<p>Maintenant que la Woody est stable je ne sais pas si il y toujours ce problème, mais à l&#8217;époque de la version Potato le <code>apt-get -u dist-upgrade</code> transformait le clavier azerty en qwerty après reboot&#8230;</p>
<h4>Ma petite histoire</h4>
<p>Je crois que tout est dit, j&#8217;ai mis à jour la Potato et je me suis retrouvé après reboot devant l&#8217;invite de login sans pouvoir taper mon mot de passe vu que c&#8217;était du qwerty. Il m&#8217;a fallu regarder un schéma de clavier qwerty pour finalement retrouver les caractères spéciaux qu&#8217;il me manquait&#8230;</p>
<h4>La solution</h4>
<p>Une fois loggué en root :</p>
<pre>dpkg-reconfigure console-data</pre>
<p>Choisir &#8220;Select keyboard from arch list&#8221; puis &#8220;azerty&#8221; et enfin &#8220;French with Euro&#8221; (ou without, au choix). Et voila un clavier azerty, ouf !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cloudconnected.fr/2002/07/24/clavier-qwerty-apres-passage-a-woody/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

