Merge "add _find_caller to the request log"
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 7d90d69..4cc7338 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -15,6 +15,7 @@
 #    under the License.
 
 import collections
+import inspect
 import json
 from lxml import etree
 import re
@@ -223,6 +224,57 @@
         versions = map(lambda x: x['id'], body)
         return resp, versions
 
+    def _find_caller(self):
+        """Find the caller class and test name.
+
+        Because we know that the interesting things that call us are
+        test_* methods, and various kinds of setUp / tearDown, we
+        can look through the call stack to find appropriate methods,
+        and the class we were in when those were called.
+        """
+        caller_name = None
+        names = []
+        frame = inspect.currentframe()
+        is_cleanup = False
+        # Start climbing the ladder until we hit a good method
+        while True:
+            try:
+                frame = frame.f_back
+                name = frame.f_code.co_name
+                names.append(name)
+                if re.search("^(test_|setUp|tearDown)", name):
+                    cname = ""
+                    if 'self' in frame.f_locals:
+                        cname = frame.f_locals['self'].__class__.__name__
+                    if 'cls' in frame.f_locals:
+                        cname = frame.f_locals['cls'].__name__
+                    caller_name = cname + ":" + name
+                    break
+                elif re.search("^_run_cleanup", name):
+                    is_cleanup = True
+                else:
+                    cname = ""
+                    if 'self' in frame.f_locals:
+                        cname = frame.f_locals['self'].__class__.__name__
+                    if 'cls' in frame.f_locals:
+                        cname = frame.f_locals['cls'].__name__
+
+                    # the fact that we are running cleanups is indicated pretty
+                    # deep in the stack, so if we see that we want to just
+                    # start looking for a real class name, and declare victory
+                    # once we do.
+                    if is_cleanup and cname:
+                        if not re.search("^RunTest", cname):
+                            caller_name = cname + ":_run_cleanups"
+                            break
+            except Exception:
+                break
+        # prevents frame leaks
+        del frame
+        if caller_name is None:
+            self.LOG.debug("Sane call name not found in %s" % names)
+        return caller_name
+
     def _get_request_id(self, resp):
         for i in ('x-openstack-request-id', 'x-compute-request-id'):
             if i in resp:
@@ -232,7 +284,8 @@
     def _log_request(self, method, req_url, resp):
         extra = dict(request_id=self._get_request_id(resp))
         self.LOG.info(
-            'Request: %s %s %s' % (
+            'Request (%s): %s %s %s' % (
+                self._find_caller(),
                 resp['status'],
                 method,
                 req_url),