{"id":4919,"date":"2017-05-01T05:00:20","date_gmt":"2017-05-01T04:00:20","guid":{"rendered":"https:\/\/www.blaess.fr\/christophe\/?p=4919"},"modified":"2017-06-05T03:19:38","modified_gmt":"2017-06-05T02:19:38","slug":"dailyfile-un-petit-outil-en-ligne-de-commande","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2017\/05\/01\/dailyfile-un-petit-outil-en-ligne-de-commande\/","title":{"rendered":"Dailyfile&nbsp;: un petit outil en ligne de commande"},"content":{"rendered":"<p><a href=\"https:\/\/www.blaess.fr\/christophe\/2017\/05\/01\/dailyfile-un-petit-outil-en-ligne-de-commande\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright wp-image-4950 size-full\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2017\/05\/dailyfile.png\" alt=\"Dailyfile\" width=\"250\" height=\"200\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">J&rsquo;ai r\u00e9cemment \u00e9t\u00e9 confront\u00e9 \u00e0 un souci de taille de fichiers de traces pour le d\u00e9bogage d&rsquo;une application. Pour r\u00e9soudre mon probl\u00e8me j&rsquo;ai \u00e9crit un petit programme en ligne de commande permettant de r\u00e9partir la sortie d&rsquo;un <em>pipeline<\/em> du shell dans des fichiers quotidiens.<\/p>\n<p style=\"text-align: justify;\">J&rsquo;ai appel\u00e9 cet outil <code><strong>dailyfile<\/strong><\/code> et je vous le pr\u00e9sente ici, en esp\u00e9rant qu&rsquo;il puisse servir \u00e0 d&rsquo;autres.<\/p>\n<p>\n<!--more-->\n<\/p>\n<h1>Pr\u00e9sentation<\/h1>\n<h2>Probl\u00e9matique<\/h2>\n<p style=\"text-align: justify;\">J&rsquo;ai d\u00e9velopp\u00e9 il y a quelques temps pour un client un programme sous Linux qui s&rsquo;occupe d&rsquo;initialiser et de superviser des communications entre des applications distantes et des serveurs. La mise au point est un peu compliqu\u00e9e car les communications reposant sur des modems 2G des difficult\u00e9s inattendues apparaissent dans la gestion des d\u00e9connexions intempestives.<\/p>\n<p style=\"text-align: justify;\">J&rsquo;ai pr\u00e9vu, comme d&rsquo;habitude, dans mon programme de nombreux messages de d\u00e9bogage que l&rsquo;on peut activer ou non en fonction d&rsquo;un niveau param\u00e9trable \u00e0 la compilation.<\/p>\n<p style=\"text-align: justify;\">Un script d\u00e9marre l&rsquo;application, qui \u00e9crira tous ses messages de d\u00e9bogage sur la sortie <code>stderr<\/code>. Comme je n&rsquo;ai pas acc\u00e8s directement \u00e0 ce serveur, les donn\u00e9es sont redirig\u00e9es dans un fichier que mon client me transmet par mail quand un probl\u00e8me survient. Le script est un peu plus complexe, mais on peut imaginer quelque chose comme\u00a0:<\/p>\n<pre>$ <strong>.\/my-application &gt;logfile.txt 2&gt;&amp;1<\/strong>\n<\/pre>\n<p style=\"text-align: justify;\">La premi\u00e8re redirection envoie la sortie standard <code>stdout<\/code> du programme dans le fichier de trace, la seconde redirection <code>2&gt;&amp;1<\/code> redirige la sortie <code>stderr<\/code> de la m\u00eame mani\u00e8re. Le script r\u00e9el est plus compliqu\u00e9 car on g\u00e8re un red\u00e9marrage automatique en cas de crash et un fichier de trace dont le nom contient la date de d\u00e9marrage.<\/p>\n<p style=\"text-align: justify;\">Les erreurs se produisant somme toute assez rarement, le programme tourne parfois pendant plusieurs jours entre deux red\u00e9marrages, et le fichier de trace p\u00e8se facilement plusieurs centaines de m\u00e9gaoctets. Son transfert et l&rsquo;analyse de son contenu deviennent alors plus compliqu\u00e9s.<\/p>\n<p style=\"text-align: justify;\">On ne peut pas facilement r\u00e9partir le contenu dans diff\u00e9rents fichiers sans arr\u00eater l&rsquo;application, ce qui est probl\u00e9matique dans notre cas. L&rsquo;utilisation de <code>logrotate<\/code> est un peu complexe, d&rsquo;autant que nous n&rsquo;avons pas les droits d&rsquo;administration sur le serveur.<\/p>\n<h2>Solution<\/h2>\n<p style=\"text-align: justify;\">Mon id\u00e9e a \u00e9t\u00e9 de remplacer la redirection \u00ab\u00a0<code>&gt;<\/code>\u00a0\u00bb vers un fichier par une redirection \u00ab\u00a0<code>|<\/code>\u00a0\u00bb dans un <em>pipeline<\/em>. De l&rsquo;autre c\u00f4t\u00e9 du <em>pipeline<\/em> un programme lira les donn\u00e9es, et les copiera dans un fichier, en changeant tous les jours.<\/p>\n<p style=\"text-align: justify;\">La programmation proprement dite est simple, et le code source est disponible dans <a href=\"https:\/\/github.com\/cpb-\/Dailyfile\" target=\"_blank\" rel=\"noopener noreferrer\">mon d\u00e9p\u00f4t Github<\/a>.<\/p>\n<h1>Installation<\/h1>\n<p style=\"text-align: justify;\">La compilation du programme ne pr\u00e9sente en principe pas de difficult\u00e9\u00a0:<\/p>\n<pre>$ <strong>git  clone  <a href=\"https:\/\/github.com\/cpb-\/Dailyfile\">https:\/\/github.com\/cpb-\/Dailyfile<\/a><\/strong>\nClonage dans 'Dailyfile'...\nremote: Counting objects: 33, done.\nremote: Compressing objects: 100% (21\/21), done.\nremote: Total 33 (delta 12), reused 31 (delta 10), pack-reused 0\nD\u00e9paquetage des objets: 100% (33\/33), fait.\nV\u00e9rification de la connectivit\u00e9... fait.\n$ <strong>cd  dailyfile\/<\/strong>\n$ <strong>make clean  &amp;&amp;  make<\/strong>\nrm -f dailyfile dailyfile.o *~\ngcc -Wall -W -DPROGRAM_VERSION=\"0.3\" -c  dailyfile.c\ngcc -o dailyfile dailyfile.o \n$ <strong>sudo  make  install<\/strong>\ncp dailyfile \/usr\/local\/bin\/\n$<\/pre>\n<h1>Utilisation<\/h1>\n<p style=\"text-align: justify;\">L&rsquo;utilisation de base est plut\u00f4t simple\u00a0:<\/p>\n<pre>$  <strong><em>commande-qui-dure-longtemps<\/em>  |  dailyfile<\/strong><\/pre>\n<p style=\"text-align: justify;\">Toutes les donn\u00e9es \u00e9crites par la premi\u00e8re commande dans le <em>pipeline<\/em> seront enregistr\u00e9es dans des fichiers nomm\u00e9s <code>day-YYYY-MM-DD.log<\/code> o\u00f9 <code>YYYY<\/code>, <code>MM<\/code>, et <code>DD<\/code> repr\u00e9sentent respectivement l&rsquo;ann\u00e9e, le mois et le jour de cr\u00e9ation du fichier.<\/p>\n<p style=\"text-align: justify;\">En voici un exemple d&rsquo;ex\u00e9cution r\u00e9elle\u00a0:<\/p>\n<pre>$ <strong>while true; do date; sleep 5; done | dailyfile<\/strong><\/pre>\n<p style=\"text-align: justify;\">Cette commande affiche la date toutes les cinq secondes. On retrouve plusieurs jours plus tard les r\u00e9sultats dans les fichiers\u00a0:<\/p>\n<pre>$ <strong>ls -l<\/strong>\ntotal 2148\n-rw-r--r-- 1 cpb cpb 583906 avril 29 01:59 day-2017-04-28.log\n-rw-r--r-- 1 cpb cpb 727838 avril 30 01:59 day-2017-04-29.log\n-rw-r--r-- 1 cpb cpb 750812 mai    1 01:59 day-2017-04-30.log\n-rw-r--r-- 1 cpb cpb 113240 mai    1 06:08 day-2017-05-01.log\n<\/pre>\n<p style=\"text-align: justify;\">On peut remarquer que l&rsquo;heure de la derni\u00e8re modification des fichiers \u00e9coul\u00e9s est \u00e0 1 heure 59. C&rsquo;est normal, le basculement est effectu\u00e9 en se basant sur l&rsquo;heure G.M.T, d\u00e9cal\u00e9e de deux heures l&rsquo;\u00e9t\u00e9 par rapport \u00e0 l&rsquo;heure locale affich\u00e9e par <code>ls<\/code>.<\/p>\n<h2>Options<\/h2>\n<p style=\"text-align: justify;\">Il existe quelques options pour modifier le comportement du programme.<\/p>\n<ul style=\"text-align: justify;\">\n<li><code>-b <em>size<\/em><\/code> ou <code>--buffer-size=<em>size<\/em><\/code>\u00a0: modifier la taille du buffer interne de copie des donn\u00e9es. Par d\u00e9faut 16384 octets.<\/li>\n<li><code>-c <em>seconds<\/em><\/code> ou <code>--cycle=<em>seconds<\/em><\/code>\u00a0: fixer la dur\u00e9e de commutation en secondes. Par d\u00e9faut 86400\u00a0secondes (une journ\u00e9e).<\/li>\n<li><code>-d <em>dir<\/em><\/code> ou <code>--directory=<em>dir<\/em><\/code>\u00a0: indiquer le r\u00e9pertoire o\u00f9 stocker les fichiers. Par d\u00e9faut, ils sont enregistr\u00e9s dans le r\u00e9pertoire courant.<\/li>\n<li><code>-h<\/code> ou <code>--help<\/code>\u00a0: afficher un rappel des commandes.<\/li>\n<li><code>-l<\/code> ou <code>--localtime<\/code>\u00a0: utiliser l&rsquo;heure locale lors de la cr\u00e9ation des noms de fichiers. Faux par d\u00e9faut, on utilise l&rsquo;<a href=\"https:\/\/fr.wikipedia.org\/wiki\/Temps_moyen_de_Greenwich\" target=\"_blank\" rel=\"noopener noreferrer\">heure G.M.T.<\/a><\/li>\n<li><code>-p <em>string<\/em><\/code> ou <code>--prefix=<em>string<\/em><\/code>\u00a0: pr\u00e9ciser le pr\u00e9fixe \u00e0 \u00e9crire avant la date dans le nom du fichier. Par d\u00e9faut, c&rsquo;est \u00ab\u00a0<code>day-<\/code>\u00ab\u00a0.<\/li>\n<li><code>-s <em>string<\/em><\/code> ou <code>--suffix=<em>string<\/em><\/code>\u00a0: indiquer le pr\u00e9fixe \u00e0 \u00e9crire apr\u00e8s la date dans le nom du fichier. Par d\u00e9faut, c&rsquo;est \u00ab\u00a0<code>.log<\/code>\u00ab\u00a0.<\/li>\n<li><code>-v<\/code> ou <code>--version<\/code>\u00a0: afficher la version de l&rsquo;outil <code>dailyfile<\/code>.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Lorsque la p\u00e9riode de commutation (option <code>-c<\/code>) est inf\u00e9rieure \u00e0 une journ\u00e9e, le nom des fichiers inclut des champs heure, minute, et seconde de cr\u00e9ation.<\/p>\n<h2>Exemple<\/h2>\n<p style=\"text-align: justify;\">Voici un exemple d&rsquo;ex\u00e9cution o\u00f9 je modifie le pr\u00e9fixe du fichier pour le remplacer par \u00ab\u00a0<code>date-<\/code>\u00ab\u00a0, son suffixe devient \u00ab\u00a0<code>.txt<\/code>\u00ab\u00a0, et sa p\u00e9riode est chang\u00e9e pour avoir un basculement de fichier \u00e0 chaque changement d&rsquo;heure\u00a0:<\/p>\n<pre>$ <strong>while true; do date; sleep 5; done | dailyfile -c 3600 -p 'date-' -s '.txt' -l<\/strong><\/pre>\n<p style=\"text-align: justify;\">Apr\u00e8s quelques heures on observe des fichiers dont le nom inclut l&rsquo;heure de cr\u00e9ation. On peut observer des petites fluctuations dans le champ \u00ab\u00a0seconde\u00a0\u00bb, d\u00fbes aux p\u00e9riodes de r\u00e9veil du shell.<\/p>\n<pre>$ <strong>ls -l<\/strong>\n-rw-r--r--  1 cpb cpb  2255 avril 27 12:59 date-2017-04-27-12-55-24.txt\n-rw-r--r--  1 cpb cpb 29520 avril 27 13:59 date-2017-04-27-13-00-00.txt\n-rw-r--r--  1 cpb cpb 29520 avril 27 14:59 date-2017-04-27-14-00-02.txt\n-rw-r--r--  1 cpb cpb 29479 avril 27 15:59 date-2017-04-27-15-00-04.txt\n-rw-r--r--  1 cpb cpb 29520 avril 27 16:59 date-2017-04-27-16-00-02.txt\n-rw-r--r--  1 cpb cpb 29479 avril 27 17:59 date-2017-04-27-17-00-04.txt\n-rw-r--r--  1 cpb cpb 29479 avril 27 18:59 date-2017-04-27-18-00-02.txt\n-rw-r--r--  1 cpb cpb 29520 avril 27 19:59 date-2017-04-27-19-00-00.txt\n-rw-r--r--  1 cpb cpb 29479 avril 27 20:59 date-2017-04-27-20-00-03.txt\n-rw-r--r--  1 cpb cpb 29479 avril 27 21:59 date-2017-04-27-21-00-02.txt\n-rw-r--r--  1 cpb cpb 29520 avril 27 22:59 date-2017-04-27-22-00-00.txt\n-rw-r--r--  1 cpb cpb 29479 avril 27 23:59 date-2017-04-27-23-00-04.txt\n-rw-r--r--  1 cpb cpb 31636 avril 28 00:59 date-2017-04-28-00-00-02.txt\n-rw-r--r--  1 cpb cpb 31680 avril 28 01:59 date-2017-04-28-01-00-01.txt\n-rw-r--r--  1 cpb cpb 31636 avril 28 02:59 date-2017-04-28-02-00-04.txt\n-rw-r--r--  1 cpb cpb 31636 avril 28 03:59 date-2017-04-28-03-00-03.txt\n-rw-r--r--  1 cpb cpb 31636 avril 28 04:59 date-2017-04-28-04-00-01.txt\n-rw-r--r--  1 cpb cpb 31680 avril 28 05:59 date-2017-04-28-05-00-00.txt\n-rw-r--r--  1 cpb cpb 31636 avril 28 06:59 date-2017-04-28-06-00-04.txt\n  [...]\n<\/pre>\n<p>&nbsp;<\/p>\n<p style=\"text-align: center;\"><strong>Les suggestions, remarques et <em>pull requests<\/em> sur Github sont les bienvenues\u00a0!<\/strong><\/p>","protected":false},"excerpt":{"rendered":"<p>J&rsquo;ai r&eacute;cemment &eacute;t&eacute; confront&eacute; &agrave; un souci de taille de fichiers de traces pour le d&eacute;bogage d&rsquo;une application. Pour r&eacute;soudre mon probl&egrave;me j&rsquo;ai &eacute;crit un petit programme en ligne de commande permettant de r&eacute;partir la sortie d&rsquo;un pipeline du shell dans des fichiers quotidiens. J&rsquo;ai appel&eacute; cet outil dailyfile et je vous le pr&eacute;sente ici, [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,13],"tags":[],"class_list":["post-4919","post","type-post","status-publish","format-standard","hentry","category-linux-2","category-shell"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/4919","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=4919"}],"version-history":[{"count":38,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/4919\/revisions"}],"predecessor-version":[{"id":4964,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/4919\/revisions\/4964"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=4919"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=4919"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=4919"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}