Verbose logging on error
* Create rest logger instance only once.
* If the token does not seams special it is omitted.
* The log level setting in tempest.conf has limitations in
configuring log level, so it is removed for now.
* No extra logging on error in any different log level.
Bug: #1089846
Change-Id: Ibd664520e81e072ea1040c47d0aeef4980903118
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 43277d6..9dca609 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -104,10 +104,6 @@
# Does the compute API support changing the admin password?
change_password_available=true
-# Level to log Compute API request/response details.
-log_level = ERROR
-
-
# Run live migration tests (requires 2 hosts)
live_migration_available = false
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index fa2ea75..5af4a40 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -15,10 +15,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+import hashlib
import httplib2
import json
import logging
from lxml import etree
+import re
import time
from tempest import exceptions
@@ -26,14 +28,14 @@
# redrive rate limited calls at most twice
MAX_RECURSION_DEPTH = 2
+TOKEN_CHARS_RE = re.compile('^[-A-Za-z0-9+/=]*$')
class RestClient(object):
TYPE = "json"
+ LOG = logging.getLogger(__name__)
def __init__(self, config, user, password, auth_url, tenant_name=None):
- self.log = logging.getLogger(__name__)
- self.log.setLevel(getattr(logging, config.compute.log_level))
self.config = config
self.user = user
self.password = password
@@ -189,11 +191,38 @@
def copy(self, url, headers=None):
return self.request('COPY', url, headers)
- def _log(self, req_url, body, resp, resp_body):
- self.log.error('Request URL: ' + req_url)
- self.log.error('Request Body: ' + str(body))
- self.log.error('Response Headers: ' + str(resp))
- self.log.error('Response Body: ' + str(resp_body))
+ def _log_request(self, method, req_url, headers, body):
+ self.LOG.info('Request: ' + method + ' ' + req_url)
+ if headers:
+ print_headers = headers
+ if 'X-Auth-Token' in headers and headers['X-Auth-Token']:
+ token = headers['X-Auth-Token']
+ if len(token) > 64 and TOKEN_CHARS_RE.match(token):
+ print_headers = headers.copy()
+ print_headers['X-Auth-Token'] = "<Token omitted>"
+ self.LOG.debug('Request Headers: ' + str(print_headers))
+ if body:
+ str_body = str(body)
+ length = len(str_body)
+ self.LOG.debug('Request Body: ' + str_body[:2048])
+ if length >= 2048:
+ self.LOG.debug("Large body (%d) md5 summary: %s", length,
+ hashlib.md5(str_body).hexdigest())
+
+ def _log_response(self, resp, resp_body):
+ status = resp['status']
+ self.LOG.info("Response Status: " + status)
+ headers = resp.copy()
+ del headers['status']
+ if len(headers):
+ self.LOG.debug('Response Headers: ' + str(headers))
+ if resp_body:
+ str_body = str(resp_body)
+ length = len(str_body)
+ self.LOG.debug('Response Body: ' + str_body[:2048])
+ if length >= 2048:
+ self.LOG.debug("Large body (%d) md5 summary: %s", length,
+ hashlib.md5(str_body).hexdigest())
def _parse_resp(self, body):
return json.loads(body)
@@ -224,7 +253,7 @@
# Likely it will cause error
if not body and resp.status >= 400:
- self.log.warning("status >= 400 response with empty body")
+ self.LOG.warning("status >= 400 response with empty body")
def request(self, method, url,
headers=None, body=None, depth=0, wait=None):
@@ -240,39 +269,34 @@
headers['X-Auth-Token'] = self.token
req_url = "%s/%s" % (self.base_url, url)
+ self._log_request(method, req_url, headers, body)
resp, resp_body = self.http_obj.request(req_url, method,
headers=headers, body=body)
+ self._log_response(resp, resp_body)
self.response_checker(method, url, headers, body, resp, resp_body)
if resp.status == 401 or resp.status == 403:
- self._log(req_url, body, resp, resp_body)
raise exceptions.Unauthorized()
if resp.status == 404:
- if not wait:
- self._log(req_url, body, resp, resp_body)
raise exceptions.NotFound(resp_body)
if resp.status == 400:
resp_body = self._parse_resp(resp_body)
- self._log(req_url, body, resp, resp_body)
raise exceptions.BadRequest(resp_body)
if resp.status == 409:
resp_body = self._parse_resp(resp_body)
- self._log(req_url, body, resp, resp_body)
raise exceptions.Duplicate(resp_body)
if resp.status == 413:
resp_body = self._parse_resp(resp_body)
- self._log(req_url, body, resp, resp_body)
#Checking whether Absolute/Rate limit
return self.check_over_limit(resp_body, method, url, headers, body,
depth, wait)
if resp.status in (500, 501):
resp_body = self._parse_resp(resp_body)
- self._log(req_url, body, resp, resp_body)
#I'm seeing both computeFault and cloudServersFault come back.
#Will file a bug to fix, but leave as is for now.
@@ -292,7 +316,6 @@
if resp.status >= 400:
resp_body = self._parse_resp(resp_body)
- self._log(req_url, body, resp, resp_body)
raise exceptions.RestClientException(str(resp.status))
return resp, resp_body
diff --git a/tempest/config.py b/tempest/config.py
index 38f3535..ec48f67 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -161,9 +161,6 @@
cfg.StrOpt('catalog_type',
default='compute',
help="Catalog type of the Compute service."),
- cfg.StrOpt('log_level',
- default="ERROR",
- help="Level for logging compute API calls."),
cfg.StrOpt('path_to_private_key',
default=None,
help="Path to a private key file for SSH access to remote "
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index 734307c..fec273c 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -112,11 +112,13 @@
self._set_auth()
req_url = "%s/%s" % (self.base_url, url)
+
+ self._log_request(method, req_url, headers, body)
resp, resp_body = self.http_obj.request(req_url, method,
headers=headers, body=body)
+ self._log_response(resp, resp_body)
if resp.status == 401 or resp.status == 403:
- self._log(req_url, body, resp, resp_body)
raise exceptions.Unauthorized()
return resp, resp_body
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index edfb234..187e80d 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -167,11 +167,11 @@
self._set_auth()
req_url = "%s/%s" % (self.base_url, url)
+ self._log_request(method, req_url, headers, body)
resp, resp_body = self.http_obj.request(req_url, method,
headers=headers, body=body)
-
+ self._log_response(resp, resp_body)
if resp.status == 401 or resp.status == 403:
- self._log(req_url, body, resp, resp_body)
raise exceptions.Unauthorized()
return resp, resp_body