blog post snapshot
authorAndrew Sutherland <asutherland@asutherland.org>
Sun, 14 Dec 2008 09:20:20 -0800
changeset 2 0f63436107bb2f6f9a031403280927d04e2e00e9
parent 1 1e6401f409b2277cb874f091bdb0e60f8c1168cd
child 3 a1fcf5764e5903e733f14948fb2cf973865047fc
push id1
push userbugmail@asutherland.org
push dateSun, 14 Dec 2008 17:23:57 +0000
blog post snapshot
application.ini
chrome/content/logviewer.css
chrome/content/logviewer.xhtml
chrome/content/viewbindings.xml
--- a/application.ini
+++ b/application.ini
@@ -1,11 +1,14 @@
 [App]
 Vendor=momo
 Name=Logsploder
 Version=0.1
 BuildID=20081207
 Copyright=Copyright (c) 2008 Mozilla Messaging, Inc.
 ID=logsploder@mozillamessaging.com
 
+[XRE]
+EnableExtensionManager=1
+
 [Gecko]
 MinVersion=1.9.0
 MaxVersion=1.9.*
--- a/chrome/content/logviewer.css
+++ b/chrome/content/logviewer.css
@@ -1,7 +1,8 @@
 #logviewer {
   -moz-binding: url('chrome://logsploder/content/viewbindings.xml#logviewer');
 }
 
 .logmessage {
   -moz-binding: url('chrome://logsploder/content/viewbindings.xml#logmessage');
+  list-style: square inside;
 }
--- a/chrome/content/logviewer.xhtml
+++ b/chrome/content/logviewer.xhtml
@@ -1,29 +1,23 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
     <title>Log Viewer</title>
-    <!-- 
     <script src="chrome://visophyte/content/visophyte.js" type="application/javascript;version=1.8"/>
-    -->
     <link rel="stylesheet"
       href="chrome://logsploder/content/logviewer.css"
       type="text/css" />
     <script type="application/javascript;version=1.8">
       const Cc = Components.classes;
       const Ci = Components.interfaces;
       const Cr = Components.results;
       const Cu = Components.utils;
 
       Cu.import("resource://logsploder/modules/gobbler.js");
     </script>
   </head>
   <body bgcolor="#ffffff">
-    <canvas id="wordy" width="800" height="200"></canvas>
-    Picture above!
-    <br/>
     <div id="logviewer"/>
-    Log crap above!
   </body>
 </html>
\ No newline at end of file
--- a/chrome/content/viewbindings.xml
+++ b/chrome/content/viewbindings.xml
@@ -15,52 +15,175 @@
         dump("Anonymous nodes: " + document.getAnonymousNodes(this) + "\n");
         dump("Anonymous node 0: " + document.getAnonymousNodes(this)[0] + "\n");
         
         this._messageArea = document.getAnonymousElementByAttribute(this,
           "anonid", "messagearea");
         dump("message area: " + this._messageArea + "\n");
         this.gobbler = new LogGobbler(this);
         this.gobbler.start(9363);
+        
+        this.logContexts = {};
+        this.logContextsByTime = [];
+        this.messagesByContext = {};
       ]]></constructor>
       <method name="onLogMessage">
         <parameter name="message"/>
         <body><![CDATA[
-          let node = document.createElement("li");
-          node.setAttribute("class", "logmessage");
-          this._messageArea.appendChild(node);
-          node.message = message;
+          if (0) {
+            let node = document.createElement("li");
+            node.setAttribute("class", "logmessage");
+            this._messageArea.appendChild(node);
+            node.message = message;
+          }
+          
+          let newContext = this.getLogContext(message);
+          if (newContext) {
+            let knownContext = this.logContexts[newContext.id];
+            
+            if (!knownContext) {
+              this.logContextsByTime.push(newContext);
+              this.logContexts[newContext.id] = newContext;
+              this.messagesByContext[newContext.id] = [message]; 
+            }
+            else {
+              for each (let [key, newVal] in Iterator(newContext)) {
+                if (!(key in knownContext))
+                  knownContext[key] = newVal;
+                else {
+                  let oldVal = knownContext[key];
+                  if (oldVal != newVal) {
+                    knownContext[key] = newVal;
+                    if (key == "lastStateChange" &&
+                        newContext.state != "finished") {
+                      let stateChanges = knownContext.stateChanges;
+                      if (stateChanges === undefined)
+                        stateChanges = knownContext.stateChanges = [];
+                      stateChanges.push([newVal, newContext.state]);
+                    }
+                  }
+                }
+              }
+              this.messagesByContext[newContext.id].push(message);
+            }
+            
+            if (newContext.finished) {
+              this.updateVis();
+              dump("duration for " + newContext.id + " was: " +
+                   (newContext.finished - newContext.started) + " sql: " +
+                   newContext.sql + "\n");
+            }
+          }
+        ]]></body>
+      </method>
+      <method name="getLogContext">
+        <parameter name="message"/>
+        <body><![CDATA[
+          for each (let [, messageObject] in
+                    Iterator(message.messageObjects)) {
+            if ((typeof(messageObject) == "object") && messageObject._isContext)
+              return messageObject;
+          }
+          return null;
         ]]></body>
       </method>
