diff --git a/openstackclient/common/clientmanager.py b/openstackclient/common/clientmanager.py
index 10f38c25bc..6d2a9d76b7 100644
--- a/openstackclient/common/clientmanager.py
+++ b/openstackclient/common/clientmanager.py
@@ -19,10 +19,10 @@ import logging
 import pkg_resources
 import sys
 
-from keystoneclient import session
 import requests
 
 from openstackclient.api import auth
+from openstackclient.common import session as osc_session
 from openstackclient.identity import client as identity_client
 
 
@@ -157,7 +157,7 @@ class ClientManager(object):
         self.auth = auth_plugin.load_from_options(**self._auth_params)
         # needed by SAML authentication
         request_session = requests.session()
-        self.session = session.Session(
+        self.session = osc_session.TimingSession(
             auth=self.auth,
             session=request_session,
             verify=self._verify,
diff --git a/openstackclient/common/session.py b/openstackclient/common/session.py
new file mode 100644
index 0000000000..dda1c41709
--- /dev/null
+++ b/openstackclient/common/session.py
@@ -0,0 +1,50 @@
+#   Licensed under the Apache License, Version 2.0 (the "License"); you may
+#   not use this file except in compliance with the License. You may obtain
+#   a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#   License for the specific language governing permissions and limitations
+#   under the License.
+#
+
+"""Subclass of keystoneclient.session"""
+
+from keystoneclient import session
+
+
+class TimingSession(session.Session):
+    """A Session that supports collection of timing data per Method URL"""
+
+    def __init__(
+            self,
+            **kwargs
+    ):
+        """Pass through all arguments except timing"""
+        super(TimingSession, self).__init__(**kwargs)
+
+        # times is a list of tuples: ("method url", elapsed_time)
+        self.times = []
+
+    def get_timings(self):
+        return self.times
+
+    def reset_timings(self):
+        self.times = []
+
+    def request(self, url, method, **kwargs):
+        """Wrap the usual request() method with the timers"""
+        resp = super(TimingSession, self).request(url, method, **kwargs)
+        for h in resp.history:
+            self.times.append((
+                "%s %s" % (h.request.method, h.request.url),
+                h.elapsed,
+            ))
+        self.times.append((
+            "%s %s" % (resp.request.method, resp.request.url),
+            resp.elapsed,
+        ))
+        return resp
diff --git a/openstackclient/common/timing.py b/openstackclient/common/timing.py
index 1c94682c84..d13c86e73c 100644
--- a/openstackclient/common/timing.py
+++ b/openstackclient/common/timing.py
@@ -33,10 +33,12 @@ class Timing(lister.Lister):
 
         results = []
         total = 0.0
-        for url, start, end in self.app.timing_data:
-            seconds = end - start
-            total += seconds
-            results.append((url, seconds))
+        for url, td in self.app.timing_data:
+            # NOTE(dtroyer): Take the long way here because total_seconds()
+            #                was added in py27.
+            sec = (td.microseconds + (td.seconds + td.days*86400) * 1e6) / 1e6
+            total += sec
+            results.append((url, sec))
         results.append(('Total', total))
         return (
             column_headers,
diff --git a/openstackclient/shell.py b/openstackclient/shell.py
index c118fbd290..444d37e442 100644
--- a/openstackclient/shell.py
+++ b/openstackclient/shell.py
@@ -292,11 +292,10 @@ class OpenStackShell(app.App):
 
         # Process collected timing data
         if self.options.timing:
-            # Loop through extensions
-            for mod in self.ext_modules:
-                client = getattr(self.client_manager, mod.API_NAME)
-                if hasattr(client, 'get_timings'):
-                    self.timing_data.extend(client.get_timings())
+            # Get session data
+            self.timing_data.extend(
+                self.client_manager.session.get_timings(),
+            )
 
             # Use the Timing pseudo-command to generate the output
             tcmd = timing.Timing(self, self.options)
diff --git a/openstackclient/tests/common/test_timing.py b/openstackclient/tests/common/test_timing.py
index aa910b91e5..a7f93b55ca 100644
--- a/openstackclient/tests/common/test_timing.py
+++ b/openstackclient/tests/common/test_timing.py
@@ -13,14 +13,15 @@
 
 """Test Timing pseudo-command"""
 
+import datetime
+
 from openstackclient.common import timing
 from openstackclient.tests import fakes
 from openstackclient.tests import utils
 
 
 timing_url = 'GET http://localhost:5000'
-timing_start = 1404802774.872809
-timing_end = 1404802775.724802
+timing_elapsed = 0.872809
 
 
 class FakeGenericClient(object):
@@ -66,9 +67,10 @@ class TestTiming(utils.TestCommand):
         self.assertEqual(datalist, data)
 
     def test_timing_list(self):
-        self.app.timing_data = [
-            (timing_url, timing_start, timing_end),
-        ]
+        self.app.timing_data = [(
+            timing_url,
+            datetime.timedelta(microseconds=timing_elapsed*1000000),
+        )]
 
         arglist = []
         verifylist = []
@@ -79,9 +81,8 @@ class TestTiming(utils.TestCommand):
 
         collist = ('URL', 'Seconds')
         self.assertEqual(collist, columns)
-        timing_sec = timing_end - timing_start
         datalist = [
-            (timing_url, timing_sec),
-            ('Total', timing_sec)
+            (timing_url, timing_elapsed),
+            ('Total', timing_elapsed),
         ]
         self.assertEqual(datalist, data)