<?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>Michael Krenz</title>
	<atom:link href="http://www.michaelkrenz.de/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.michaelkrenz.de</link>
	<description>a little tech and a little rock'n'roll</description>
	<lastBuildDate>Sat, 10 Dec 2011 16:08:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Using PECL/Memcached to store sessions</title>
		<link>http://www.michaelkrenz.de/2011/09/06/using-peclmemcached-to-store-sessions/</link>
		<comments>http://www.michaelkrenz.de/2011/09/06/using-peclmemcached-to-store-sessions/#comments</comments>
		<pubDate>Tue, 06 Sep 2011 12:06:00 +0000</pubDate>
		<dc:creator>Michael Krenz</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.michaelkrenz.de/?p=167</guid>
		<description><![CDATA[This post is the second part of my earlier article about installing and setting up the Memcached server and PECL/Memcached PHP client on CentOS 5.5. Let&#8217;s assume you have PECL/Memcached up and running and want to use it as a session handler. I&#8217;ll talk below about why you&#8217;d want to do this (and why not) [...]]]></description>
			<content:encoded><![CDATA[<p>This post is the second part of my earlier article about <a href="http://www.michaelkrenz.de/2011/09/06/how-to-set-up-the-memcached-php-client-library-on-centos-5">installing and setting up the Memcached server and PECL/Memcached PHP client on CentOS 5.5</a>.</p>
<p>Let&#8217;s assume you have PECL/Memcached up and running and want to use it as a session handler. I&#8217;ll talk below about why you&#8217;d want to do this (and why not) and how to get there.</p>
<h2>Is storing sessions with Memcached a good idea?</h2>
<p>As usual: it depends.<br />
Regular file-based session storage is reliable and reasonably fast. It has its drawbacks though, especially when you want to scale: First of all, if you have several servers behind a load balancer, you need to make sure that a visitor always gets the same session if he is assigned to another server in-between. This is difficult if sessions are stored locally on each server. Also, a LOT of these tiny session files can pile up fast on your server, which makes server backups more difficult. Also, when you&#8217;re on a cheap cloud server, file I/O speed might not be optimal. So you start thinking about a RAM-based solution. One way to do this would be a tmpfs partition to store session files in memory. But remember, you still need a central place to store sessions. In comes Memcached.<br />
Memcached operates in-memory only, and can be run on one or more central servers. Great, right? Yes and no. Memcached is not a database, but an LRU (&#8220;least-recently-used&#8221;) cache with a fixed size. If there is not enough room, the oldest items will be removed. If we use it for session storage, some people might be logged out randomly. Duh. So, if you want to use Memcached, you have to weigh its <a href="http://artur.ejsmont.org/blog/content/php-session-in-mysql-vs-memcached">advantages and drawbacks</a>. It&#8217;s certainly not a good option if you have important sessions (like shopping carts) that you cannot afford to lose. On the other hand, if it&#8217;s OK to lose a session once in a while, Memcached might be a good solution for you. It&#8217;s very fast and easy to set up, and it is supported as a session handler by PHP out of the box. You can mitigate the risk by assigning enough RAM, and by adding a &#8220;remember me&#8221; feature (if it&#8217;s not a security concern, depending on the type of your site). If you use a custom session handler, you can even use Memcached purely as a caching front-end for a database session store and get the best of both worlds.</p>
<h2>How to set up Memcached as PHP session handler</h2>
<p>There are two ways to use Memcached as your session handler: if you have no special needs, you can simply set some PHP ini options and you&#8217;re done. This was good enough in my situation and I&#8217;ll describe this solution here. If you want to use advanced options, like using persistent connections or using a <a href="http://www.keboola.com/blog/php-sessions-with-memcached-and-a-database-session-in-the-cloud-done-right">combined Memcached/MySQL solution</a>, you will need to use a custom session handler (not described here).</p>
<h2>The easy way: set PHP ini options</h2>
<p>As PHP comes with support for Memcached as session storage baked in, you only need to set two options and you&#8217;re good to go. You can either set these in your php.ini file, or at run-time in your application.<br />
<code>; either put this in php.ini<br />
; replace or comment out the existing two options<br />
session.save_handler = memcached<br />
; change server:port to fit your needs<br />
session.save_path="127.0.0.1:11211"</code><br />
<code># or, include this in your application startup code<br />
ini_set('session.save_handler', 'memcached');<br />
ini_set('session.save_path', '127.0.0.1:11211');</code></p>
<p><strong>Note:</strong> There are a few gotchas here, and this is actually what made me write this post. Most other blog posts about this topic use PECL/Memcache, not PECL/Memcached. Both have a different API and different options. If you&#8217;re using PECL/Memcached (like me), make sure to include the &#8220;d&#8221; in the handler name (&#8220;memcached&#8221;). Also, the save path must NOT include the protocol (just server IP and port). You CAN specify a comma-separated list of servers, but you CANNOT specify options here, like you can with PECL/Memcache. If you need special options, you must use a custom session handler, as mentioned above.</p>
<p>That&#8217;s it, we&#8217;re done! Now go ahead, restart Apache, and test your shiny new Memcached sessions.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.michaelkrenz.de/2011/09/06/using-peclmemcached-to-store-sessions/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>How to set up the Memcached PHP client library on CentOS 5</title>
		<link>http://www.michaelkrenz.de/2011/09/06/how-to-set-up-the-memcached-php-client-library-on-centos-5/</link>
		<comments>http://www.michaelkrenz.de/2011/09/06/how-to-set-up-the-memcached-php-client-library-on-centos-5/#comments</comments>
		<pubDate>Tue, 06 Sep 2011 12:05:04 +0000</pubDate>
		<dc:creator>Michael Krenz</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.michaelkrenz.de/?p=129</guid>
		<description><![CDATA[As we are currently building community features for our game download deal discovery site Deals4Downloads.com, I started investigating Memcached as a caching and session storage option. There are already many blog posts out there about this, but as many of them are unclear or even misleading, and I stumbled into every gotcha out there along [...]]]></description>
			<content:encoded><![CDATA[<p>As we are currently building community features for our game download deal discovery site <a href="http://www.deals4downloads.com" title="Price Search and Deals for Game Downloads">Deals4Downloads.com</a>, I started investigating <strong>Memcached</strong> as a caching and session storage option. There are already many blog posts out there about this, but as many of them are unclear or even misleading, and I stumbled into every gotcha out there along the way, I thought I&#8217;d share some helpful tips here on how to get it all running. I&#8217;ll explain below what you&#8217;ll need to get Memcached along with PECL/Memcached (note the &#8220;d&#8221;) for your PHP site on CentOS 5.5. I&#8217;m not a pro sysadmin and I won&#8217;t go into every detail, but you&#8217;ll get the gist.</p>
<h2>Memcache, Memcached, what&#8217;s with the name?</h2>
<p>There are two parts to this equation: a server component and a PHP client component. You will need both. For the PHP client, there are two options, one of which even shares the name with the server component, which has caused a good deal of confusion.</p>
<h2>Installing and setting up the Memcached server</h2>
<p>You&#8217;ll need to install the Memcached server component first to be able to store and read values. Fortunately, this is the easy part: install package, configure and start server, add firewall rule to secure server, done. </p>
<h3>Installation</h3>
<p>Memcached is available as a ready-made package in my favorite repository, <a href="http://blog.famillecollet.com/">Remi</a>, so we can install it with:</p>
<p><code>yum --enablerepo=remi install memcached</code></p>
<p>This should hopefully proceed without any problems. If you don&#8217;t have the Remi repository, you should first add it to your system, or use the repo of your choice. </p>
<h3>Configuration</h3>
<p>Next we need to edit the server&#8217;s configuration, start it and add it to the system start configuration. As far as I see it, you have two options here: either use the provided start script from the RPM, or add your own. You can set several parameters, like the IP and port that the service runs on, the user, and the amount of memory assigned (keep in mind that this is a fixed value).<br />
<code># Option 1: edit and use the RPM start script<br />
  #adapt options here, like memory available<br />
  vi /etc/init.d/memcached<br />
  # start service<br />
  /etc/init.d/memcached start<br />
  # add to system boot config<br />
  chkconfig memcached on</code><br />
<code># Option 2: start server manually and add custom start command to /etc/rc.local<br />
  # start server as daemon<br />
  /usr/bin/memcached -d -m 1024 -u httpd -l 127.0.0.1<br />
  # next, add the above command to /etc/rc.local to make it run at boot-time</code></p>
<p>A word about the parameters shown above:<br />
<code>-d start as daemon<br />
-u user name for Memcached (adapt to your needs)<br />
-m amount of memory assigned, in MB<br />
-l (this is an L) IP address to listen on</code></p>
<h3>Making it more secure</h3>
<p>I&#8217;ll assume you will use your Memcache server only locally. It&#8217;s a good idea to add an IpTables rule to block all outside requests to this server. Add a line like this to your IpTables config (I won&#8217;t show this in detail here):<br />
<code>-A INPUT -p tcp --dport 11211 -j ACCEPT</code><br />
If you want to set up a dedicated Memcached server and access it from another server, you will have to change the above accordingly.</p>
<h3>Testing your Memcached server</h3>
<p>Let&#8217;s test our new server a bit. I&#8217;ll show you some tools with output from my test server below:<br />
<code># Is the service running?<br />
root@D4D-TEST01 ~: netstat -tap | grep memcached<br />
tcp  0  0 *:11211  *:*  LISTEN  29441/memcached<br />
tcp  0  0 *:11211  *:*  LISTEN  29441/memcached</code><br />
<code># see some stats with memcached-tool (installed along with RPM):<br />
root@D4D-TEST01 ~: memcached-tool 127.0.0.1:11211 stats<br />
#127.0.0.1:11211   Field       Value<br />
         accepting_conns           1<br />
               auth_cmds           0<br />
             auth_errors           0<br />
                   bytes        1867<br />
              bytes_read       81117<br />
           bytes_written       54550<br />
          [... etc]</code></p>
<p>Let&#8217;s connect with Telnet and set and get a value. You can set values with &#8220;set [keyname] [flag] [expirytime] [bytes]&#8221; and get values with &#8220;get <keyname>&#8220;. If you set a value, you specify the keyname and the options first, press Enter, and then specify the value on the next line. You can read more about these commands <a href="http://blog.elijaa.org/index.php?post/2010/05/21/Memcached-telnet-command-summary" title="Memcached telnet command summary">here</a> for example. </p>
<p><code>root@D4D-TEST01 ~: telnet localhost 11211<br />
Trying 127.0.0.1...<br />
Connected to localhost.<br />
Escape character is '^]'.<br />
set mykey 0 900 6<br />
mydata<br />
STORED<br />
get mykey<br />
VALUE mykey 0 6<br />
mydata<br />
END</code></p>
<p>This is a bit clumsy of course, and what we really want is to set values from PHP. Time to install the PHP client component.</p>
<h3>Again: Memcache, Memcached &#8211; what&#8217;s up?</h3>
<p>This is where the confusion starts: there are two PHP client libraries available (both in PECL): one is called &#8220;Memcache&#8221; (or PECL/Memcache) and one is called &#8220;Memcached&#8221; (or PECL/Memcached). Yep, the second one is named exactly like the server. For a comparison, see for example <a href="http://code.google.com/p/memcached/wiki/PHPClientComparison">here</a> and <a href="http://stackoverflow.com/questions/1442411/using-memcache-vs-memcached-with-php">here</a>. The short of it: PECL/Memcache is older, less actively developed, and more widely used. PECL/Memcached relies on the libmemcached library, is newer and has more features. Most blog posts you&#8217;ll find are about PECL/Memcache, and that can be a bit misleading if you want to start out with PECL/Memcached.<br />
After weighing my options, I decided to go with PECL/Memcached, and I&#8217;ll show you how to get it below.</p>
<h3>Installing PECL/Memcached</h3>
<p>If you just want the current stable version, get it from a suitable RPM. You will need libmemcached, too.</p>
<p><code>yum --enablerepo=remi install libmemcached<br />
yum --enablerepo=remi install php5-memcached</code></p>
<p>After reading about some bugs in that version, I decided to use the current beta though, so I had to get it from PECL, which proved to be a bit more challenging. To make a long story short, you will definitely need zlib and libmemcached first, and probably their development libs as well (plus PECL of course):<br />
<code>yum --enablerepo=remi install zlib zlib-devel<br />
yum --enablerepo=remi install libmemcached libmemcached-devel<br />
pecl install memcached-beta</code></p>
<p>That should do the trick. You might have to add<br />
<code>extension=memcached.so</code></p>
<p>to your php.ini, if it&#8217;s not there already. If you call up phpinfo() (after restarting Apache), it should look like this:<br />
<img src="http://www.michaelkrenz.de/wp-content/uploads/2011/09/memcached_phpinfo_output.png" alt="phpinfo output for PECL/Memcached" title="phpinfo output for PECL/Memcached" width="671" height="410" class="aligncenter size-full wp-image-151" style="margin: 5px 0"/></p>
<h3>Testing, again</h3>
<p>So let&#8217;s test our new client with a little PHP script:<br />
<code>&lt;?php<br />
$mc = new Memcached();<br />
$mc-&gt;addServer('localhost', 11211);<br />
$mc-&gt;set('testkey', 'Hello there');<br />
echo $mc-&gt;get('testkey');</code></p>
<p>Keep in mind that the APIs for Memcache and Memcached are very different, so most examples you see on the net won&#8217;t work for PECL/Memcached. The correct version of the documentation (as opposed to the one for Memcache) is <a href="http://www.php.net/manual/en/book.memcached.php">here</a>.<br />
If you want to use persistent connections, make sure that you only add a server when none is defined yet, lest you end up with hundreds of them:<br />
<code>if (!count($mc-&gt;getServerList()))<br />
  $mc-&gt;addServer("localhost", 11211);</code></p>
<p>That&#8217;s about it. You now have a working Memcached setup and can use it for your caching purposes.</p>
<p>You can also use Memcached to store your sessions, but that will be covered in <a href="http://www.michaelkrenz.de/2011/09/06/using-peclmemcached-to-store-sessions" title="Using PECL/Memcached to store sessions">my next post</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.michaelkrenz.de/2011/09/06/how-to-set-up-the-memcached-php-client-library-on-centos-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Remembering The (Good?) Old Times</title>
		<link>http://www.michaelkrenz.de/2010/05/02/remembering-the-good-old-times/</link>
		<comments>http://www.michaelkrenz.de/2010/05/02/remembering-the-good-old-times/#comments</comments>
		<pubDate>Sun, 02 May 2010 09:52:28 +0000</pubDate>
		<dc:creator>Michael Krenz</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[art]]></category>
		<category><![CDATA[berlin]]></category>
		<category><![CDATA[photography]]></category>

		<guid isPermaLink="false">http://www.michaelkrenz.de/?p=119</guid>
		<description><![CDATA[I just discovered io9.com, part of the Gawker family of blogs, which has a post about the now defunct amusement park &#8220;Plänterwald&#8221;, later called Spreepark: Berlin&#8217;s Abandoned Spreepark Is Where Fun Goes To Die. They have some awesome photos up which have a slightly surrealistic feel. I remember how I went there as a kid [...]]]></description>
			<content:encoded><![CDATA[<p>I just discovered <a href="http://www.io9.com">io9.com</a>, part of the Gawker family of blogs, which has a post about the now defunct amusement park &#8220;Plänterwald&#8221;, later called Spreepark: <a href="http://io9.com/5528826/berlins-abandoned-spreepark-is-where-fun-goes-to-die/">Berlin&#8217;s Abandoned Spreepark Is Where Fun Goes To Die</a>. They have some awesome photos up which have a slightly surrealistic feel.<br />
I remember how I went there as a kid and went up in that huge Ferris Wheel. You could see Moabit from up there, part of West Berlin. I found that soo exciting, because West Berlin was like some mysterious and forbidding wonderland for me. </p>
<p>The video below makes me feel a little nostalgic&#8230; </p>
<p><object width="400" height="300"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=10791541&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=10791541&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"></embed></object>
<p><a href="http://vimeo.com/10791541">spreepark berlin rewinded</a> from <a href="http://vimeo.com/user2550026">kriz mental</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.michaelkrenz.de/2010/05/02/remembering-the-good-old-times/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Optimized Error Logging With Zend Framework</title>
		<link>http://www.michaelkrenz.de/2009/05/23/optimized-error-logging-with-zend-framework/</link>
		<comments>http://www.michaelkrenz.de/2009/05/23/optimized-error-logging-with-zend-framework/#comments</comments>
		<pubDate>Sat, 23 May 2009 15:33:03 +0000</pubDate>
		<dc:creator>Michael Krenz</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://www.michaelkrenz.de/?p=79</guid>
		<description><![CDATA[If you have a large code base, it&#8217;s a good idea to log any errors that might occur. It helps you to become aware of errors and to track them down. If you&#8217;re not careful though, those logs and messages can quickly overwhelm you, so it&#8217;s wise to develop a logging strategy. I&#8217;d like to [...]]]></description>
			<content:encoded><![CDATA[<p>If you have a large code base, it&#8217;s a good idea to log any errors that might occur. It helps you to become aware of errors and to track them down. If you&#8217;re not careful though, those logs and messages can quickly overwhelm you, so it&#8217;s wise to develop a logging strategy. </p>
<p>I&#8217;d like to share a few tips here on how to optimize your error logging when using Zend Framework (&#8220;ZF&#8221;), one of the most established PHP frameworks available. I assume that you already know to use this framework. .</p>
<h2>Basic Strategies &#8211; Filtering And Fingerprinting</h2>
<p>When we released the <a href="http://www.community.e-fellows.net">e-fellows.net Community</a> (a closed social network for holders of the <a href="http://www.e-fellows.net/show/detail.php/9425">e-fellows.net scholarship</a>), logging was a straight-forward affair: all errors were logged to a file. It quickly became apparent that this was not good enough: often, critical errors went undetected for days, because nobody bothered to look into the logs regularly.</p>
<p>So we implemented a priority-based filtering strategy: errors and log messages up to a certain log priority are logged into various files, as before. Additionally, more important errors are sent out via email to a workflow folder that is checked regularly. The most critical errors are emailed directly to all members of technical staff.</p>
<p>All was fine for a while until we realized that sometimes, for example after a release, the same error occurs repeatedly on every page, leading to thousands of emails that flood your inbox within minutes. That&#8217;s why we came up with the idea of assigning each log message a unique fingerprint which is stored in the database. Each time a message is to be logged, its fingerprint is first checked in the database. If it has already been logged within the last, say, 24 hours, it is discarded.</p>
<p>The last step was to setup log-rotating on the server, i.e. older logs are automatically archived and then deleted after a certain time (but that&#8217;s beyond the scope of this article).</p>
<p>Next I&#8217;m going to show you how to setup log filtering with the Zend Framework. Message fingerprinting<br />
will be covered later in the article.</p>
<h2>Log Setup</h2>
<p>First, we define a few logs and a simple log-format:<br />
<code>//config.php<br />
$loggers = array('framework','database','import','admin','login','minifeed',<br />
                 'signoff','notification','cron','newsletter','mail','upload',<br />
                 'application','pdf');<br />
Zend_Registry::set('loggers', $loggers);<br />
$logFormat = date('r') . ', "%message%" (%priorityName%)' . PHP_EOL;<br />
$simpleFormatter = new Zend_Log_Formatter_Simple($logFormat);</code></p>
<p>Next, for each log, we define a file-based log writer that writes all messages above a certain priority to a specified file. Messages with a lower priority (i.e. debug messages) are discarded. If we really want to see those debug messages (like for, uhm, debugging), we just change the corresponding config setting. Message priorities are actually arbitrary (though you have to choose one of the pre-determined values). It&#8217;s up to you to define what priority an error should have and what that means to you. </p>
<p><code>foreach ($loggers as $aLogger) {<br />
    $loglevel = $config-&gt;log-&gt;level;<br />
    $class = new ReflectionClass('Zend_Log');<br />
    $priorities = array_flip($class-&gt;getConstants());<br />
    $loglevel = array_search($loglevel, $priorities);<br />
    $fileFilter = new Zend_Log_Filter_Priority($loglevel, '&lt;=');<br />
    $fileWriter = new Zend_Log_Writer_Stream(APP_LOG_PATH . '/' . $aLogger . '.log');<br />
    $fileWriter-&gt;setFormatter($simpleFormatter);<br />
    $fileWriter-&gt;addFilter($fileFilter);</code></p>
<p>(Note: In the code above, we first determine all available log levels via reflection. Then we define that all messages with a priority <strong>below</strong> a certain threshold get logged (all others will be discarded). That&#8217;s because in the Zend Framework (like with UNIX system logs), a more severe error is mapped to a priority with a <strong>lower</strong> numeric value. In this article, I describe things the other way round because I find it more intuitive that way.)</p>
<p>Next, we set up a log writer that emails log messages with priority &#8220;ERR&#8221; or higher. It includes another threshold for sending critical messages to another mail address, but we&#8217;ll come to that later.<br />
<code>    $mailWriter = new Default_Helpers_EmailLogWriter();<br />
    $mailFilter = new Zend_Log_Filter_Priority(Zend_Log::ERR);<br />
    $mailWriter-&gt;addFilter($mailFilter);<br />
    $mailWriter-&gt;setFormatter($simpleFormatter);</code></p>
<p>Lastly, we instantiate a logger object, attach the two writers to it and save it in a registry for easier access:<br />
<code>    $logger = new Zend_Log();<br />
    $logger-&gt;addWriter($fileWriter);<br />
    $logger-&gt;addWriter($mailWriter);<br />
    Zend_Registry::set('log' . ucfirst($aLogger), $logger);<br />
}</code></p>
<h2>Log Usage</h2>
<p>Logging an error is straight-forward and done the standard Zend Framework way. In client code, errors are logged like this:<br />
<code>Zend_Registry::get('logDatabase')-&gt;err(__METHOD__ . ' - error getting proper<br />
                                         sysid from oracle');</code><br />
The developer doesn&#8217;t need to know how log messages are handled internally. We just get a log from the registry and write an entry with a certain priority. (For exceptions, we use another method which includes a stack trace.)</p>
<p>This would result in a log message like the following, which contains information about the date, method name and the actual message:<br />
<code>Fri, 22 May 2009 14:19:57 +0200, Default_Helpers_Database::getNextSysId() -<br />
"error getting proper sysid from oracle" (ERR)</code></p>
<p>Based on its high priority, this message would get logged to file and be sent out via email, too.</p>
<h2>Logging to email</h2>
<p>In the code above, you may have noticed a reference to the class Default_Helpers_EmailLogWriter, which extends the abstract log writer base class provided by ZF and implements the _write() method:<br />
<code>class Default_Helpers_EmailLogWriter extends Zend_Log_Writer_Abstract<br />
{<br />
  protected function _write($event)<br />
  {<br />
    $errorHandler = new Default_Models_ErrorHash();<br />
    if (false === $errorHandler-&gt;isErrorAlreadyLogged($event['message'])) {<br />
      $mail = new Default_Helpers_Mail();<br />
      $msg = $this-&gt;_formatter-&gt;format($event);<br />
      if ($event['priority'] &lt; Zend_Log::ERR) {<br />
        $mail-&gt;sendCriticalError("System Message: A Critical Error Ocurred!", $msg);<br />
      } else {<br />
        $mail-&gt;sendToAdmin("System Message: An Error Ocurred!", $msg);<br />
      }<br />
    }<br />
  }<br />
}</code></p>
<p>The first two lines of the _write method check whether the method was logged before (see below). If not, we instantiate a mail helper and send the log message via email. Remember, messages only get this far if their priority is at least &#8220;ERR&#8221;. If the error is even more critical, it is not sent to the standard address, but directly to the admin team&#8217;s inboxes, to make sure it gets handled promptly.</p>
<h2>Logging Messages Only Once A Day</h2>
<p>In order to avoid sending the same email repeatedly, we create an md5 hash for each message and store this hash value, or &#8220;fingerprint&#8221;, in the database (remember that the message contains additional info like the method the error occurred in). If this message was already logged within the last 24 hours (or any other interval we have configured), we discard it. This is determined with the help of the Default_Models_ErrorHash class:</p>
<p><code>class Default_Models_ErrorHash extends Default_Models_Database<br />
{<br />
  protected $_name = 'Errorhash';<br />
  protected $_primary = 'errorhash';</code></p>
<p>This class only contains one method which checks whether an error is already &#8220;known&#8221;. First we delete all hashes that are older than the configured interval. Then we look up the message&#8217;s fingerprint in the database. If it is found in the database (i.e. it was already logged within the last 24 hours), we simply return true. Otherwise, the hash will be inserted into the database.<br />
<code>  public function isErrorAlreadyLogged($errorMsg)<br />
  {<br />
    $db = $this-&gt;getAdapter();<br />
    $where = $db-&gt;quoteInto('created &lt;= DATE_SUB(NOW(), INTERVAL ? HOUR)',<br />
      Zend_Registry::get('config')-&gt;log-&gt;resendErrorMailAfter);<br />
    $db-&gt;delete($this-&gt;_name, $where);<br />
    if (false === empty($errorMsg)) {<br />
      $md5 = md5($errorMsg);<br />
      $query = 'SELECT COUNT(*) FROM '.$this-&gt;_name.' WHERE errorhash=?';<br />
      if($db-&gt;fetchOne($query, $md5)) {<br />
        return true;<br />
      } else {<br />
        $db-&gt;insert($this-&gt;_name, array('errorhash' =&gt; $md5));<br />
      }<br />
    }<br />
    return false;<br />
  }<br />
}</code></p>
<p>The Errorhash table looks like this:<br />
<code>CREATE TABLE `Errorhash` (<br />
`errorhash` char(32) collate utf8_unicode_ci NOT NULL,<br />
`created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,<br />
PRIMARY KEY  (`errorhash`)<br />
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;</code></p>
<h2>Wrap-up</h2>
<p>There you have it: I have shown you how to filter log messages with the Zend framework based on their priority, and how to avoid getting flooded with log emails. Both strategies help to make much better sense of your error logs.</p>
<p>Have you found other ways to optimize your error logs? If so, please share them below.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.michaelkrenz.de/2009/05/23/optimized-error-logging-with-zend-framework/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Firefox 3 with Mozilla Weave &#8211; and on my own server, too</title>
		<link>http://www.michaelkrenz.de/2008/07/20/firefox-3-with-mozilla-weave-and-on-my-own-server-too/</link>
		<comments>http://www.michaelkrenz.de/2008/07/20/firefox-3-with-mozilla-weave-and-on-my-own-server-too/#comments</comments>
		<pubDate>Sun, 20 Jul 2008 19:14:10 +0000</pubDate>
		<dc:creator>Michael Krenz</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">/?p=55</guid>
		<description><![CDATA[Today I finally upgraded to Firefox 3. The speed difference is incredible. I also hope that FF2&#8242;s atrocious memory leak problems are indeed a thing of the past. What held me back so long was the missing support for Google Browser Sync, which I&#8217;ve come to rely upon heavily, because it ensures a smooth transition [...]]]></description>
			<content:encoded><![CDATA[<p><img alt="Weave Logo" src="/wp-content/uploads/2009/02/icon-weave-m.gif" class="left" height="100" width="100" />Today I finally upgraded to Firefox 3. The speed difference is incredible. I also hope that FF2&#8242;s atrocious memory leak problems are indeed a thing of the past.</p>
<p>What held me back so long was the missing support for Google Browser Sync, which I&#8217;ve come to rely upon heavily, because it ensures a smooth transition between my various computers. Fortunately, something similar is emerging for FF3: <a href="http://labs.mozilla.com/projects/weave/">Mozilla Weave</a>. It&#8217;s still in early alpha and very buggy, but it looks promising.</p>
<p>I had signed up a few days ago, but I had forgotten my encryption passphrase, but fortunately I was able to delete my Weave profile data with the help of <a title="How to reset your Mozilla weave account" href="http://blog.randompage.org/2008/07/howto-reset-your-mozilla-weave.html">this tip from Lars Tackmann</a>.</p>
<p>There was still the problem that the Mozilla Weave server is very slow and often overloaded. Then I learned that you can host the service elsewhere. Good thing that I just got my own server from <a title="Slicehost Xen hosting" href="http://www.slicehost.com">slicehost.com</a>!</p>
<p>Using <a href="http://remcobressers.nl/2008/07/create-your-own-mozilla-weave-server/">Remco Bressers tutorial</a>, I had a Weave account running on my own server in no time, and it performs much better, too.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.michaelkrenz.de/2008/07/20/firefox-3-with-mozilla-weave-and-on-my-own-server-too/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Another swede, please</title>
		<link>http://www.michaelkrenz.de/2007/07/13/another-swede-please/</link>
		<comments>http://www.michaelkrenz.de/2007/07/13/another-swede-please/#comments</comments>
		<pubDate>Fri, 13 Jul 2007 19:56:47 +0000</pubDate>
		<dc:creator>Michael Krenz</dc:creator>
				<category><![CDATA[Current Favorites]]></category>
		<category><![CDATA[Music]]></category>
		<category><![CDATA[ScandiPop]]></category>

		<guid isPermaLink="false">/2007/07/13/another-swede-please/</guid>
		<description><![CDATA[As I&#8217;m heavily into Swedish music, I&#8217;ve taken to getting musical inspiration from the excellent swedesplease blog lately. One cool discovery was the friendlynoise label sporting great bands like Testbild! and Differnet. Another one is Winter Took His Life, who is Susanna Brandin from, need I mention it, Gothenburg. Her music is beautiful acoustic stuff [...]]]></description>
			<content:encoded><![CDATA[<p><img class="left" src="/wp-content/uploads/2007/07/stanna.thumbnail.jpg" />As I&#8217;m heavily into Swedish music, I&#8217;ve taken to getting musical inspiration from the excellent <a href="http://swedesplease.blogspot.com/">swedesplease</a> blog lately. One cool discovery was the <a href="http://www.friendlynoise.se">friendlynoise</a> label sporting great bands like Testbild! and Differnet.<br />
Another one is <a href="http://www.myspace.com/wintertookhislife">Winter Took His Life</a>, who is Susanna Brandin from, need I mention it, Gothenburg. Her music is beautiful acoustic stuff in the vein of <a href="http://www.bicrunga.com/">Bic Runga</a> or <a href="http://www.bobbybaby.net/">Bobby Baby</a>. I never tire of beautiful female voices.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.michaelkrenz.de/2007/07/13/another-swede-please/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Presentation on the use of XML in the L10N process</title>
		<link>http://www.michaelkrenz.de/2006/12/20/presentation-on-the-use-of-xml-in-the-l10n-process/</link>
		<comments>http://www.michaelkrenz.de/2006/12/20/presentation-on-the-use-of-xml-in-the-l10n-process/#comments</comments>
		<pubDate>Wed, 20 Dec 2006 11:45:04 +0000</pubDate>
		<dc:creator>Michael Krenz</dc:creator>
				<category><![CDATA[Translation]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">/2006/12/20/presentation-on-the-use-of-xml-in-the-l10n-process/</guid>
		<description><![CDATA[On Jan 10th, 2007, I&#8217;ll be giving a presentation at Humboldt-Universität Berlin on the use of XML in I18N and L10N. The seminar is open for everyone. I&#8217;ll cover questions like these: Background and characteristics of XML Reasons for using XML in the software translation industry XML as a family of technologies (XSL etc.) XML [...]]]></description>
			<content:encoded><![CDATA[<p>On Jan 10th, 2007, I&#8217;ll be giving a presentation at Humboldt-Universität Berlin on the use of XML in I18N and L10N. The seminar is open for everyone.</p>
<p>I&#8217;ll cover questions like these:</p>
<ul>
<li>Background and characteristics of XML</li>
<li>Reasons for using XML in the software translation industry</li>
<li>XML as a family of technologies (XSL etc.)</li>
<li>XML standards for the L10N industry (XLIFF, TMX etc.)</li>
<li>Tool support (especially TRADOS 7)</li>
</ul>
<p>In the next issue of &#8220;MDÜ&#8221; (the quarterly magazine of the German translators industry association BDÜ), I&#8217;ll publish an article on the same subject.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.michaelkrenz.de/2006/12/20/presentation-on-the-use-of-xml-in-the-l10n-process/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New Compilation: Folding Space</title>
		<link>http://www.michaelkrenz.de/2006/11/15/new-compilation-folding-space/</link>
		<comments>http://www.michaelkrenz.de/2006/11/15/new-compilation-folding-space/#comments</comments>
		<pubDate>Wed, 15 Nov 2006 13:35:11 +0000</pubDate>
		<dc:creator>Michael Krenz</dc:creator>
				<category><![CDATA[Current Favorites]]></category>
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">/2006/11/15/new-compilation-folding-space/</guid>
		<description><![CDATA[I&#8217;ve just finished Folding Space, a Minimal House compilation. More info in my last.fm journal.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just finished <em>Folding Space</em>, a Minimal House compilation. More info in <a href="http://www.last.fm/user/Paus/journal/2006/11/13/266755/">my last.fm journal</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.michaelkrenz.de/2006/11/15/new-compilation-folding-space/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New client site under development: lovelite.de</title>
		<link>http://www.michaelkrenz.de/2006/11/03/new-client-site-under-development-lovelitede/</link>
		<comments>http://www.michaelkrenz.de/2006/11/03/new-client-site-under-development-lovelitede/#comments</comments>
		<pubDate>Fri, 03 Nov 2006 13:01:30 +0000</pubDate>
		<dc:creator>Michael Krenz</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">/2007/03/03/new-client-site-under-development-lovelitede/</guid>
		<description><![CDATA[For the past few weeks, I&#8217;ve been working on a new client site for the Lovelite, a unique 60&#8242;ies soul/funk club in east Berlin. I&#8217;ve been friends with these guys for years, so when they asked me to rebuild their site, it was a perfect fit. Their old site had several severe problems. Due to [...]]]></description>
			<content:encoded><![CDATA[<p>For the past few weeks, I&#8217;ve been working on a new client site for the <a href="http://www.lovelite.de">Lovelite</a>, a unique 60&#8242;ies soul/funk club in east Berlin. I&#8217;ve been friends with these guys for years, so when they asked me to rebuild their site, it was a perfect fit.</p>
<p>Their old site had several severe problems. Due to a few poor design choices, it was hard for users to navigate. Even worse, the site was Flash based and could only be updated if you knew your way in Flash. If you are a non-technical club owner and need to publish events regularly, this can become a huge hindrance indeed. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.michaelkrenz.de/2006/11/03/new-client-site-under-development-lovelitede/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lo-Fi-Fnk Fun</title>
		<link>http://www.michaelkrenz.de/2006/09/12/lo-fi-fnk-fun/</link>
		<comments>http://www.michaelkrenz.de/2006/09/12/lo-fi-fnk-fun/#comments</comments>
		<pubDate>Tue, 12 Sep 2006 10:50:06 +0000</pubDate>
		<dc:creator>Michael Krenz</dc:creator>
				<category><![CDATA[ScandiPop]]></category>

		<guid isPermaLink="false">/2006/09/12/lo-fi-fnk-fun/</guid>
		<description><![CDATA[Every once in a while, a band comes along that makes music fun again. Right now, Lo-Fi-Fnk, from (you guessed it) Sweden, do just that for me. Their slightly trashy electropop is really refreshing and puts a smile on my face. (See their myspace page.) If you like them, check out those other cool Swedes, [...]]]></description>
			<content:encoded><![CDATA[<div style="overflow:auto">
<img id="image40" src="/wp-content/uploads/2006/09/431448045_m.jpg" alt="Lo-Fi-Fnk doin' it live" class="left"/><br />
Every once in a while, a band comes along that makes music fun again. Right now, Lo-Fi-Fnk, from (you guessed it) Sweden, do just that for me. Their slightly trashy electropop is really refreshing and puts a smile on my face. (See their <a href="http://www.myspace.com/lofifnksweden">myspace</a> page.)<br />
If you like them, check out those other cool Swedes, <a href="http://www.myspace.com/toughalliance">The Tough Alliance</a> (also featured on <a href="/2006/04/17/my-faves-for-october-2005-april-2006/">my last compilation</a>)!
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.michaelkrenz.de/2006/09/12/lo-fi-fnk-fun/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

