<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DEAGSHgzeCp7ImA9WhVWFkg.&quot;"><id>tag:blogger.com,1999:blog-5349471866547418688</id><updated>2012-04-29T00:45:29.680+01:00</updated><category term="apache" /><category term="communique" /><category term="day" /><category term="performance" /><category term="cq" /><category term="components" /><category term="templates components" /><category term="caching" /><category term="analytics" /><category term="cq qrcode programming java osgi googlecharts sling apache day cq5 mobile" /><category term="google" /><category term="logging log4j grep unix log file" /><title>CQStuff</title><subtitle type="html">Somewhere to squirrel my Day CQ Experiences</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.diffa.co.uk/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.diffa.co.uk/" /><author><name>Chris Pilsworth</name><uri>http://www.blogger.com/profile/03221639608396248493</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/Cqstuff" /><feedburner:info uri="cqstuff" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DEAGSHgzfCp7ImA9WhVWFkg.&quot;"><id>tag:blogger.com,1999:blog-5349471866547418688.post-696163435077190977</id><published>2012-04-29T00:45:00.001+01:00</published><updated>2012-04-29T00:45:29.684+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-29T00:45:29.684+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="logging log4j grep unix log file" /><title>Filtering Log4j logs for ERRORs with Stacktraces using grep</title><content type="html">I have recently been looking for ways to improve the way we collect information from the logs. &amp;nbsp;We had a process in support where logs produced through log4j would be grep'd for ERROR messages using something like&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;grep 'ERROR' application.log&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This is OK, but it strips any stack trace information present directly below the ERROR log entry and the stack trace will often give you the information you need to go directly to the source of the problem.&lt;br /&gt;
&lt;br /&gt;
After reading the &lt;a href="http://dropwizard.codahale.com/manual/core/#logging"&gt;logging documentation &lt;/a&gt;from the excellent &lt;a href="http://dropwizard.codahale.com/"&gt;dropwizard&lt;/a&gt;&amp;nbsp;framework, I was inspired to take a slightly different approach. &amp;nbsp;Dropwizard uses &lt;a href="http://logback.qos.ch/"&gt;Logback&lt;/a&gt;&amp;nbsp;and has some special handling for outputting stack traces that prefixes the lines with the exclamation mark character. &amp;nbsp;As far as I know this is not possible using Log4j, but it is possible to match on the default formatting for stack trace information.&lt;br /&gt;
&lt;br /&gt;
By default a log4j log file will look &lt;i&gt;something like&lt;/i&gt; this&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;0 &amp;nbsp; &amp;nbsp;[main] INFO &amp;nbsp;ExceptionThrower &amp;nbsp;- making progress&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;1 &amp;nbsp; &amp;nbsp;[main] INFO &amp;nbsp;ExceptionThrower &amp;nbsp;- making progress&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;2 &amp;nbsp; &amp;nbsp;[main] INFO &amp;nbsp;ExceptionThrower &amp;nbsp;- making progress&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;2 &amp;nbsp; &amp;nbsp;[main] ERROR ExceptionThrower &amp;nbsp;- Something went wrong&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;java.lang.Exception: Wrapped the exception&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at ExceptionThrower.main(ExceptionThrower.java:21)&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Caused by: java.lang.NullPointerException: Something was null&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;at ExceptionThrower.main(ExceptionThrower.java:18)&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;... 5 more&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;5 &amp;nbsp; &amp;nbsp;[main] INFO &amp;nbsp;ExceptionThrower &amp;nbsp;- making progress&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;5 &amp;nbsp; &amp;nbsp;[main] INFO &amp;nbsp;ExceptionThrower &amp;nbsp;- making progress&lt;/span&gt;&lt;br /&gt;
&lt;div style="font-size: small;"&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
Notice that all of the stack trace lines are prefixed with some whitespace then the word "at". &amp;nbsp;Grepping on the "at" will only give us the stack and not the error message. &amp;nbsp;But if we use the --before-context parameter to grep then we can pull in the log error message and the details of the exception:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;grep -i '^[[:space:]]*at' --before-context=2 application.log&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Using this command will give us just the ERROR message, the subsequent stack trace and the stack trace of the causal exception:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;2 &amp;nbsp; &amp;nbsp;[main] ERROR ExceptionThrower &amp;nbsp;- Something went wrong&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;java.lang.Exception: Wrapped the exception&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; at ExceptionThrower.main(ExceptionThrower.java:21)&lt;/span&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Caused by: java.lang.NullPointerException: Something was null&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; at ExceptionThrower.main(ExceptionThrower.java:18)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Any other log statements we are not interested in at this time are omitted.&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Cqstuff/~4/D6Ywus9-gM8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.diffa.co.uk/feeds/696163435077190977/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.diffa.co.uk/2012/04/filtering-log4j-logs-for-errors-with.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5349471866547418688/posts/default/696163435077190977?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5349471866547418688/posts/default/696163435077190977?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Cqstuff/~3/D6Ywus9-gM8/filtering-log4j-logs-for-errors-with.html" title="Filtering Log4j logs for ERRORs with Stacktraces using grep" /><author><name>Chris Pilsworth</name><uri>http://www.blogger.com/profile/03221639608396248493</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.diffa.co.uk/2012/04/filtering-log4j-logs-for-errors-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YNQnk5eCp7ImA9WxFSFkU.&quot;"><id>tag:blogger.com,1999:blog-5349471866547418688.post-5069353003824968339</id><published>2010-04-19T14:47:00.002+01:00</published><updated>2010-04-19T14:53:13.720+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-19T14:53:13.720+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="cq qrcode programming java osgi googlecharts sling apache day cq5 mobile" /><title>Creating QR Codes for Apache Sling URLs</title><content type="html">Matt Cutts &lt;a href="http://twitter.com/mattcutts/status/11780579336"&gt;mentioned recently&lt;/a&gt; that the goo.gl URL shortening service had a trick where if a ".qr" extension is added to the shortened URL then a &lt;a href="http://en.wikipedia.org/wiki/QRcode"&gt;QR Code&lt;/a&gt; image is generated for that URL. &lt;br /&gt;
&lt;br /&gt;
After a quick look at the &lt;a href="http://sling.apache.org/site/servlets.html"&gt;Apache Sling documentation&lt;/a&gt; it seemed that adding such a feature to Sling/ Day CQ would be pretty easy, especially as goo.gl uses the &lt;a href="http://code.google.com/apis/chart/docs/gallery/qr_codes.html"&gt;Google Chart API&lt;/a&gt; to create the images.&lt;br /&gt;
&lt;br /&gt;
To deal with requests within Sling based on the url extension, a Servlet Service must be added via an OSGi bundle and use service reference properties to detail which extensions/paths/selectors/methods/prefix are handled by this servlet. &amp;nbsp;Thanks to the maven-bundle-plugin and maven-scr-plugins, packaging this bundle for deployment using Maven is a piece of cake.&lt;br /&gt;
&lt;br /&gt;
The Servlet is quite simple.  Here are the SCR annotations from the Servlet class javadoc that tell the Sling what type of requests this Servlet will service:&lt;br /&gt;
&lt;pre&gt;/**
 * @scr.service interface="javax.servlet.Servlet"
 * @scr.property name="sling.servlet.resourceTypes"
 *               value="sling/servlet/default"
 *
 * @scr.property name="sling.servlet.extensions" value = "qr"
 */
