{"id":809,"date":"2011-09-28T19:16:31","date_gmt":"2011-09-29T02:16:31","guid":{"rendered":"http:\/\/www.visophyte.org\/blog\/?p=809"},"modified":"2011-09-28T19:16:31","modified_gmt":"2011-09-29T02:16:31","slug":"the-joy-of-integrated-logging-and-log-viewing-with-fancy-logs","status":"publish","type":"post","link":"https:\/\/www.visophyte.org\/blog\/2011\/09\/28\/the-joy-of-integrated-logging-and-log-viewing-with-fancy-logs\/","title":{"rendered":"The joy of integrated logging and log viewing with fancy logs"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-810\" title=\"about-loggest-collapsed-view\" src=\"http:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/about-loggest-collapsed-view.png\" alt=\"\" width=\"142\" height=\"101\" \/><\/p>\n<p>The <a href=\"https:\/\/github.com\/mozilla\/deuxdrop\">deuxdrop messaging experiment<\/a>&#8216;s current incarnation exists as an (under development) Jetpack that runs in Firefox. \u00a0I am still trying to shake out functionality to be driven by the UI rather than headless unit tests. \u00a0While <a href=\"http:\/\/www.visophyte.org\/blog\/2011\/07\/12\/new-adventures-in-rich-execution-logs-for-debugging-and-program-understanding\/\">firebug<\/a> has been a great help, another boon has been the logging framework and log viewing framework developed for the unit tests. \u00a0(Previous posts <a href=\"http:\/\/www.visophyte.org\/blog\/2011\/07\/12\/new-adventures-in-rich-execution-logs-for-debugging-and-program-understanding\/\">here<\/a> and <a href=\"http:\/\/www.visophyte.org\/blog\/2011\/07\/20\/overview-ownershipcommunication-graphs-for-rich-execution-logs\/\">here<\/a>). \u00a0Since the log is made up of structured JSON data, all the log processing logic is written in JS, and the log viewing UI is HTML\/CSS\/JS, it is trivial to embed the log viewer into the Jetpack itself.<\/p>\n<p>If you type <strong>about:loggest<\/strong>\u00a0in the URL bar (or better yet, create a bookmark on the bookmark bar and click that), the log viewer is displayed. \u00a0Deuxdrop&#8217;s client daemon logic (which runs in a hidden frame), uses a log reaper that runs at 1-second intervals. \u00a0If anything happens log-wise during that second, it is packaged and added to a circular-buffer style list of the last 60 seconds where anything happened. \u00a0When the log viewer starts up, it asks for and receives the data. \u00a0The result looks like the above small screenshot. \u00a0If no errors were logged during the time interval, it is automatically collapsed.<\/p>\n<p>Let us experience the joy of integrated logging by looking at a real problem I recently encountered. \u00a0In the development UI (accessible via about:dddev), I brought up a list of my contacts after starting a conversation. \u00a0It looks like this right now:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-811\" title=\"peeps-tab-user-erroneously-included\" src=\"http:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/peeps-tab-user-erroneously-included.png\" alt=\"\" width=\"505\" height=\"91\" srcset=\"https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/peeps-tab-user-erroneously-included.png 505w, https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/peeps-tab-user-erroneously-included-300x54.png 300w\" sizes=\"auto, (max-width: 505px) 100vw, 505px\" \/><\/p>\n<p>The problem is that I, the user, am &#8220;Andrew Sutherland&#8221; and should not be in my own contact list. \u00a0Also, the display should not be claiming there are an undefined number of unread messages from me, but that is likely fallout from the system intentionally not maintaining such information about me, the user.<\/p>\n<p>I want to quickly figure out why this is happening, so I bring up about:loggest and open the most recent time entry to see what happened when this query was issued and filled:<\/p>\n<p><a href=\"http:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/loggest-query-peeps-by-any.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-thumbnail wp-image-814\" title=\"loggest-query-peeps-by-any\" src=\"http:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/loggest-query-peeps-by-any-600x139.png\" alt=\"\" width=\"600\" height=\"139\" srcset=\"https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/loggest-query-peeps-by-any-600x139.png 600w, https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/loggest-query-peeps-by-any-300x69.png 300w, https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/loggest-query-peeps-by-any.png 1014w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>I can see that the query ended up issuing database requests for both Walternate (purple) and myself (green), strongly suggesting that the database index being queried on names me.<\/p>\n<p>I wonder if the conversation processing logic was the code that did this&#8230; let&#8217;s check by going to the time slice where the conversation was processed, expanding it, and only screenshotting some of it:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-813\" title=\"loggest-new-conv-join-process-bad-index-write\" src=\"http:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/loggest-new-conv-join-process-bad-index-write.png\" alt=\"\" width=\"594\" height=\"461\" srcset=\"https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/loggest-new-conv-join-process-bad-index-write.png 594w, https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/loggest-new-conv-join-process-bad-index-write-300x232.png 300w\" sizes=\"auto, (max-width: 594px) 100vw, 594px\" \/><\/p>\n<p>Yes, the conversation logic did this. \u00a0It&#8217;s generating index values in the <em>peepData<\/em>\u00a0table for the <em>idxPeepAny<\/em>\u00a0and <em>idxPeepRecip<\/em>\u00a0indices. \u00a0But I thought my unit tests covered this? \u00a0Nope. \u00a0It turns that although we test that a peep query returns the right thing both cold from the database and inductively via notifications as contact relationships are established, we don&#8217;t issue a new query after creating a conversation. \u00a0Furthermore, we only issued queries against the alphabetical index, not against <em>idxPeepAny<\/em>. \u00a0So we rectify that by augmenting the unit test:<\/p>\n<pre>  \/\/ - make sure that the conversation addition did not screw up our peeps list\r\n  T.group('check peeps list after conversation join');\r\n  lqFinalAllPeeps = moda_a.do_queryPeeps(\"allPeepsFinal:any\", {by: 'any'});<\/pre>\n<p>And the test indeed now fails:<\/p>\n<p><a href=\"http:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/test-run-details-query-any-failure.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-thumbnail wp-image-815\" title=\"test-run-details-query-any-failure\" src=\"http:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/test-run-details-query-any-failure-600x155.png\" alt=\"\" width=\"600\" height=\"155\" srcset=\"https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/test-run-details-query-any-failure-600x155.png 600w, https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/test-run-details-query-any-failure-300x77.png 300w, https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/test-run-details-query-any-failure-1024x266.png 1024w, https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/test-run-details-query-any-failure.png 1158w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>The relevant bit is in the lower right, which I blow up here with the &#8220;unexpected event&#8221; <em>obj<\/em>\u00a0popup displayed above it, and the &#8220;failed expectation&#8221; <em>obj<\/em>\u00a0popup below it. \u00a0The postAnno stuff is to indicate what is new in the query result. \u00a0Because it&#8217;s a freshly issued query and this is the first set of results, everything is new. \u00a0It&#8217;s probably worth noting that these errors would usually show up as a single &#8220;mismatched&#8221; error instead of an unexpected\/failed pair in our tests, but the specific logger was operating in unordered set mode because we don&#8217;t care about the exact order that different query notifications occur in, we just care that they do occur.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-816\" title=\"test-run-details-query-any-failure-focused-with-popups\" src=\"http:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/test-run-details-query-any-failure-focused-with-popups.png\" alt=\"\" width=\"534\" height=\"355\" srcset=\"https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/test-run-details-query-any-failure-focused-with-popups.png 534w, https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/09\/test-run-details-query-any-failure-focused-with-popups-300x199.png 300w\" sizes=\"auto, (max-width: 534px) 100vw, 534px\" \/><\/p>\n<p>(The structure is intended to later be enhanced to provide a nicer visualization where we only show the contents of the &#8220;state&#8221; attribute and use preAnno to indicate annotations on a representation of the most recent state for the object (from a previous log entry) and postAnno to indicate annotations on the now-current representation &#8220;state&#8221;. \u00a0For postAnno, values of 1 represent an addition, and values of 0 represent a change or event firing on the object.)<\/p>\n<p>A potentially even more exciting bit of integrated logging is that <strong>about:loggest-server<\/strong>\u00a0opens a tab that retrieves its contents from the server. \u00a0When run with the <em>&#8211;loggest-web-debug<\/em>\u00a0flag, the server loads a module that cranks up the logging and does the same 1-second interval log reaping magic and exposes it for HTTP retrieval. \u00a0While this specific configuration with the high level of detailed logging is only appropriate for a developer-machine test server, it is incredibly valuable to be able to just pop open another tab and see what the server just got up to.<\/p>\n<p>In any event, I leave it as an exercise to the reader to assume that I will take care of the bug now that it&#8217;s extremely clear what the problem is. \u00a0Well, extremely clear if I had taken a bigger screenshot of the conversation creation log. \u00a0Above the region captured is a header that indicates the actions are being triggered by the &#8216;convJoin&#8217; task and the entry (which is visible) indicates the update_conv_data function likely kicked off the database activity.<\/p>\n<p>PS: All the gibberish looking characters in the screenshots are crypto keys or other binary data that lack aliases mapping them to known objects. \u00a0Examples of successfully mapped aliases are the colored blocks. \u00a0In the case of the conversation creation gibberish, we are seeing the conversation id. \u00a0Those aliases are generated as a separate pass by the log reaper by walking the set of existing queries and using helper functions to map the items currently exposed by the queries to human names because it&#8217;s quick and easy and is O(what&#8217;s being looked at) not O(size of the database). \u00a0In the case of the conversation, there was no query against the conversation and I also have not written the helper function yet, which is why it did not get aliased. \u00a0Unit tests don&#8217;t have the problem because we create aliases for everything.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The deuxdrop messaging experiment&#8216;s current incarnation exists as an (under development) Jetpack that runs in Firefox. \u00a0I am still trying to shake out functionality to be driven by the UI rather than headless unit tests. \u00a0While firebug has been a &hellip; <a href=\"https:\/\/www.visophyte.org\/blog\/2011\/09\/28\/the-joy-of-integrated-logging-and-log-viewing-with-fancy-logs\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[7,3,8],"tags":[106,109,108],"class_list":["post-809","post","type-post","status-publish","format-standard","hentry","category-debugging","category-mozilla","category-program-execution","tag-arbpl","tag-deuxdrop","tag-loggest"],"_links":{"self":[{"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/posts\/809","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/comments?post=809"}],"version-history":[{"count":8,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/posts\/809\/revisions"}],"predecessor-version":[{"id":824,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/posts\/809\/revisions\/824"}],"wp:attachment":[{"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/media?parent=809"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/categories?post=809"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/tags?post=809"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}