{"id":393,"date":"2011-12-16T15:47:21","date_gmt":"2011-12-16T20:47:21","guid":{"rendered":"http:\/\/irreal.org\/blog\/?p=393"},"modified":"2011-12-16T15:47:21","modified_gmt":"2011-12-16T20:47:21","slug":"filtering-log-files-stored-as-lisp-with-emacs","status":"publish","type":"post","link":"https:\/\/irreal.org\/blog\/?p=393","title":{"rendered":"Filtering Log Files Stored As Lisp With Emacs"},"content":{"rendered":"\n<p>Yesterday, I wrote about <a href=\"http:\/\/irreal.org\/blog\/?p=391\">transforming log files stored as Lisp<\/a>. Today, I want to continue that theme by considering how we can have the log file filter itself so that we can pick out records meeting certain criteria. I wasn&#8217;t going to bother with this but it&#8217;s so easy once you have the infrastructure set up, I thought it might be fun to explore it a bit. Yesterday, I worked in Common Lisp, today, just for variety, I&#8217;ll work in Emacs Lisp. <\/p>\n<p> For the benefit of those just joining the discussion, here is a typical record (from Steve Yegge&#8217;s <a href=\"http:\/\/sites.google.com\/site\/steveyegge2\/the-emacs-problem\">The Emacs Problem<\/a>). <\/p>\n<pre class=\"src src-lisp\">(record\n  (date <span style=\"color: #8b2252;\">\"2005-02-21T18:57:39\"<\/span>)\n  (millis 1109041059800)\n  (sequence 1)\n  (logger nil)\n  (level 'SEVERE)\n  (class <span style=\"color: #8b2252;\">\"java.util.logging.LogManager$RootLogger\"<\/span>)\n  (method 'log)\n  (thread 10)\n  (message <span style=\"color: #8b2252;\">\"A very very bad thing has happened!\"<\/span>)\n  (exception\n    (message <span style=\"color: #8b2252;\">\"java.lang.Exception\"<\/span>)\n    (frame\n      (class <span style=\"color: #8b2252;\">\"logtest\"<\/span>)\n      (method 'main)\n      (line 30))))\n<\/pre>\n<p> To help me in developing code for this post, I duplicated this record 4 times, changing some of the fields, wrapped it in a <code>(log ...)<\/code> sexpr, and put it in the variable <code>log-file<\/code>. As we did yesterday, we start by making each of the tags executable. To start, we define <code>record<\/code>, <code>exception<\/code>, and <code>frame<\/code> as functions that perform an <code>and<\/code> operation on their arguments. The <code>record<\/code> function is defined as <\/p>\n<pre class=\"src src-emacs-lisp\">(<span style=\"color: #7f007f;\">defun<\/span> <span style=\"color: #0000ff;\">record<\/span> (<span style=\"color: #228b22;\">&amp;rest<\/span> args) (every 'identity args))\n<\/pre>\n<p> and the other two are the same except for their names. See <a href=\"http:\/\/irreal.org\/blog\/?p=318\">Applying and And or In Emacs<\/a> for why something like <code>(apply 'and args)<\/code> won&#8217;t work. The other tags are defined as functions that just return <code>t<\/code>. For example, <code>date<\/code> is <\/p>\n<pre class=\"src src-emacs-lisp\">(<span style=\"color: #7f007f;\">defun<\/span> <span style=\"color: #0000ff;\">date<\/span> (<span style=\"color: #228b22;\">&amp;rest<\/span> args) t)\n<\/pre>\n<p> Now let&#8217;s suppose we only want to see records that have a <code>level<\/code> of <code>SEVERE<\/code>. We redefine <code>level<\/code> as <\/p>\n<pre class=\"src src-emacs-lisp\">(<span style=\"color: #7f007f;\">defun<\/span> <span style=\"color: #0000ff;\">level<\/span> (s) (eq s 'SEVERE))\n<\/pre>\n<p> and filter out the other records by running <\/p>\n<pre class=\"src src-emacs-lisp\">(remove-if-not 'eval (cdr log-file))\n<\/pre>\n<p> The <code>remove-if-not<\/code> function filters out any records that fail the \u201cpredicate\u201d <code>eval<\/code>. Because <code>eval<\/code> evaluates the <code>record<\/code> sexpr it returns a <code>t<\/code> or <code>nil<\/code> value for each record. In this case, records without a level of <code>SEVERE<\/code> will have level return <code>nil<\/code> and therefore <code>record<\/code> will also return <code>nil<\/code> and therefore be filtered out. <\/p>\n<p> We can build up more complicated conditions if needed. For example, if we want to see only records with a level of <code>SEVERE<\/code> and a <code>line<\/code> greater than 30, in addition to redefining <code>level<\/code>, we would also redefine <code>line<\/code> as <\/p>\n<pre class=\"src src-emacs-lisp\">(<span style=\"color: #7f007f;\">defun<\/span> <span style=\"color: #0000ff;\">line<\/span> (l) (&gt; l 30))\n<\/pre>\n<p> and run the <code>remove-if-not<\/code> function on <code>log-file<\/code>. <\/p>\n<p> If you&#8217;re interested in this sort of thing, here are some problems to think about <\/p>\n<ol>\n<li>How would you filter on\n<pre class=\"example\">level equals SEVERE or line &gt; 30\n<\/pre>\n<\/li>\n<li>Notice that <code>method<\/code> appears twice in the record. How would you    filter on the one that&#8217;s in the <code>frame<\/code> sexpr? <\/li>\n<li>How would you handle general queries such as\n<pre class=\"example\">(level equals SEVERE or line &gt; 30) and thread equals 10\n<\/pre>\n<\/li>\n<\/ol>\n<p>I&#8217;ll give my answers to those questions in the next installment. <\/p>\n<p> It might seem like this is a lot of work to run a query given that there are general tools available for doing so but it doesn&#8217;t take nearly as much effort as you might think. First of all, you would have a lot of these functions already defined so that you can just paste them into your buffer, redefine the filtering conditions, and run the filter. In the next installment, I&#8217;ll talk about how writing these functions, even if you don&#8217;t already have them, is really easy when you leverage the power of Emacs. I&#8217;ll also discuss how I used Emacs to develop and test the code interactively as I went along. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Yesterday, I wrote about transforming log files stored as Lisp. Today, I want to continue that theme by considering how we can have the log file filter itself so that we can pick out records meeting certain criteria. I wasn&#8217;t &hellip; <a href=\"https:\/\/irreal.org\/blog\/?p=393\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[18,28,14],"class_list":["post-393","post","type-post","status-publish","format-standard","hentry","category-programming","tag-emacs","tag-emacs-lisp","tag-lisp"],"_links":{"self":[{"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/393","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=393"}],"version-history":[{"count":0,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/393\/revisions"}],"wp:attachment":[{"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=393"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=393"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=393"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}