diff --git a/gracedb/views.py b/gracedb/views.py
index 8266ccd8efde923b6831face3700e8ea4f0bc3dd..fe427c8204281e140787b191a65a6a8e9574e0a8 100644
--- a/gracedb/views.py
+++ b/gracedb/views.py
@@ -44,6 +44,7 @@ MAX_QUERY_RESULTS = 1000
 GRACEDB_DATA_DIR = settings.GRACEDB_DATA_DIR
 
 import json
+import datetime
 
 def index(request):
 #   assert request.user
@@ -1155,3 +1156,77 @@ def taglogentry(request, graceid, num, tagname):
     msg = "Successfully applied tag %s to log message %s." % (tagname, num)
     return HttpResponse(msg, content_type="text")
 
+# XXX added by Branson. Performance metrics.
+def performance(request):
+    # First, try to find the relevant logfile from settings.
+    try:
+        logfilepath = settings.LOGGING['handlers']['performance_file']['filename']
+        logfile = open(logfilepath, "r")
+    except:
+        return HttpResponse("Failed to locate performance log file. Sorry")
+
+   
+    # Now parse the log file
+    dateformat = '%Y-%m-%dT%H:%M:%S' # ISO format. I think.
+
+    # Lookback time is 3 days.
+    dt_now = datetime.datetime.now()
+    dt_min = dt_now + datetime.timedelta(days=-3)
+
+    creation_status_totals = {}
+    annotation_status_totals = {}
+    total_create_requests = 0
+    total_annotate_requests = 0
+
+    totals_by_status = {}
+    totals_by_method = {}
+
+    for line in logfile:
+        datestring = line[0:len('YYYY-MM-DDTHH:MM:SS')]
+        # Check the date to see whether it's fresh enough
+        dt = datetime.datetime.strptime(datestring, dateformat)
+        if dt > dt_min:
+            # Get rid of the datestring and the final colon.
+            line = line[len(datestring)+1:]
+            # Parse
+            method, status, username = line.split(':')
+            method = method.strip()
+            status = int(status.strip())
+            username = username.strip()
+
+            if method not in totals_by_method.keys():
+                totals_by_method[method] = 1
+                totals_by_status[method] = {status: 1}
+            else:
+                totals_by_method[method] += 1
+                if status not in totals_by_status[method].keys():
+                    totals_by_status[method][status] = 1
+                else:
+                    totals_by_status[method][status] += 1
+
+    # Calculate summary information:
+    summaries = {}
+    for method in totals_by_method.keys():
+        summaries[method] = {'gt_500': 0, 'btw_300_500': 0}
+        for key in totals_by_status[method].keys():
+            if key >= 500:
+                summaries[method]['gt_500'] += totals_by_status[method][key]
+            elif key >= 300:
+                summaries[method]['btw_300_500'] += totals_by_status[method][key]
+        # Normalize
+        if totals_by_method[method] > 0:
+            for key in summaries[method].keys():
+                summaries[method][key] = float(summaries[method][key])/totals_by_method[method]
+
+    context = {
+            'summaries': summaries,
+            'current_time' : str(dt_now),
+            'totals_by_status' : totals_by_status,
+            'totals_by_method' : totals_by_method,
+    }
+
+    return render_to_response(
+            'gracedb/performance.html',
+            context,
+            context_instance=RequestContext(request))
+ 
diff --git a/settings/default.py b/settings/default.py
index 5178c21fa4d91d96cd5a0e5bd2d80069ad838cc5..7f192690fa84f9f80175df3c59ff7a957f6c3a92 100644
--- a/settings/default.py
+++ b/settings/default.py
@@ -190,6 +190,7 @@ ADMIN_GROUP_HEADER = None
 ADMIN_GROUP = None
 
 MIDDLEWARE_CLASSES = [
+    'middleware.performance.PerformanceMiddleware',
     'middleware.accept.AcceptMiddleware',
     'middleware.cli.CliExceptionMiddleware',
     'django.middleware.common.CommonMiddleware',
@@ -239,3 +240,52 @@ STATICFILES_FINDERS = (
 )
 
 STATICFILES_DIRS = ()
+
+# XXX The following Log settings are for a performance metric.
+import logging
+LOG_ROOT = '/home/branson/logs'
+LOG_FILE_SIZE = 1024*1024 # 1 MB
+LOG_FILE_BAK_CT = 3
+
+# Filter objects to separate out each level of alert.
+class infoOnlyFilter(logging.Filter):
+    def filter(self,record):
+        if record.levelname=='INFO':
+            return 1
+        return 0
+
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers' : True,
+    'formatters': {
+        'simple': {
+            'format': '%(asctime)s: %(message)s',
+            'datefmt': '%Y-%m-%dT%H:%M:%S',
+        },
+    },
+    'handlers': {
+        'null': {
+            'level':'DEBUG',
+            'class':'django.utils.log.NullHandler',
+        },
+        'performance_file': {
+            'class': 'logging.handlers.RotatingFileHandler',
+            'formatter': 'simple',
+            'filename': '%s/gracedb_performance.log' % LOG_ROOT,
+            'maxBytes': LOG_FILE_SIZE,
+            'backupCount': LOG_FILE_BAK_CT,
+        },
+    },
+    'loggers': {
+        'django': {
+            'handlers': ['null'],
+            'propagate': True,
+            'level': 'INFO',
+        },
+        'middleware': {
+            'handlers': ['performance_file'],
+            'propagate': True,
+            'level': 'INFO',
+        },
+   },
+}
diff --git a/templates/gracedb/histogram.html b/templates/gracedb/histogram.html
index 42b8c9613a2f34409be1e800e91251fe9d46ea0b..c3c52c61c9ee1ea5a5ecb7b9c7a3dc1b7b98d83b 100644
--- a/templates/gracedb/histogram.html
+++ b/templates/gracedb/histogram.html
@@ -137,5 +137,9 @@ function toggle(id) {
      No rate charts.
 {% endif %}
 </div>
+<br/>
+<br/>
+
+<a href="{% url performance %}"><h3>GraceDB 3-day performance summary</h3></a>
 
 {% endblock %}
diff --git a/urls.py b/urls.py
index b319de8822c928b8c7d79b7984ec2245dc2530e4..53b23fa363c08a4691937150fbe60c7e2b9bdcf1 100644
--- a/urls.py
+++ b/urls.py
@@ -29,6 +29,7 @@ urlpatterns = patterns('',
     (r'^feeds/(?P<url>.*)/$', EventFeed()),
     url (r'^feeds/$', feedview, name="feeds"),
 
+    url (r'^performance/$', 'gracedb.views.performance', name="performance"),
     url (r'^reports/$', 'gracedb.reports.histo', name="reports"),
     url (r'^reports/gstlalcbc_report/(?P<format>(json|flex))?$', 'gracedb.reports.gstlalcbc_report', name="gstlalcbc_report"),
     (r'^reports/(?P<path>.+)$', 'django.views.static.serve',