&lt;/pre&gt;&lt;br /&gt;
and here are the couple of lines that create the redirect URL for the QR Code image and send that in the response.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;private static final String baseUrl = "http://chart.apis.google.com/chart?cht=qr&amp;amp;chs=150x150&amp;amp;choe=UTF-8&amp;amp;chld=H&amp;amp;chl=";
 
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ... { 
 resp.sendRedirect(baseUrl + removeQRExtension(req));
} 

protected String removeQRExtension(HttpServletRequest req) {
 StringBuffer url = req.getRequestURL();
 return url.substring(0, url.length() -3);  
} 
&lt;/pre&gt;&lt;a href="http://chart.apis.google.com/chart?cht=qr&amp;amp;chs=150x150&amp;amp;choe=UTF-8&amp;amp;chld=H&amp;amp;chl=http://localhost:4502/libs/cq/core/content/welcome.html" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://chart.apis.google.com/chart?cht=qr&amp;amp;chs=150x150&amp;amp;choe=UTF-8&amp;amp;chld=H&amp;amp;chl=http://localhost:4502/libs/cq/core/content/welcome.html" /&gt;&lt;/a&gt;&lt;br /&gt;
Once the OSGi bundle is installed, you can add the .qr extension to any url on your Sling/CQ5 server and get back a QR code for that URL. For example the CQ5 URL&lt;br /&gt;
&lt;a href="http://localhost:4502/libs/cq/core/content/welcome.html.qr"&gt;http://localhost:4502/libs/cq/core/content/welcome.html.qr&lt;/a&gt;&lt;br /&gt;
will give you this QR Code.&lt;br /&gt;
&lt;br /&gt;
Although QR codes not yet made it mainstream, they provide a great way for mobile users to grab information quickly and there seem to be plenty of QR code readers out there. &amp;nbsp;I have been using &lt;a href="http://www.quickmark.com.tw/default.asp"&gt;QuickMark&lt;/a&gt;&amp;nbsp;on the iPhone and that works great for me.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;The full code can be found here&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;a href="http://github.com/cpilsworth/urlqrcode"&gt;http://github.com/cpilsworth/urlqrcode&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;and the compiled OSGi bundle can be found here&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;a href="http://github.com/downloads/cpilsworth/urlqrcode/qrcodes-0.0.2-SNAPSHOT.jar"&gt;http://github.com/downloads/cpilsworth/urlqrcode/qrcodes-0.0.2-SNAPSHOT.jar&lt;/a&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Cqstuff/~4/TNlHtVKo_zI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.diffa.co.uk/feeds/5069353003824968339/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.diffa.co.uk/2010/04/creating-qr-codes-for-apache-sling-urls.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5349471866547418688/posts/default/5069353003824968339?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5349471866547418688/posts/default/5069353003824968339?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Cqstuff/~3/TNlHtVKo_zI/creating-qr-codes-for-apache-sling-urls.html" title="Creating QR Codes for Apache Sling URLs" /><author><name>Chris Pilsworth</name><uri>http://www.blogger.com/profile/03221639608396248493</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.diffa.co.uk/2010/04/creating-qr-codes-for-apache-sling-urls.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0QFRHw8eyp7ImA9WxNaF0g.&quot;"><id>tag:blogger.com,1999:blog-5349471866547418688.post-4028566680570606388</id><published>2009-12-02T10:50:00.003Z</published><updated>2009-12-02T10:55:15.273Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-02T10:55:15.273Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="communique" /><category scheme="http://www.blogger.com/atom/ns#" term="cq" /><category scheme="http://www.blogger.com/atom/ns#" term="templates components" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><category scheme="http://www.blogger.com/atom/ns#" term="day" /><category scheme="http://www.blogger.com/atom/ns#" term="analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="components" /><title>New Google Analytics Tracking Code for CQ 5.x</title><content type="html">Today's &lt;a href="http://googlecode.blogspot.com/2009/12/google-analytics-launches-asynchronous.html"&gt;announcement from Google Analytics&lt;/a&gt; that they are providing an alternative page tracking snippet to make tracking asynchronous looks good. &amp;nbsp;Steve Souders provides a &lt;a href="http://www.stevesouders.com/blog/2009/12/01/google-analytics-goes-async/"&gt;good write up of the benefits&lt;/a&gt; of their revised approach. &lt;br /&gt;
&lt;br /&gt;
Fortunately, its very easy to upgrade any Day CQ5.x sites that use the previous incarnation of the Google tracking code from &amp;nbsp;base page component. &lt;br /&gt;
&lt;br /&gt;
There are 3 steps to updating &amp;nbsp;the existing Google analytics implementation to an asynchronous one&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Overlay the analytics.google.jsp in /apps/foundation/components/page/ with&amp;nbsp;an &lt;a href="http://gist.github.com/247092#file_analytics.google.jsp"&gt;async version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Create a &lt;a href="http://gist.github.com/247115#file_analytics.google.queue.jsp"&gt;script block&lt;/a&gt; to queue Google Analytics commands (trackPageView)&lt;/li&gt;
&lt;li&gt;Add that script block to the  section of the base template by &lt;a href="http://gist.github.com/247101#file_head.jsp"&gt;overriding head.jsp&lt;/a&gt; in the overlayed component&lt;/li&gt;
&lt;/ol&gt;More simply; that is the following 3 files added to the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;/apps/foundation/components/page/ &lt;/span&gt;folder on your CQ instance:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://gist.github.com/247092#file_analytics.google.jsp"&gt;google.analytics.jsp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://gist.github.com/247115#file_analytics.google.queue.jsp"&gt;google.analytics.queue.jsp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://gist.github.com/247101#file_head.jsp"&gt;head.jsp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;This will override the one built into CQ. &amp;nbsp;If you find that it is not working out for you, then remove these files and you will go back to the original tracking code (make sure you flush any caches here too).&lt;br /&gt;
&lt;br /&gt;
You could always add as an alternative provider for analytics by setting it up as&lt;br /&gt;
&lt;span style="font-family: tahoma, verdana, Arial, sans-serif; font-size: 11px; white-space: pre;"&gt;/libs/foundation/components/page/dialog/items/items/analytics/items/provider/options/google-async&lt;/span&gt;&lt;br /&gt;
and renaming the files accordingly. &amp;nbsp;It probably wouldn't hurt to use the provider selection logic in the queue jsp also. &amp;nbsp;However, it is great to see how easy it is to override out of the box CQ functionality.&lt;img src="http://feeds.feedburner.com/~r/Cqstuff/~4/dlF7zqbemIU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.diffa.co.uk/feeds/4028566680570606388/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.diffa.co.uk/2009/12/new-google-analytics-tracking-code-for.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5349471866547418688/posts/default/4028566680570606388?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5349471866547418688/posts/default/4028566680570606388?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Cqstuff/~3/dlF7zqbemIU/new-google-analytics-tracking-code-for.html" title="New Google Analytics Tracking Code for CQ 5.x" /><author><name>Chris Pilsworth</name><uri>http://www.blogger.com/profile/03221639608396248493</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.diffa.co.uk/2009/12/new-google-analytics-tracking-code-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UERHYyeSp7ImA9WxNaF0g.&quot;"><id>tag:blogger.com,1999:blog-5349471866547418688.post-7388697377351529811</id><published>2009-11-17T17:40:00.006Z</published><updated>2009-12-02T10:53:25.891Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-02T10:53:25.891Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="performance" /><category scheme="http://www.blogger.com/atom/ns#" term="communique" /><category scheme="http://www.blogger.com/atom/ns#" term="caching" /><category scheme="http://www.blogger.com/atom/ns#" term="cq" /><category scheme="http://www.blogger.com/atom/ns#" term="day" /><category scheme="http://www.blogger.com/atom/ns#" term="apache" /><title>Improving Day CQ Performance Using Caching</title><content type="html">Recently, we looked at how best to improve performance on one of our CQ4 extranet sites and found that although the page content was being served very fast, a lot of time was being spent by the client downloading various associated resources for that page.&amp;nbsp; In fact for every page, there were about 40 &lt;i&gt;static&lt;/i&gt; resources (png, css, js, etc) that simply didn't change between application releases, yet for every page request the browser would request each of these 40 resources and a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;304 Not Modified&lt;/span&gt; response returned for each.&amp;nbsp; Given the fact that each of these requests was laden with SSO, load balancer &amp;amp; CQ session cookies (another problem); the overhead for this was quite great.&lt;br /&gt;
&lt;br /&gt;
In keeping with &lt;a href="http://developer.yahoo.com/performance/rules.html"&gt;good practices for speeding up websites&lt;/a&gt;, we wanted to set &lt;a href="http://developer.yahoo.com/performance/rules.html#expires"&gt;far future Expires headers&lt;/a&gt; on these static resources so that once the client populated their cache, there would no more requests for these resources.&lt;br /&gt;
The first step towards this was to add some directives to our apache httpd.conf that set the expires headers for us.&lt;br /&gt;
&lt;br /&gt;
This would add an &lt;a href="http://www.mnot.net/cache_docs/#EXPIRES"&gt;Expires header&lt;/a&gt; to each static resource&lt;b&gt; &lt;/b&gt;that was requested with a date that was 1 year in the future.&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;
&amp;lt;Location "cq/myapp/static"&amp;gt;&lt;br /&gt;
ExpiresDefault "access plus 1 year"&lt;br /&gt;
&amp;lt;/Location&amp;gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
However, from time to time we make application releases which do change these "static" resources.&amp;nbsp; For example, any change to the site's CSS design or javascript functionality would need to be represented immediately for users of the site.&lt;br /&gt;
&lt;br /&gt;
To get around this we used the CQ4 mapper functionality to rewrite the resource URLs within the system to include the version number.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;This meant changing the &lt;span style="color: #333399;"&gt;&lt;b&gt;/config/delivery/mapper_live_publish.xml&lt;/b&gt;&lt;/span&gt; file to contain the following mapping:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_4jbBMJC6xXc/SwLdHPWgAAI/AAAAAAAAAWI/3OYHwkVOY7w/s1600/mapper.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_4jbBMJC6xXc/SwLdHPWgAAI/AAAAAAAAAWI/3OYHwkVOY7w/s400/mapper.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #003366;"&gt;&lt;b&gt;&lt;map from="/apps/myapp/docroot/myapp/static" to="/myapp/static/v1.0.2/"&gt;&lt;/map&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
This adapted the URLs output from CQ templates from&lt;br /&gt;
/&lt;span style="color: #333399;"&gt;&lt;b&gt;myapp/static/js/logo.png &lt;span style="color: #38761d; font-size: small;"&gt;&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #333399;"&gt;&lt;b&gt;/myapp/static/&lt;span style="color: green;"&gt;v.1.0.2&lt;/span&gt;/js/logo.png&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
All this means that a client with a populated cache will rarely request any of the static resources of the site &lt;i&gt;unless &lt;/i&gt;they change, in which case they are requested immediately.&amp;nbsp; This saves a tremendous amount of effort for the client browser, and the user experience of the site performance is greatly improved.&amp;nbsp; These simple steps gave us great performance boost for very little effort.&lt;img src="http://feeds.feedburner.com/~r/Cqstuff/~4/LVagdzW8ers" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.diffa.co.uk/feeds/7388697377351529811/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.diffa.co.uk/2009/11/improving-day-cq-performance-using.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5349471866547418688/posts/default/7388697377351529811?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5349471866547418688/posts/default/7388697377351529811?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Cqstuff/~3/LVagdzW8ers/improving-day-cq-performance-using.html" title="Improving Day CQ Performance Using Caching" /><author><name>Chris Pilsworth</name><uri>http://www.blogger.com/profile/03221639608396248493</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_4jbBMJC6xXc/SwLdHPWgAAI/AAAAAAAAAWI/3OYHwkVOY7w/s72-c/mapper.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://blog.diffa.co.uk/2009/11/improving-day-cq-performance-using.html</feedburner:origLink></entry></feed>
