<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>tail -f | sysadmin</title>
	
	<link>http://www.tail-f.com.ar</link>
	<description>Noticias y recursos para sysadmins Unix</description>
	<lastBuildDate>Sat, 24 Jul 2010 20:42:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Tail-fSysadmin" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="tail-fsysadmin" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Cmd: Creando una consola interactiva con Python</title>
		<link>http://www.tail-f.com.ar/programacion/python/cmd-creando-una-consola-interactiva-con-python.html</link>
		<comments>http://www.tail-f.com.ar/programacion/python/cmd-creando-una-consola-interactiva-con-python.html#comments</comments>
		<pubDate>Sat, 24 Jul 2010 20:42:50 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Cmd]]></category>
		<category><![CDATA[Consola Interactiva]]></category>
		<category><![CDATA[Directadmin]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=400</guid>
		<description><![CDATA[Siguiendo con los ejemplos de los grandes recursos que ofrece la standard library de Python, así como el otro día hablé sobre BaseHTTPServer, hoy voy a hablar de Cmd. Cmd es un módulo que nos permite crear una consola interactiva, como la propia consola de Python, en unas pocas líneas. La consola incluye manejo de [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_402" class="wp-caption alignright" style="width: 290px"><a href="http://www.tail-f.com.ar/wp-content/uploads/smilingpython.gif"><img class="size-full wp-image-402 " title="Python" src="http://www.tail-f.com.ar/wp-content/uploads/smilingpython.gif" alt="Python" width="280" height="280" /></a><p class="wp-caption-text">Python</p></div>
<p>Siguiendo con los ejemplos de los grandes recursos que ofrece la standard library de Python, así como el otro día hablé sobre <a href="http://www.tail-f.com.ar/programacion/python/python-basehttpserver-un-servidor-http-en-unas-pocas-lineas.html">BaseHTTPServer</a>, hoy voy a hablar de <a href="http://docs.python.org/library/cmd.html">Cmd</a>.</p>
<p>Cmd es un módulo que nos permite crear una consola interactiva, como la propia consola de Python, en unas pocas líneas. La consola incluye manejo de distintos prompts, hooks para la ejecución de comandos, manejo de historial, ayuda general y por comando, y autocompletado de comandos y parámetros, etc. Lo único que tenemos que hacer para implementarla es extender la clase <strong>cmd.Cmd</strong> e implementar métodos <strong>do_*</strong> para los distintos comandos que queramos definir.</p>
<p>Veamos las opciones disponibles con un ejemplo muy sencillo:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="co1"># -*- coding: utf-8 -*-</span><br />
<span class="kw1">import</span> <span class="kw3">cmd</span></p>
<p><span class="kw1">class</span> Console<span class="br0">&#40;</span><span class="kw3">cmd</span>.<span class="me1">Cmd</span><span class="br0">&#41;</span>:</p>
<p>&nbsp; &nbsp; prompt = <span class="st0">&quot;&gt; &quot;</span></p>
<p>&nbsp; &nbsp; _colors = <span class="br0">&#123;</span><span class="st0">&#8216;red&#8217;</span>: <span class="st0">&#8216;#FF0000&#8242;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&#8216;white&#8217;</span>: <span class="st0">&#8216;#FFFFFF&#8217;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&#8216;black&#8217;</span>: <span class="st0">&#8216;#000000&#8242;</span><span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">def</span> <span class="kw4">__init__</span> <span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Constructor&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">cmd</span>.<span class="me1">Cmd</span>.<span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">def</span> do_hello <span class="br0">&#40;</span><span class="kw2">self</span>, name<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Says hello to someone&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Hello %s!&quot;</span> % name</p>
<p>&nbsp; &nbsp; <span class="kw1">def</span> do_get_color <span class="br0">&#40;</span><span class="kw2">self</span>, color<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Prints out the hex representation of a color&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> color <span class="kw1">in</span> <span class="kw2">self</span>._colors:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;%s: %s&quot;</span> % <span class="br0">&#40;</span>color, <span class="kw2">self</span>._colors<span class="br0">&#91;</span>color<span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;I don&#8217;t know: %s&quot;</span> % color</p>
<p>&nbsp; &nbsp; <span class="kw1">def</span> complete_get_color <span class="br0">&#40;</span><span class="kw2">self</span>, text, line, begidx, endix<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Complete function for get_color&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#91;</span>i <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">self</span>._colors <span class="kw1">if</span> i.<span class="me1">startswith</span><span class="br0">&#40;</span>text<span class="br0">&#41;</span><span class="br0">&#93;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">def</span> do_quit <span class="br0">&#40;</span><span class="kw2">self</span>, s<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Bye, bye&#8230;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">True</span></p>
<p>&nbsp; &nbsp; <span class="kw1">def</span> help_quit <span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Quits the console&quot;</span></p>
<p>&nbsp; &nbsp; do_EOF = do_quit<br />
&nbsp; &nbsp; help_EOF = help_quit</p>
<p><span class="kw1">if</span> __name__ == <span class="st0">&quot;__main__&quot;</span>:<br />
&nbsp; &nbsp; console = Console<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">try</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; console.<span class="me1">cmdloop</span><span class="br0">&#40;</span><span class="st0">&quot;Hola!&quot;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">except</span> <span class="kw2">KeyboardInterrupt</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; console.<span class="me1">do_quit</span><span class="br0">&#40;</span><span class="kw2">None</span><span class="br0">&#41;</span><br />
&nbsp;</div>
<p><strong>Inicialización</strong></p>
<p>Lo primero que hacemos es definir la clase Console que extiende cmd.Cmd. Luego definimos la propiedad pública &#8220;prompt&#8221;, que será el prompt de la consola (por default &#8220;(Cmd)&#8221;).</p>
<p><strong>Un método básico</strong></p>
<p>Luego tenemos el método do_hello que toma un argumento y le dice hola al argumento. Notesé que el texto que definimos en el comentario (&#8220;Says hello to someone&#8221;), además de ser la documentación de la función es tomada por Cmd para mostrarlo como ayuda del comando. Si en la consola ponemos &#8220;? hello&#8221; o &#8220;help hello&#8221;, se imprimirá esa cadena.</p>
<p><strong>Autocompletado</strong></p>
<p>A continuación tenemos el método do_get_colors que imprime el código hexadecimal de un color, según el diccionario _colors. Además de tener su texto de ayuda, a continuación tenemos el método complete_get_colors que lo que hace es manejar el autocompletado de los parámetros. Aquí lo que hacemos es ver el texto que se tipeó y devolver todas las claves del diccionario _colors que empiecen con ese texto.</p>
<p><strong>Salir de la consola</strong></p>
<p>Para salir del loop de la consola un método tiene que devolver True. Para ello definimos el método do_quit. Aquí imprimimos un saludo y salimos. Las novedades son, por un lado, la función help_quit que cumple la misma función que el docstring: imprime la ayuda del comando quit. Y además duplicamos la función do_quit como do_EOF (y help_quit como help_EOF). De esta forma, cuando la consola reciba EOF (es decir, Ctrl+D) ejecutará do_quit y saldrá.</p>
<p><strong>Ejecutando la consola</strong></p>
<p>Por último, al final del código instanciamos la clase Console y ejecutamos el método cmdloop() que inicia el loop de la consola. De paso agregamos el handling de la excepción KeyboardInterrupt (es decir, Ctrl+C) para que ejecute do_quit y cierre la consola adecuadamente.</p>
<p><strong>Otro ejemplo</strong></p>
<p>Así como hice la última vez, les dejo otro ejemplo más completo en el que anduve trabajando. En este caso es parte del código de mi modesto proyecto <a href="http://www.tail-f.com.ar/paneles-de-control/directadmin/python-directadmin-api-para-conectarse-a-directadmin-desde-python.html">python-directadmin</a>. Se trata de <a href="http://code.google.com/p/python-directadmin/wiki/DaConsole">DAConsole</a>, una pequeña consola interactiva para interactuar con Directadmin, donde implemento todas estas cosas vistas aquí, además de la posibilidad de crear consolas anidadas.</p>
<p><a href="http://code.google.com/p/python-directadmin/source/browse/trunk/daconsole.py">Ver código de DAConsole</a>.</p>
<p><strong>Referencias</strong></p>
<ul>
<li><a href="http://docs.python.org/library/cmd.html">Módulo Cmd en la documentación de Python</a></li>
<li><a href="http://wiki.python.org/moin/CmdModule">Módulo Cmd en la wiki de Python</a> (con explicaciones y ejemplos más completos)</li>
<li><a href="http://code.google.com/p/python-directadmin/source/browse/trunk/daconsole.py">DAConsole</a></li>
</ul>

<p><a href="http://feedads.g.doubleclick.net/~a/dKFcT9McDmCWrEGBkU4uWsXyA4Y/0/da"><img src="http://feedads.g.doubleclick.net/~a/dKFcT9McDmCWrEGBkU4uWsXyA4Y/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/dKFcT9McDmCWrEGBkU4uWsXyA4Y/1/da"><img src="http://feedads.g.doubleclick.net/~a/dKFcT9McDmCWrEGBkU4uWsXyA4Y/1/di" border="0" ismap="true"></img></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/python/cmd-creando-una-consola-interactiva-con-python.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Probando nuevo diseño: zBench</title>
		<link>http://www.tail-f.com.ar/meta/probando-nuevo-diseno-zbench.html</link>
		<comments>http://www.tail-f.com.ar/meta/probando-nuevo-diseno-zbench.html#comments</comments>
		<pubDate>Sun, 18 Jul 2010 18:23:52 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[meta]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[Themes]]></category>
		<category><![CDATA[zBench]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=397</guid>
		<description><![CDATA[Me dieron ganas de probar un nuevo diseño para el blog, un poco más legible. Después de bastante tiempo usando themes negros, esta vez elegí uno más claro, con un mejor contraste que facilite la lectura. Encontré zBench que me pareció que cumplía con los requisitos que buscaba. Además es un theme muy completo, que [...]]]></description>
			<content:encoded><![CDATA[<p>Me dieron ganas de probar un nuevo diseño para el blog, un poco más legible. Después de bastante tiempo usando themes negros, esta vez elegí uno más claro, con un mejor contraste que facilite la lectura.</p>
<p>Encontré <a href="http://wordpress.org/extend/themes/zbench">zBench</a> que me pareció que cumplía con los requisitos que buscaba. Además es un theme muy completo, que implementa la mayor parte de las funcionalidades de WordPress, define estilos para &lt;pre&gt; y &lt;blockquote&gt; que acá uso bastante y me parece lindo.</p>
<p>Así que me tomé algunos minutos para traducirlo (algo que no había hecho con themes anteriores) y lo dejé andando. De paso también vi que el código es bastante prolijo, lo cual es otro punto a favor.</p>
<p>¿Qué les parece?</p>

<p><a href="http://feedads.g.doubleclick.net/~a/fIkPisiXVIgJqmTd6MdeisXHOyI/0/da"><img src="http://feedads.g.doubleclick.net/~a/fIkPisiXVIgJqmTd6MdeisXHOyI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/fIkPisiXVIgJqmTd6MdeisXHOyI/1/da"><img src="http://feedads.g.doubleclick.net/~a/fIkPisiXVIgJqmTd6MdeisXHOyI/1/di" border="0" ismap="true"></img></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/meta/probando-nuevo-diseno-zbench.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Pegá el folleto de las Charlas de Python en tu lugar de trabajo!</title>
		<link>http://www.tail-f.com.ar/programacion/python/pega-el-folleto-de-las-charlas-de-python-en-tu-lugar-de-trabajo.html</link>
		<comments>http://www.tail-f.com.ar/programacion/python/pega-el-folleto-de-las-charlas-de-python-en-tu-lugar-de-trabajo.html#comments</comments>
		<pubDate>Fri, 16 Jul 2010 17:39:29 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Charlas]]></category>
		<category><![CDATA[La Tribu]]></category>
		<category><![CDATA[PyAr]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=390</guid>
		<description><![CDATA[Como les contaba hace unos días, el 24 de julio empieza el Ciclo de Charlas Abiertas de Python Argentina en la sede del Colectivo La Tribu, Lambaré 873. La entrada es libre y gratuita. Se pasará una gorra voluntaria durante los cursos para hacer frente a viáticos y gastos generales. No hace falta registrarse, pero [...]]]></description>
			<content:encoded><![CDATA[<p>Como les contaba hace unos días, el 24 de julio empieza el <a href="http://www.tail-f.com.ar/programacion/python/ciclo-de-charlas-abiertas-de-python-argentina-en-la-tribu.html">Ciclo de Charlas Abiertas de Python Argentina</a> en la sede del Colectivo La Tribu, Lambaré 873.</p>
<div id="attachment_391" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.tail-f.com.ar/wp-content/uploads/charlasabiertaspytribu.png"><img class="size-medium wp-image-391" title="charlasabiertaspytribu" src="http://www.tail-f.com.ar/wp-content/uploads/charlasabiertaspytribu-300x136.png" alt="" width="300" height="136" /></a><p class="wp-caption-text">Charlas Abiertas de Python el La Tribu</p></div>
<p>La entrada es libre y gratuita. Se pasará una gorra voluntaria durante los cursos para hacer frente a viáticos y gastos generales.<br />
No hace falta registrarse, pero vengan temprano para asegurarse un lugar porque los cupos son limitados.</p>
<p>La gente de <a href="http://python.org.ar/pyar/Inicio">PyAr</a> está invitando a pegar <a href="http://www.tail-f.com.ar/files/CharlasAbiertasPythonLaTribu2010.pdf">el folleto</a> de las charlas en facultades y lugares de trabajo.</p>
<p><strong>Mapa:</strong></p>
<div align="center">
<iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="http://maps.google.com/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=Lambar%C3%A9+873,+ciudad+de+buenos+aires&amp;sll=37.0625,-95.677068&amp;sspn=47.167389,89.296875&amp;ie=UTF8&amp;hq=&amp;hnear=Lambar%C3%A9+873,+Almagro,+Ciudad+Aut%C3%B3noma+de+Buenos+Aires,+Argentina&amp;z=14&amp;ll=-34.604634,-58.430473&amp;output=embed"></iframe><br /><small><a href="http://maps.google.com/maps?f=q&amp;source=embed&amp;hl=en&amp;geocode=&amp;q=Lambar%C3%A9+873,+ciudad+de+buenos+aires&amp;sll=37.0625,-95.677068&amp;sspn=47.167389,89.296875&amp;ie=UTF8&amp;hq=&amp;hnear=Lambar%C3%A9+873,+Almagro,+Ciudad+Aut%C3%B3noma+de+Buenos+Aires,+Argentina&amp;z=14&amp;ll=-34.604634,-58.430473" style="color:#0000FF;text-align:left">View Larger Map</a></small></div>

<p><a href="http://feedads.g.doubleclick.net/~a/gh2UTqxQSiy3EBJRI184P8Cy4nk/0/da"><img src="http://feedads.g.doubleclick.net/~a/gh2UTqxQSiy3EBJRI184P8Cy4nk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/gh2UTqxQSiy3EBJRI184P8Cy4nk/1/da"><img src="http://feedads.g.doubleclick.net/~a/gh2UTqxQSiy3EBJRI184P8Cy4nk/1/di" border="0" ismap="true"></img></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/python/pega-el-folleto-de-las-charlas-de-python-en-tu-lugar-de-trabajo.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python BaseHTTPServer: un servidor HTTP en unas pocas líneas</title>
		<link>http://www.tail-f.com.ar/programacion/python/python-basehttpserver-un-servidor-http-en-unas-pocas-lineas.html</link>
		<comments>http://www.tail-f.com.ar/programacion/python/python-basehttpserver-un-servidor-http-en-unas-pocas-lineas.html#comments</comments>
		<pubDate>Thu, 15 Jul 2010 20:25:01 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Load average]]></category>
		<category><![CDATA[Servidor HTTP]]></category>
		<category><![CDATA[Status]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=384</guid>
		<description><![CDATA[Python es un lenguaje tan poderoso que me sorprende constantemente. Particularmente su librería standard incluye tantas cosas maravillosas que lleva tiempo ir descubriéndolas todas. Hoy voy a hablar de BaseHTTPServer un módulo de Python 2.x (en 3.x se llama http.server) que nos permite implementar un servidor web en muy pocas líneas de código. Es la [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_386" class="wp-caption alignright" style="width: 277px"><a href="http://www.tail-f.com.ar/wp-content/uploads/python.png"><img class="size-full wp-image-386" title="python" src="http://www.tail-f.com.ar/wp-content/uploads/python.png" alt="Python" width="267" height="235" /></a><p class="wp-caption-text">Python</p></div>
<p>Python es un lenguaje tan poderoso que me sorprende constantemente. Particularmente su librería standard incluye tantas cosas maravillosas que lleva tiempo ir descubriéndolas todas.</p>
<p>Hoy voy a hablar de <a href="http://docs.python.org/library/basehttpserver.html">BaseHTTPServer</a> un módulo de Python 2.x (en 3.x se llama http.server) que nos permite implementar un servidor web en muy pocas líneas de código. Es la base de otros dos módulos muy interesantes, <a href="http://docs.python.org/library/simplehttpserver.html">SimpleHTTPServer</a> y <a href="http://docs.python.org/library/cgihttpserver.html">CGIHTTPServer</a>. El primero implementa un muy simple servidor web que sirve archivos y el segundo es un servidor que ejecuta script CGI en entornos Unix.</p>
<p>Por ejemplo, con SimpleHTTPServer podemos hacer algo tan maravilloso como esto:</p>
<pre>$ cd ~/musica
$ python -m SimpleHTTPServer
</pre>
<p>Y con sólo eso tenemos montado un servidor web escuchando en 0.0.0.0:8000 y sirviendo todos nuestros archivos de la carpeta ~/musica.</p>
<p>Pero la clase BaseHTTPServer es más poderosa porque nos permite implementar nuestros propios RequestHandlers, es decir, clases que extiendan <a href="http://docs.python.org/library/basehttpserver.html#BaseHTTPServer.BaseHTTPRequestHandler">BaseHTTPRequestHandler</a> y hagan lo que nosotros queramos en cada petición para cada método HTTP. Por ejemplo, para implementar el método GET solamente hace falta crear una clase que extienda BaseHTTPRequestHandler y sobrecargar el método do_GET.</p>
<p>Por ejemplo, si yo quisiera implementar un muy básico servidor que me diga el <a href="http://en.wikipedia.org/wiki/Load_%28computing%29">load average</a> del sistema sería tan sencillo como poner:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="co1">#!/usr/bin/env python</span><br />
<span class="co1"># -*- coding: utf-8 -*-</span><br />
<span class="kw1">import</span> <span class="kw3">os</span><br />
<span class="kw1">import</span> <span class="kw3">sys</span><br />
<span class="kw1">import</span> <span class="kw3">BaseHTTPServer</span></p>
<p><span class="kw1">class</span> RequestHandler <span class="br0">&#40;</span><span class="kw3">BaseHTTPServer</span>.<span class="me1">BaseHTTPRequestHandler</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="kw1">def</span> do_GET <span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">self</span>.<span class="me1">send_response</span><span class="br0">&#40;</span><span class="nu0">200</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">self</span>.<span class="me1">end_headers</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">self</span>.<span class="me1">wfile</span>.<span class="me1">write</span><span class="br0">&#40;</span><span class="kw2">self</span>._get_status<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><br />
&nbsp; &nbsp; <span class="kw1">def</span> _get_status <span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="st0">&quot;Status:<span class="es0">\n</span>&quot;</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&quot;&#8212;&#8212;-<span class="es0">\n</span>&quot;</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&quot;Load average: %s<span class="es0">\n</span>&quot;</span> % \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="st0">&quot;%01.2f, %01.2f, %01.2f&quot;</span> % \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">os</span>.<span class="me1">getloadavg</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p><span class="kw1">def</span> main <span class="br0">&#40;</span>args<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; httpd = <span class="kw3">BaseHTTPServer</span>.<span class="me1">HTTPServer</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="st0">&#8216;localhost&#8217;</span>, <span class="nu0">8000</span><span class="br0">&#41;</span>, RequestHandler<span class="br0">&#41;</span><br />
&nbsp; &nbsp; httpd.<span class="me1">serve_forever</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p><span class="kw1">if</span> __name__ == <span class="st0">&quot;__main__&quot;</span>:<br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span>main<span class="br0">&#40;</span><span class="kw3">sys</span>.<span class="me1">argv</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp;</div>
<p>Y al entrar a http://localhost:8000 vería algo así:</p>
<pre>Status:
-------
Load average: 0.26, 0.35, 0.40
</pre>
<p>A esta altura creo que se hace bastante evidente el potencial de esta clase BaseHTTPServer. Piensen lo sencillo que sería hacer un servidor para un <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer#RESTful_web_services">web service REST (RESTful web service)</a> implementando métodos do_GET, do_DELETE, do_POST etc.</p>
<p>Para jugar un poco hice una versión un poco más completa de este servidor de status. Al correrlo lanza el servidor HTTP, al cual podemos acceder para pedirle un status general del sistema en tres formatos: texto plano (plain), HTML y JSON. También le agregué un <a href="http://docs.python.org/library/optparse.html">OptionParser</a> para poder configurar el host y puerto en el cual el servidor deberá escuchar. Con comentarios y todo ocupa 149 líneas.</p>
<p>Pueden ver el código aquí: <a href="http://pastebin.com/G5FgTDiv">http://pastebin.com/G5FgTDiv</a></p>

<p><a href="http://feedads.g.doubleclick.net/~a/1G0Vxik_ymlQYsoSI-3ZgG7JsBQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/1G0Vxik_ymlQYsoSI-3ZgG7JsBQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/1G0Vxik_ymlQYsoSI-3ZgG7JsBQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/1G0Vxik_ymlQYsoSI-3ZgG7JsBQ/1/di" border="0" ismap="true"></img></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/python/python-basehttpserver-un-servidor-http-en-unas-pocas-lineas.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ciclo de Charlas Abiertas de Python Argentina en La Tribu</title>
		<link>http://www.tail-f.com.ar/programacion/python/ciclo-de-charlas-abiertas-de-python-argentina-en-la-tribu.html</link>
		<comments>http://www.tail-f.com.ar/programacion/python/ciclo-de-charlas-abiertas-de-python-argentina-en-la-tribu.html#comments</comments>
		<pubDate>Sat, 10 Jul 2010 20:38:07 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Charlas]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=378</guid>
		<description><![CDATA[PyAr,  la comunidad de Python Argentina presenta el Ciclo de Charlas Abiertas de Python 2010 en la sede del Colectivo La Tribu. Se trata de una serie de presentaciones que tendrán lugar los días sábados, a lo largo de la segunda mitad del año, desarrollando distintos temas relacionados con Python desde los más básicos a [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_379" class="wp-caption alignright" style="width: 174px"><a href="http://www.tail-f.com.ar/wp-content/uploads/pyar-logo.png"><img class="size-full wp-image-379" title="Python Argentina" src="http://www.tail-f.com.ar/wp-content/uploads/pyar-logo.png" alt="Python Argentina" width="164" height="65" /></a><p class="wp-caption-text">Python Argentina</p></div>
<p><a href="http://python.org.ar/pyar/Inicio">PyAr</a>,  la comunidad de Python Argentina presenta el <a href="http://python.org.ar/pyar/CharlasAbiertas2010">Ciclo de Charlas Abiertas de Python 2010</a> en la sede del <a href="http://www.fmlatribu.com/">Colectivo La Tribu</a>.</p>
<p>Se trata de una serie de presentaciones que tendrán lugar los días sábados, a lo largo de la segunda mitad del año, desarrollando distintos temas relacionados con <a href="http://www.python.org/">Python</a> desde los más básicos a algunos bastante avanzados. Las charlas estarán a cargo de miembros de la comunidad PyAr, destacados desarrolladores con un profundo dominio del lenguaje en cuestión.</p>
<p>Las charlas comienzan el sábado 24 de julio, su entrada es libre y gratuita (sin necesidad de registrarse) y tendrán lugar en la sede del Colectivo La Tribu, sito en Lambaré 873, Capital Federal [<a href="http://maps.google.com/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=Lambar%C3%A9+873,+ciudad+de+buenos+aires&amp;sll=37.0625,-95.677068&amp;sspn=47.167389,89.296875&amp;ie=UTF8&amp;hq=&amp;hnear=Lambar%C3%A9+873,+Almagro,+Ciudad+Aut%C3%B3noma+de+Buenos+Aires,+Argentina&amp;z=16">ver mapa</a>].</p>
<p>A continuación una versión resumida del cronograma de charlas. La versión completa con descripciones y horarios pueden consultarla en la <a href="http://python.org.ar/pyar/CharlasAbiertas2010">página de PyAr</a>.</p>
<p><strong>Cronograma</strong></p>
<p><strong>Día 1: Sábado 24 de Julio</strong><br />
Tema: Introducción a la Programación<br />
Disertante: Facundo Batista</p>
<p><strong>Día 2: Sábado 31 de Julio</strong><br />
Tema: Introducción a Python<br />
Disertantes: Tomás Zulberti y Facundo Batista</p>
<p><strong>Día 3: Sábado 21 de Agosto</strong><br />
Tema: Introducción al Desarrollo Web I<br />
Disertantes: Mariano Reingart y Alejandro J. Cura<br />
Tema: FooBar (virtualenv, buildout, nose)<br />
Disertante: Roberto Alsina</p>
<p><strong>Día 4: Sábado 11 de Septiembre</strong><br />
Tema: Introducción al Desarrollo Web II<br />
Disertantes: Mariano Reingart y Alejandro J. Cura<br />
Tema: Django<br />
Disertante: Manuel Kauffman</p>
<p><strong>Día 5: Sábado 25 de Septiembre</strong><br />
Tema: Introducción a las Interfaces Gráficas de Escritorio I<br />
Disertante: Roberto Alsina<br />
Tema: Plone<br />
Disertante: Roberto Allende</p>
<p><strong>Día 6: Sábado 2 de Octubre</strong><br />
Tema: Introducción a las Interfaces Gráficas de Escritorio II<br />
Disertante: Roberto Alsina<br />
Tema: wxPython<br />
Disertante: Mariano Reingart</p>
<p><strong>Día 7: Sábado 30 de Octubre</strong><br />
Tema: Optimizando Python<br />
Disertante: Gabriel Genellina<br />
Tema: PyQt<br />
Disertante: Roberto Alsina</p>
<p><strong>Día 8: Sábado 13 de Noviembre</strong><br />
Tema: Python 3000<br />
Disertante: Facundo Batista<br />
Tema: Twisted<br />
Disertante: Lucio Torre<br />
<strong><br />
Día 9: Sábado 27 de Noviembre</strong><br />
Tema: Taller de Programación de Juegos<br />
Disertantes: Alejandro J. Cura y Hector Sanchez</p>

<p><a href="http://feedads.g.doubleclick.net/~a/qua2sqT-7CDIrrLZh2X9-8I3ADY/0/da"><img src="http://feedads.g.doubleclick.net/~a/qua2sqT-7CDIrrLZh2X9-8I3ADY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/qua2sqT-7CDIrrLZh2X9-8I3ADY/1/da"><img src="http://feedads.g.doubleclick.net/~a/qua2sqT-7CDIrrLZh2X9-8I3ADY/1/di" border="0" ismap="true"></img></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/python/ciclo-de-charlas-abiertas-de-python-argentina-en-la-tribu.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Obtener listado de link rotos con wget</title>
		<link>http://www.tail-f.com.ar/programacion/bash/obtener-listado-de-link-rotos-con-wget.html</link>
		<comments>http://www.tail-f.com.ar/programacion/bash/obtener-listado-de-link-rotos-con-wget.html#comments</comments>
		<pubDate>Mon, 28 Jun 2010 15:03:44 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[BASH]]></category>
		<category><![CDATA[scripts]]></category>
		<category><![CDATA[wget]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=371</guid>
		<description><![CDATA[Esas cosas por las que uno ama Linux. Encontré este post en DiarioLinux que me pareció genial. $ wget --spider --no-parent -r -o log.txt http://tuweb.com Parámetros: –spider : recorrer la web que le digas, pero SIN descargar nada. Sólo recorrerla. - r : recursivo, como si fuera el robotito de Google - o fichero : [...]]]></description>
			<content:encoded><![CDATA[<p>Esas cosas por las que uno ama Linux. Encontré <a href="http://diariolinux.com/2010/06/11/receta-como-obtener-listado-de-links-rotos/">este post</a> en <a href="http://diariolinux.com">DiarioLinux</a> que me pareció genial.</p>
<pre>$  wget --spider  --no-parent -r -o log.txt http://tuweb.com</pre>
<p><a href="http://www.tail-f.com.ar/wp-content/uploads/broken-link.jpg"><img class="alignright size-medium wp-image-372" title="broken-link" src="http://www.tail-f.com.ar/wp-content/uploads/broken-link-300x224.jpg" alt="" width="300" height="224" /></a><br />
<strong>Parámetros:</strong></p>
<p>–spider : recorrer la web que le digas, pero SIN descargar nada. Sólo  recorrerla.<br />
- r : recursivo, como si fuera el robotito de Google <img src='http://www.tail-f.com.ar/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
- o fichero   :  la salida de ejecutar el comando que salga por pantalla<br />
–no-parent : si le pasamos como parámetro un nombre de directorio, no  queremos que suba hacia los directorios padre.</p>
<p>La lista de enlaces rotos estará en log.txt (parte final)</p>
<p>Tomado de <a href="http://diariolinux.com/2010/06/11/receta-como-obtener-listado-de-links-rotos/">DiarioLinux</a>.</p>
<p>Y agrego otro muy útil. Cómo descargar todos los contenidos de un sitio FTP con wget.</p>
<pre>wget -r -q -b -P /home/myuser/destination ftp://mydomain.com --ftp-user=myuser --ftp-password=mypass</pre>
<p><strong>Parámetros:</strong></p>
<p>-r: recursivo<br />
-q: quiet/silencioso, no imprime mensajes en la consola<br />
-b: background, para que se ejecute en background y nos devuelva el prompt.<br />
-P: directorio donde queremos que se guarde todo lo que bajamos<br />
&#8211;ftp-user=: usuario FTP<br />
&#8211;ftp-password=: password FTP</p>

<p><a href="http://feedads.g.doubleclick.net/~a/bu6f7drP77Up6H4ugVQSDMqvfng/0/da"><img src="http://feedads.g.doubleclick.net/~a/bu6f7drP77Up6H4ugVQSDMqvfng/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/bu6f7drP77Up6H4ugVQSDMqvfng/1/da"><img src="http://feedads.g.doubleclick.net/~a/bu6f7drP77Up6H4ugVQSDMqvfng/1/di" border="0" ismap="true"></img></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/bash/obtener-listado-de-link-rotos-con-wget.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arreglar: ‘Failed to load magic database’</title>
		<link>http://www.tail-f.com.ar/programacion/php/arreglar-failed-to-load-magic-database.html</link>
		<comments>http://www.tail-f.com.ar/programacion/php/arreglar-failed-to-load-magic-database.html#comments</comments>
		<pubDate>Mon, 31 May 2010 02:04:22 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Fileinfo]]></category>
		<category><![CDATA[Mime Magic]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=368</guid>
		<description><![CDATA[Cada tanto nos topamos con esos errores molestos y dificiles de solucionar, y la solución la encontramos en un comentario perdido en php.net. El error de hoy es el siguiente: Warning: finfo::finfo() [finfo.finfo]: Failed to load magic database at &#8216;/usr/share/misc/magic&#8217; El archivo /usr/share/misc/magic existe, tiene permisos, etc. PHP estaba actualizado, fileinfo también, todo. ¿Cuál era [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_103" class="wp-caption alignright" style="width: 105px"><a href="http://www.tail-f.com.ar/wp-content/uploads/php-med-trans.png"><img class="size-full wp-image-103" title="PHP" src="http://www.tail-f.com.ar/wp-content/uploads/php-med-trans.png" alt="PHP" width="95" height="51" /></a><p class="wp-caption-text">PHP</p></div>
<p>Cada tanto nos topamos con esos errores molestos y dificiles de solucionar, y la solución la encontramos en <a href="http://usphp.com/manual/en/ref.fileinfo.php#73924">un comentario perdido en php.net</a>.</p>
<p>El error de hoy es el siguiente:</p>
<blockquote><p>Warning: finfo::finfo() [finfo.finfo]: Failed to load magic database<br />
at &#8216;/usr/share/misc/magic&#8217;</p></blockquote>
<p>El archivo /usr/share/misc/magic existe, tiene permisos, etc. PHP estaba actualizado, fileinfo también, todo.</p>
<p>¿Cuál era el problema? <a href="http://en.wikipedia.org/wiki/Libmagic">libmagic</a> le agrega &#8220;.mime&#8221; al archivo y por eso PHP no lo encuentra, ni tampoco muestra un mensaje de error que se entienda.</p>
<p><strong>Solución</strong></p>
<p>Creamos un link simbólico para el archivo que libmagic va a buscar.</p>
<pre># ln -s /usr/share/misc/magic /usr/share/misc/magic.mime
</pre>

<p><a href="http://feedads.g.doubleclick.net/~a/ejXab0q_onw915INqkEiumcTkhE/0/da"><img src="http://feedads.g.doubleclick.net/~a/ejXab0q_onw915INqkEiumcTkhE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ejXab0q_onw915INqkEiumcTkhE/1/da"><img src="http://feedads.g.doubleclick.net/~a/ejXab0q_onw915INqkEiumcTkhE/1/di" border="0" ismap="true"></img></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/programacion/php/arreglar-failed-to-load-magic-database.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Instalar Monit: monitoreo de servicios para servidores Unix</title>
		<link>http://www.tail-f.com.ar/servicios/instalar-monit-monitoreo-de-servicios-para-servidores-unix.html</link>
		<comments>http://www.tail-f.com.ar/servicios/instalar-monit-monitoreo-de-servicios-para-servidores-unix.html#comments</comments>
		<pubDate>Sun, 04 Apr 2010 14:40:47 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[servicios]]></category>
		<category><![CDATA[Monit]]></category>
		<category><![CDATA[Monitoreo]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=364</guid>
		<description><![CDATA[Hoy voy a explicar cómo instalar Monit, un software muy completo para monitoreo de servicios (locales y remotos) de cualquier sistema Unix. Con él podremos estar atentos ante posibles problemas en alguno de nuestros servidores y realizar algunas tareas automaticamente. ¿Qué es Monit? De acuerdo con su propia definición, Monit es una utilidad gratuita y [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.tail-f.com.ar/wp-content/uploads/monit-logo.gif"><img class="alignright size-full wp-image-365" title="Monit" src="http://www.tail-f.com.ar/wp-content/uploads/monit-logo.gif" alt="Monit" width="269" height="115" /></a>Hoy voy a explicar cómo instalar <a href="http://mmonit.com/monit/">Monit</a>, un software muy completo para monitoreo de servicios (locales y remotos) de cualquier sistema Unix. Con él podremos estar atentos ante posibles problemas en alguno de nuestros servidores y realizar algunas tareas automaticamente.</p>
<p><strong>¿Qué es Monit?</strong></p>
<p>De acuerdo con su propia definición, Monit es una utilidad gratuita y Open Source para administrar y monitorear procesos, archivos, directorios y filesystems en un sistema Unix. Realiza tareas automáticas de mantenimiento y reparación y puede ejecutar acciones significativas durante situaciones de error.</p>
<p>Está desarrollado en C (pueden ver el <a href="http://code.google.com/p/monit/source/browse/">código fuente en Google Code</a>) y su demonio corre de manera casi imperceptible para el sistema, en tanto consume muy pocos recursos.</p>
<p>Para más información, se puede consultar el <a href="http://mmonit.com/monit/">sitio oficial de Monit</a> y su <a href="http://mmonit.com/monit/documentation/monit.html">manual online</a> (ambos en inglés).</p>
<p><strong>Instalación</strong></p>
<p>La instalación de Monit es muy sencilla.</p>
<pre># cd /usr/src
# wget http://mmonit.com/monit/dist/monit-5.1.1.tar.gz
# tar zxvf monit-5.1.1.tar.gz
# cd monit-5.1.1
# ./configure --prefix=/usr
# make &amp;&amp; make install</pre>
<p>Luego, si estamos instalando en CentOS o algún Linux similar, vamos a querer copiar el archivo rc.</p>
<pre># cp contrib/rc.monit /etc/init.d/monit
# chown root:root /etc/init.d/monit
# chmod 755 /etc/init.d/monit
# chkconfig --add monit
# chkconfig monit on</pre>
<p><strong>Configuración</strong></p>
<p>Una vez instalado podemos pasar a la configuración, que será lo más importante del proceso. Para ello yo suelo crear un archivo inicial /etc/monitrc que tiene la configuración general del Monit, y luego dentro de una carpeta /etc/monit creo un archivo por cada servicio que quiero monitorear.</p>
<p>Les dejo aquí mi configuración.</p>
<p>Archivo: /etc/monitrc</p>
<pre>set daemon  120
set logfile syslog facility log_daemon
set mailserver localhost

set alert administrator@domain.com                      # receive all alert
set alert anotheradmin@domain2.com

set httpd port 2812 and
   use address localhost  # only accept connection from localhost
    allow localhost        # allow localhost to connect to the server and
#    allow admin:monit      # require user 'admin' with password 'monit'
#
#
###############################################################################
## Services
###############################################################################
##
## Check general system resources such as load average, cpu and memory
## usage. Each test specifies a resource, conditions and the action to be
## performed should a test fail.
#
  check system fqdn.domain.com
    if loadavg (1min) &gt; 5 then alert
    if loadavg (5min) &gt; 10 then alert
    if loadavg (1min) &gt; 20 then exec "/bin/bash /root/handle_high_load.sh"
    if memory usage &gt; 75% then alert
    if cpu usage (user) &gt; 70% for 3 cycles then alert
    if cpu usage (system) &gt; 30% for 3 cycles then alert
    if cpu usage (wait) &gt; 20% for 3 cycles then alert

include /etc/monit/*.monitrc</pre>
<p>Algunas cosas para anotar de esta primera parte. El daemon va a revisar cada 120 segundos los servicios, va a loguear en Syslog y va enviar mails usando el mailserver local. Cuando haya alguna alerta, la enviará a administrador@domain.com y anotheradmin@domain2.com. Luego habilito el servicio web que ofrece monit para que escuche en la IP local (esto es para poder utilizar todas las opciones del comando `monit`). Por último defino las reglas para el chequeo del sistema, cuyo FQDN es fqdn.domain.com (acá iría el hostname de su servidor). Las reglas son bastante sencillas. En algunos casos lo que hago es enviar una alerta y si el loadavg es más de 20 ejecuto un script para controlarlo.</p>
<p>La última línea incluye todos los archivos *.monit del directorio /etc/monit. Que es lo que vamos a ver ahora.</p>
<p>Archivo: /etc/monit/httpd.monitrc</p>
<pre>#
# Monitor Apache (httpd)
#
check process httpd with pidfile /var/run/httpd.pid
    start program = "/sbin/service httpd start"
    stop program  = "/sbin/service httpd stop"
    if cpu &gt; 80% for 3 cycles then alert
    if totalmem &gt; 1500.0 MB for 5 cycles then alert
    if children &gt; 250 then alert
    if children &gt; 255 for 5 cycles then stop
    if cpu usage &gt; 95% for 3 cycles then restart
    if failed port 80 protocol http then restart

check file httpd.conf with path /etc/httpd/conf/httpd.conf
    if changed checksum then alert</pre>
<p>Aquí defino un proceso de nombre &#8220;httpd&#8221; con un pidfile en /var/run/httpd.pid. Luego defino los comandos para iniciar y detener el proceso. Y luego las acciones a realizar según el evento. En algunos casos será &#8220;alert&#8221; (enviar aviso por mail), en otros &#8220;restart&#8221; (reinicar el proceso). Hay otras opciones que podrán ver en la <a href="http://mmonit.com/monit/documentation/monit.html">documentación</a>. Por último agrego una verificación del archivo httpd.conf. Si se modifica me notificará por mail.</p>
<p>De la misma forma, en el directorio /etc/monit tengo archivos similares para MySQL, SMTP, POP3, IMAP, SSH, etc. Y además tengo archivos para controlar algunos servicios externos. Esto es por una cuestión básica: hasta ahora estamos haciendo todos chequeos locales, si el servidor se cae o por alguna razón no puede enviarme las alertas, podría nunca enterarme de qué pasa. Entonces voy a agregar este otro archivo para controlar un servidor externo que me diga si los servicios están accesibles.</p>
<p>Archivo: server1.monitrc</p>
<pre># server1.domain.com check
check host server1.domain.com with address 1.2.3.4
      if failed icmp type echo count 10 with timeout 15 seconds
         then alert
      if failed port 21 proto ftp then alert
      if failed port 25 proto smtp then alert
      if failed port 80 proto http then alert
      if failed port 110 proto pop then alert</pre>
<p>Aquí estoy monitreando el servidor server1.domain.com con IP 1.2.3.4 (este archivo debería estar en otro servidor con Monit, por ejemplo, servidor2.domain.com). Lo primero que intento es hacer un Echo ICMP. Lamentablemente Monit no soporta hacer ping, pero un echo ICMP es lo más cercano que nos permite. Si falla 10 veces seguidas, le pido que me avise (la cantidad de veces tan alta es para asegurarme de no recibir una alerta por un paquete perdido y llenar mi mail de alertas inútiles que no me permitan ver las importantes). Luego agrego que testee los principales puertos a través de los protocolos correspondientes y que si falla me avise.</p>
<p><strong>Iniciando Monit</strong></p>
<p>Una vez que tenemos la configuración, ya podemos probarlo. Para ello iniciaremos el servicio, veremos si se inicia correctamente en el log y veremos el status.</p>
<p>Iniciamos:</p>
<pre># service monit start</pre>
<p>Luego vemos en syslog:</p>
<pre>Apr  4 11:35:23 fqdn monit[24820]: Starting monit daemon with http interface at [localhost:2812]
Apr  4 11:35:23 fqdn monit[24822]: Starting monit HTTP server at [localhost:2812]
Apr  4 11:35:23 fqdn monit[24822]: monit HTTP server started
Apr  4 11:35:23 fqdn monit[24822]: 'fqdn.domain.com' Monit started</pre>
<p>Monit inició y tiene su servidor HTTP escuchando en localhost:2812. Ahora veamos el resumen del status de los servicios.</p>
<pre># monit status
The Monit daemon 5.0.3 uptime: 1m 

System 'fqdn.domain.com' running
Process 'sshd'                      running
File 'sshd_config'                  accessible
Process 'exim'                      running
File 'exim.conf'                    accessible
Process 'mysqld'                    running
File 'my.cnf'                       accessible
Process 'httpd'                     running
File 'httpd.conf'                   accessible
Remote Host 'fqdn.domain.com' online with all services</pre>
<p>Para ver los comandos disponibles:</p>
<pre># monit -h</pre>
<p>Al mismo tipo de información podremos acceder por vía web si accedemos a http://localhost:2812. También, si queremos acceder desde afuera, podemos configurar Monit para que escuche en otra IP (por ejemplo, 0.0.0.0) y definir un método de autenticación (para que no pueda acceder cualquiera).</p>

<p><a href="http://feedads.g.doubleclick.net/~a/854_8_Z-0CZAawUnHhaanemu2Mw/0/da"><img src="http://feedads.g.doubleclick.net/~a/854_8_Z-0CZAawUnHhaanemu2Mw/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/854_8_Z-0CZAawUnHhaanemu2Mw/1/da"><img src="http://feedads.g.doubleclick.net/~a/854_8_Z-0CZAawUnHhaanemu2Mw/1/di" border="0" ismap="true"></img></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/servicios/instalar-monit-monitoreo-de-servicios-para-servidores-unix.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Python: Ver dominios de Apache que más transferencia consumen</title>
		<link>http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/python-ver-dominios-de-apache-que-mas-transferencia-consumen.html</link>
		<comments>http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/python-ver-dominios-de-apache-que-mas-transferencia-consumen.html#comments</comments>
		<pubDate>Thu, 11 Mar 2010 01:47:12 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[access_log]]></category>
		<category><![CDATA[log]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=361</guid>
		<description><![CDATA[Hace un rato publiqué un post con un script para ver qué dominios de Apache consumen mayor transferencia. El script en BASH toma unos 7 segundos en procesar 750 archivos de uno de mis servidores. Ahora hice una versión en Python, para la que me dieron algunos consejos los chicos de PyAr, y toma aproximadamente [...]]]></description>
			<content:encoded><![CDATA[<p>Hace un rato publiqué un post con un script para ver <a href="http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/ver-dominios-de-apache-que-mas-transferencia-consumen.html">qué dominios de Apache consumen mayor transferencia</a>. El script en <a href="http://www.tail-f.com.ar/tag/bash">BASH</a> toma unos 7 segundos en procesar 750 archivos de uno de mis servidores. Ahora hice una versión en <a href="http://www.tail-f.com.ar/tag/python">Python</a>, para la que me dieron algunos consejos los chicos de <a href="http://python.org.ar/pyar/">PyAr</a>, y toma aproximadamente 4 segundos en procesar los mismos archivos. Aquí les dejo el código:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="co1">#!/usr/bin/env python</span><br />
<span class="st0">&quot;&quot;</span><span class="st0">&quot; Access Log Parser</p>
<p>Parses all the files in a directory<br />
treating them as access_log files<br />
and outputs the list of files sorted<br />
by transfered megabytes. Useful for<br />
identifying heavy users.</p>
<p>Usage:<br />
./access_log_parser.py &lt;base_dir&gt;<br />
base_dir = directory where the access_log files are<br />
&quot;</span><span class="st0">&quot;&quot;</span><br />
<span class="kw1">import</span> <span class="kw3">sys</span><br />
<span class="kw1">import</span> <span class="kw3">os</span><br />
<span class="kw1">import</span> <span class="kw3">time</span><br />
<span class="kw1">from</span> <span class="kw3">operator</span> <span class="kw1">import</span> itemgetter</p>
<p><span class="kw1">def</span> main <span class="br0">&#40;</span>args<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Main</p>
<p>&nbsp; &nbsp; Main function of the script.<br />
&nbsp; &nbsp; This is where the magic happens.<br />
&nbsp; &nbsp; It takes the script arguments<br />
&nbsp; &nbsp; and returns an exit code.<br />
&nbsp; &nbsp; &quot;</span><span class="st0">&quot;&quot;</span></p>
<p>&nbsp; &nbsp; <span class="co1"># Parameter checking</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw2">len</span><span class="br0">&#40;</span>args<span class="br0">&#41;</span> &lt; <span class="nu0">2</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Usage: %s &lt;base_dir&gt;&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">1</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">isdir</span><span class="br0">&#40;</span>args<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; base_dir = args<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">print</span> <span class="st0">&quot;%s is not a directory&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">return</span> <span class="nu0">2</span></p>
<p>&nbsp; &nbsp; <span class="co1"># Init vars</span><br />
&nbsp; &nbsp; t1 = <span class="kw3">time</span>.<span class="kw3">time</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; mbyte = <span class="nu0">1048576.0</span><br />
&nbsp; &nbsp; domains = <span class="br0">&#91;</span><span class="br0">&#93;</span></p>
<p>&nbsp; &nbsp; <span class="co1"># Start processing files</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> item <span class="kw1">in</span> <span class="kw3">os</span>.<span class="me1">listdir</span><span class="br0">&#40;</span>args<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; path = <span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">join</span><span class="br0">&#40;</span>base_dir, item<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">isfile</span><span class="br0">&#40;</span>path<span class="br0">&#41;</span> <span class="kw1">and</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">getsize</span><span class="br0">&#40;</span>path<span class="br0">&#41;</span> &gt; <span class="nu0">0</span>:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bytes = <span class="nu0">0</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; init_date = <span class="kw2">None</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data = <span class="kw2">None</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1"># Process file lines</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> line <span class="kw1">in</span> <span class="kw2">open</span><span class="br0">&#40;</span>path, <span class="st0">&#8216;r&#8217;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data = line.<span class="me1">split</span><span class="br0">&#40;</span><span class="st0">&quot; &quot;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> init_date <span class="kw1">is</span> <span class="kw2">None</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; init_date = data<span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">1</span>:<span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">try</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bytes += <span class="kw2">long</span><span class="br0">&#40;</span>data<span class="br0">&#91;</span><span class="nu0">9</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">except</span> <span class="kw2">ValueError</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">pass</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; domains.<span class="me1">append</span><span class="br0">&#40;</span><span class="br0">&#123;</span><span class="st0">&#8216;domain&#8217;</span>: item, \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;mbytes&#8217;</span>: bytes / mbyte, \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;init_date&#8217;</span>: init_date, \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;end_date&#8217;</span>: data<span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">1</span>:<span class="br0">&#93;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span></p>
<p>&nbsp; &nbsp; <span class="co1"># Print out sorted information</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> domain <span class="kw1">in</span> <span class="kw2">sorted</span><span class="br0">&#40;</span>domains, key=itemgetter<span class="br0">&#40;</span><span class="st0">&#8216;mbytes&#8217;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;%.2f MB | From: %s | To: %s | %s&quot;</span> % \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>domain<span class="br0">&#91;</span><span class="st0">&#8216;mbytes&#8217;</span><span class="br0">&#93;</span>, \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;domain<span class="br0">&#91;</span><span class="st0">&#8216;init_date&#8217;</span><span class="br0">&#93;</span>, \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;domain<span class="br0">&#91;</span><span class="st0">&#8216;end_date&#8217;</span><span class="br0">&#93;</span>, \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;domain<span class="br0">&#91;</span><span class="st0">&#8216;domain&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Generated in %d seconds&quot;</span> % <span class="br0">&#40;</span><span class="kw3">time</span>.<span class="kw3">time</span><span class="br0">&#40;</span><span class="br0">&#41;</span> &#8211; t1<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span></p>
<p><span class="kw1">if</span> __name__ == <span class="st0">&quot;__main__&quot;</span>:<br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span>main<span class="br0">&#40;</span><span class="kw3">sys</span>.<span class="me1">argv</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
<p>Para ejecutarlo:</p>
<pre>./access_log_parser.py /tmp/domain_logs
...
544.30 MB | From: 10/Mar/2010:02:48:33 | To: 10/Mar/2010:18:13:25 | dominio1.com.ar.log
602.34 MB | From: 10/Mar/2010:00:23:09 | To: 10/Mar/2010:23:39:45 | dominio2.com.ar.log
944.03 MB | From: 10/Mar/2010:00:49:35 | To: 10/Mar/2010:23:39:57 | dominio3.com.ar.log
Generated in 3 seconds
</pre>

<p><a href="http://feedads.g.doubleclick.net/~a/EoIXt8T6tXB5K-Mg2scobNzrLfA/0/da"><img src="http://feedads.g.doubleclick.net/~a/EoIXt8T6tXB5K-Mg2scobNzrLfA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/EoIXt8T6tXB5K-Mg2scobNzrLfA/1/da"><img src="http://feedads.g.doubleclick.net/~a/EoIXt8T6tXB5K-Mg2scobNzrLfA/1/di" border="0" ismap="true"></img></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/python-ver-dominios-de-apache-que-mas-transferencia-consumen.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ver dominios de Apache que más transferencia consumen</title>
		<link>http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/ver-dominios-de-apache-que-mas-transferencia-consumen.html</link>
		<comments>http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/ver-dominios-de-apache-que-mas-transferencia-consumen.html#comments</comments>
		<pubDate>Wed, 10 Mar 2010 19:07:44 +0000</pubDate>
		<dc:creator>elbarto</dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[BASH]]></category>
		<category><![CDATA[access_log]]></category>
		<category><![CDATA[logs]]></category>

		<guid isPermaLink="false">http://www.tail-f.com.ar/?p=350</guid>
		<description><![CDATA[Frecuentemente me encuentro ante la necesidad de saber qué dominios de los que tengo alojados en mis servidores consumen más tráfico HTTP. Como éste es el tipo de tráfico más importante y que más incide en el desempeño general de mis servidores, saber qué dominios transfieren más datos por HTTP me orienta en la búsqueda [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.tail-f.com.ar/wp-content/uploads/nerd.jpg"><img class="alignright size-medium wp-image-354" title="nerd" src="http://www.tail-f.com.ar/wp-content/uploads/nerd-300x227.jpg" alt="" width="300" height="227" /></a>Frecuentemente me encuentro ante la necesidad de saber qué dominios de los que tengo alojados en mis servidores consumen más tráfico HTTP. Como éste es el tipo de tráfico más importante y que más incide en el desempeño general de mis servidores, saber qué dominios transfieren más datos por HTTP me orienta en la búsqueda de heavy users. Para ello hice un script hace algún tiempo, y ahora lo estuve revisando, retocando y simplificando, y decidí compartirlo.</p>
<p>En el entorno de <a href="http://www.tail-f.com.ar/tag/directadmin">Directadmin</a>, los logs de <a href="http://www.tail-f.com.ar/tag/apache">Apache</a> se encuentran en /var/log/httpd. Allí hay una carpeta &#8220;domains&#8221; que guarda los logs de cada dominio. Por cada dominio hay tres logs: dominio.com.log, dominio.com.error.log y dominio.com.bytes. El primero es el access_log, el segundo el error_log y el tercero solamente guarda la cantidad de bytes de cada request. La opción más sencilla es trabajar con este último tipo de logs, pero el problema que tienen es que no indican la fecha. Si bien se supone que los logs de Directadmin rotan una vez por día, alguna vez me ha pasado que por razones que nunca pude descubrir, algunos logs no rotaban y generaban ciertas confusiones. Por lo tanto, el script que dejo usa los access_logs. Además esta opción es reutilizable en otras implementaciones de Apache que no tengan archivos de bytes.</p>
<p>El código:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="re3"># Access Log Parser</span><br />
<span class="re3">#</span><br />
<span class="re3"># Parses all the files <span class="kw1">in</span> a directory</span><br />
<span class="re3"># treating them <span class="kw2">as</span> access_log files</span><br />
<span class="re3"># and outputs the list of files sorted</span><br />
<span class="re3"># by transfered megabytes. Useful for</span><br />
<span class="re3"># identifying heavy <span class="kw2">users</span>.</span><br />
<span class="re3">#</span><br />
<span class="re3"># Usage:</span><br />
<span class="re3"># ./access_log_parser.<span class="kw2">sh</span> &lt;base_dir&gt;</span><br />
<span class="re3"># base_dir = directory where the access_log files are</span></p>
<p><span class="kw1">if</span> <span class="br0">&#91;</span> -z $<span class="nu0">1</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Usage: $0 &quot;</span><br />
&nbsp; &nbsp; <span class="kw3">exit</span> <span class="nu0">1</span><br />
<span class="kw1">fi</span></p>
<p><span class="re2">BASE_DIR=</span>$<span class="nu0">1</span><br />
<span class="re2">T1=</span>`<span class="kw2">date</span> +%s`<br />
<span class="kw1">for</span> <span class="kw2">file</span> <span class="kw1">in</span> <span class="re1">$BASE_DIR</span>/*;<br />
<span class="kw1">do</span><br />
&nbsp; &nbsp; <span class="re2">size=</span>`<span class="kw2">stat</span> -c %s <span class="re1">$file</span>`<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re1">$size</span> -gt <span class="nu0">0</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re2">from=</span>`<span class="kw2">head</span> <span class="nu0">-1</span> <span class="re1">$file</span> | <span class="kw2">awk</span> <span class="st0">&#8216;{print($4)}&#8217;</span> |sed <span class="st0">&#8216;s/^<span class="es0">\[</span>//&#8217;</span>`<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re2">to=</span>`<span class="kw2">tail</span> <span class="nu0">-1</span> <span class="re1">$file</span> | <span class="kw2">awk</span> <span class="st0">&#8216;{print($4)}&#8217;</span> |sed <span class="st0">&#8216;s/^<span class="es0">\[</span>//&#8217;</span>`<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re2">bytes=</span>`<span class="kw2">cat</span> <span class="re1">$file</span> | <span class="kw2">awk</span> <span class="st0">&#8216;{a+=$10}END{print a}&#8217;</span>`<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re2">mbytes=</span>`<span class="kw3">echo</span> <span class="re1">$bytes</span> | <span class="kw2">awk</span> <span class="st0">&#8216;{print $1 / 1048576}&#8217;</span>`<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> &nbsp;<span class="st0">&quot;$mbytes MB ($bytes bytes) | From: $from | To: $to | ${file:${#BASE_DIR}+1}&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span><br />
<span class="kw1">done</span> \<br />
| <span class="kw2">sort</span> -nb<br />
<span class="re2">T=</span>`<span class="kw2">date</span> +%s`</div>
<p>Un detalle importante: el script levanta todos los archivos de un directorio que se especifica por parámetro. Esto es así porque yo lo invoco desde otro script:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="re3">#!/bin/bash</span><br />
<span class="re2">LOG_DIR=</span>/var/log/httpd/domains/<br />
<span class="re2">TMP=</span>/tmp/domain_logs<br />
<span class="kw1">if</span> <span class="br0">&#91;</span> ! -d <span class="re1">$TMP</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; <span class="kw2">mkdir</span> -p <span class="re1">$TMP</span><br />
<span class="kw1">fi</span></p>
<p><span class="kw2">rm</span> -f <span class="re1">$TMP</span>/*</p>
<p><span class="kw3">cd</span> <span class="re1">$LOG_DIR</span><br />
<span class="kw1">for</span> i <span class="kw1">in</span> `<span class="kw2">ls</span> *.log |grep -v error`; <span class="kw1">do</span><br />
&nbsp; &nbsp; <span class="kw2">ln</span> <span class="re1">$i</span> <span class="re1">$TMP</span>/<span class="re1">$i</span><br />
<span class="kw1">done</span><br />
/root/access_log_parser.<span class="kw2">sh</span> <span class="re1">$TMP</span></div>
<p>Este último script lo que hace es crear un directorio temporal (si no existe). Vaciar su contenido. Y luego generar hardlinks a todos los access_logs de /var/log/httpd/domains. De esta forma, no me tengo que preocupar por si los logs son modificados mientras yo estoy ejecutando el script. Por último, ejecuta mi primer script (access_log_parser.sh) y le pasa como parámetro el directorio temporal donde están los access_logs.</p>
<p>Por último, la salida del script sería algo así:</p>
<pre>...
186.995 MB (196078184 bytes) | From: 10/Mar/2010:00:27:47 | To: 10/Mar/2010:16:51:09 | dominio1.com.ar.log
187.096 MB (196184596 bytes) | From: 10/Mar/2010:03:24:55 | To: 10/Mar/2010:16:51:24 | dominio2.com.ar.log
245.692 MB (257626221 bytes) | From: 10/Mar/2010:02:53:50 | To: 10/Mar/2010:16:39:54 | dominio3.com.log
273.46 MB (286743390 bytes) | From: 10/Mar/2010:02:48:33 | To: 10/Mar/2010:14:59:29 | dominio4.com.ar.log
306.344 MB (321224473 bytes) | From: 10/Mar/2010:00:23:09 | To: 10/Mar/2010:16:51:20 | dominio5.com.ar.log
444.097 MB (465669066 bytes) | From: 10/Mar/2010:00:49:35 | To: 10/Mar/2010:16:51:20 | dominio6.com.ar.log
Generated in 6 seconds</pre>
<p>Les dejo, de yapa, la opción del script utilizando los logs de bytes. Como dije, esta opción es un poco más sencilla y veloz, pero no nos dice las fechas de los logs.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="re3">#!/bin/bash</span></p>
<p><span class="kw1">if</span> <span class="br0">&#91;</span> -z $<span class="nu0">1</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Usage: $0 &quot;</span><br />
&nbsp; &nbsp; <span class="kw3">exit</span> <span class="nu0">1</span><br />
<span class="kw1">fi</span></p>
<p><span class="re2">BASE_DIR=</span>$<span class="nu0">1</span><br />
<span class="re2">T1=</span>`<span class="kw2">date</span> +%s`<br />
<span class="kw1">for</span> <span class="kw2">file</span> <span class="kw1">in</span> <span class="re1">$BASE_DIR</span>/*.bytes;<br />
<span class="kw1">do</span><br />
&nbsp; &nbsp; <span class="re2">size=</span>`<span class="kw2">stat</span> -c %s <span class="re1">$file</span>`<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re1">$size</span> -gt <span class="nu0">0</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re2">bytes=</span>`<span class="kw2">cat</span> <span class="re1">$file</span> | <span class="kw2">awk</span> <span class="st0">&#8216;{a+=$1}END{print a}&#8217;</span>`<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re2">mbytes=</span>`<span class="kw3">echo</span> <span class="re1">$bytes</span> | <span class="kw2">awk</span> <span class="st0">&#8216;{print $1 / 1048576}&#8217;</span>`<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> &nbsp;<span class="st0">&quot;$mbytes MB ($bytes bytes) ${file:${#BASE_DIR}+1}&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span><br />
<span class="kw1">done</span> \<br />
| <span class="kw2">sort</span> -nb<br />
<span class="re2">T=</span>`<span class="kw2">date</span> +%s`<br />
<span class="kw3">echo</span> <span class="st0">&quot;Generated in $(($T-$T1)) seconds&quot;</span></div>
<p>Y la salida sería así:</p>
<pre># ./parser.sh /var/log/httpd/domains
...
181.716 MB (190543470 bytes) dominio1.com.bytes
187.115 MB (196203973 bytes) dominio2.com.ar.bytes
189.093 MB (198278283 bytes) dominio3.com.ar.bytes
245.692 MB (257626221 bytes) dominio4.com.bytes
273.472 MB (286756234 bytes) dominio5.com.ar.bytes
314.32 MB (329588717 bytes) dominio6.com.ar.bytes
444.516 MB (466108759 bytes) dominio7.com.ar.bytes
Generated in 2 seconds</pre>

<p><a href="http://feedads.g.doubleclick.net/~a/b6bOUIi-L0FT2z9yl2VASb0hEGI/0/da"><img src="http://feedads.g.doubleclick.net/~a/b6bOUIi-L0FT2z9yl2VASb0hEGI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/b6bOUIi-L0FT2z9yl2VASb0hEGI/1/da"><img src="http://feedads.g.doubleclick.net/~a/b6bOUIi-L0FT2z9yl2VASb0hEGI/1/di" border="0" ismap="true"></img></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.tail-f.com.ar/servicios/httpd/apache-httpd-servicios/ver-dominios-de-apache-que-mas-transferencia-consumen.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic page generated in 0.654 seconds. --><!-- Cached page generated by WP-Super-Cache on 2010-07-24 18:51:08 -->