+      
+      <method name="updateVis">
+        <body><![CDATA[
+          if (this.vRequest === undefined) {
+            this.vRequest = vRequest = new Vis();
+            vRequest.add(new DistinctColor("noun", "fill", 0.2, 0.9));
+            vRequest.add(new ValueMapper("type", "stroke",
+              {query: "#000", xbl: "#080", stream: "#008"}));
+            vRequest.add(new Rectangle("fill", "stroke", "strokeWidth"));
+        
+            this.vTimeline = vTimeline = new Vis();
+            vTimeline.add(new HoverToggler("toggled",
+                                         {fill: "white"}));
+            vTimeline.add(new ClickCallback(this, this.showMessagesForContext));                         
+            // position and size the vRequest instances
+            vTimeline.add(new TimeLayout(vRequest, 10, "started", "finished",
+                {strokeWidth: 1}, "stateChanges",
+                {dbdone: "#00f", cachestart: "#f00", cachedone: "#0f0",
+                 addItemStart: "#f00",
+                 gotMessages: "#f00", procedMessages: "#0f0",
+                 issueStream: "#f8f", gotStream: "#888"}));
+          }
+          else {
+            this.vcTimeline.unbindFromCanvasNode();
+          }
+          
+          this.vcTimeline = this.vTimeline.makeContext(this.logContextsByTime,
+              {}); 
+          let canvasNode = document.getAnonymousElementByAttribute(this,
+              "anonid", "canvasy");
+          this.vcTimeline.bindToCanvasNode(canvasNode, 0, 0);
+        ]]></body>
+      </method>
+      
+      <method name="clearLogs">
+        <body><![CDATA[
+          this.logContexts = {};
+          this.logContextsByTime = [];
+          this.messagesByContext = {};
+        ]]></body>
+      </method>
+      
+      <method name="showMessagesForContext">
+        <parameter name="phantomContext"/>
+        <body><![CDATA[
+          let messages = this.messagesByContext[phantomContext.id];
+          
+          if (messages) {
+            // nuke the current messages
+            let messageArea = this._messageArea;
+            while (messageArea.firstChild)
+              messageArea.removeChild(messageArea.firstChild);
+            
+            for each (let [, message] in Iterator(messages)) {
+              let node = document.createElement("li");
+              node.setAttribute("class", "logmessage");
+              this._messageArea.appendChild(node);
+              node.message = message;
+            }
+          }
+        ]]></body>
+      </method>
+
     </implementation>
     <content>
-      <html:div>
-        Hello, jerky XBL world!
-      </html:div>
+      <html:canvas anonid="canvasy" width="1000" height="320"></html:canvas>
+      <html:hr/>
+      <html:button onclick="document.getBindingParent(this).clearLogs()">Clear</html:button>
+      <html:hr/>
       <ul anonid="messagearea" />
     </content>
   </binding>
   
   <binding id="logmessage">
     <implementation>
       <constructor><![CDATA[
         //this._messageNode = document.getAnonymousElementByAttribute(this,
         //  "anonid", "message");
       ]]></constructor>
       <property name="message">
         <setter><![CDATA[
           this._message = val;
           
+          let date = new Date(this._message.time);
           let messageText = "";
           for each (let [, messageObject] in
                     Iterator(this._message.messageObjects)) {
             if (typeof(messageObject) != "object")
               messageText += (messageText ? " " : "") + messageObject;
             else if (!messageObject._isContext)
               messageText += (messageText ? " " : "") + messageObject.toString();
-          } 
+            else {
+              dump("Got context! " + messageObject.id + ":" + messageObject.state + "\n");
+            }
+          }
           
-          this.textContent = messageText;
+          this.textContent = date + ": " + messageText;
         ]]></setter>
       </property>
     </implementation>
   </binding>
 </bindings>