Patchwork [1,of,6,V2] blackbox: adds a blackbox extension

login
register
mail settings
Submitter Durham Goode
Date Feb. 12, 2013, 11:12 p.m.
Message ID <248720a9332a9fac80d5.1360710773@dev350.prn1.facebook.com>
Download mbox | patch
Permalink /patch/971/
State Accepted
Commit 18242716a014eea609f09f39b190248fafde4b00
Headers show

Comments

Durham Goode - Feb. 12, 2013, 11:12 p.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1360706913 28800
#      Tue Feb 12 14:08:33 2013 -0800
# Node ID 248720a9332a9fac80d5f1ab2e19b106cf44e90b
# Parent  5b73c50e99dd6bdf5a5c59a0b4b09ced76b684ad
blackbox: adds a blackbox extension

Adds a blackbox extension that listens to ui.log() and writes the messages to
.hg/blackbox.log. Future commits will use ui.log() to log commands, unhandled
exceptions, incoming changes, and hooks.  The extension defaults to logging
everything, but can be configured via blackbox.track to only log certain events.
Log lines are of the format:  "date time user> message"

Example log line:
2013/02/09 08:35:19 durham> 1 incoming changes - new heads: d84ced58aaa
Bryan O'Sullivan - Feb. 12, 2013, 11:29 p.m.
On Tue, Feb 12, 2013 at 3:12 PM, Durham Goode <durham@fb.com> wrote:

> +        def log(self, event, *msg, **opts):
>

Where does this opts dict get used?
Durham Goode - Feb. 12, 2013, 11:40 p.m.
On 2/12/13 3:29 PM, "Bryan O'Sullivan" <bos@serpentine.com> wrote:

>
>On Tue, Feb 12, 2013 at 3:12 PM, Durham Goode <durham@fb.com> wrote:
>
>>  +        def log(self, event, *msg, **opts):
>
>Where does this opts dict get used?
>

No where at the moment, but ui.status/warn/note/debug/etc have it, so I
figured it was a pattern.  Though now that I look, they only seem to write
to opts.  They never read from it.

Patch

diff --git a/hgext/blackbox.py b/hgext/blackbox.py
new file mode 100644
--- /dev/null
+++ b/hgext/blackbox.py
@@ -0,0 +1,70 @@ 
+"""log repository events to a blackbox for debugging
+
+Logs event information to .hg/blackbox.log to help debug and diagnose problems.
+The events that get logged can be configured via the blackbox.track config key.
+Examples:
+
+  [blackbox]
+  track = *
+
+  [blackbox]
+  track = command, commandfinish, commandexception, exthook, pythonhook
+
+  [blackbox]
+  track = incoming
+
+"""
+
+from mercurial import util, cmdutil
+from mercurial.i18n import _
+import os, getpass, re, string
+
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+testedwith = 'internal'
+lastblackbox = None
+
+def wrapui(ui):
+    class blackboxui(ui.__class__):
+        @util.propertycache
+        def track(self):
+            return ui.configlist('blackbox', 'track', ['*'])
+
+        def log(self, event, *msg, **opts):
+            global lastblackbox
+            super(blackboxui, self).log(event, *msg, **opts)
+
+            if not '*' in self.track and not event in self.track:
+                return
+
+            if util.safehasattr(self, '_blackbox'):
+                blackbox = self._blackbox
+            else:
+                # certain ui instances exist outside the context of
+                # a repo, so just default to the last blackbox that
+                # was seen.
+                blackbox = lastblackbox
+
+            if blackbox:
+                date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
+                user = getpass.getuser()
+                formattedmsg = msg[0] % msg[1:]
+                blackbox.write('%s %s> %s' % (date, user, formattedmsg))
+                lastblackbox = blackbox
+
+        def setrepo(self, repo):
+            self._blackbox = repo.opener('blackbox.log', 'a')
+
+    ui.__class__ = blackboxui
+
+def uisetup(ui):
+    wrapui(ui)
+
+def reposetup(ui, repo):
+    # During 'hg pull' a httppeer repo is created to represent the remote repo.
+    # It doesn't have a .hg directory to put a blackbox in, so we don't do
+    # the blackbox setup for it.
+    if not repo.local():
+        return
+
+    ui.setrepo(repo)
diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -739,7 +739,7 @@ 
         else:
             self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
 
-    def log(self, service, message):
+    def log(self, service, *msg, **opts):
         '''hook for logging facility extensions
 
         service should be a readily-identifiable subsystem, which will