summaryrefslogtreecommitdiffstats
path: root/openstack/common/rpc/common.py
diff options
context:
space:
mode:
authorDan Smith <danms@us.ibm.com>2012-12-05 12:22:40 -0800
committerDan Smith <danms@us.ibm.com>2012-12-06 08:31:13 -0800
commit15ae704d927ba2ecd97d29195d30d5587987e2ad (patch)
treebcca356f634c5f7a67d7f3e7b0672a8ac3e7ef72 /openstack/common/rpc/common.py
parent2f7a7edc41d0e7b663877592aeda14e766a64241 (diff)
Allow exceptions to pass over RPC silently
When one service performs an operation on behalf of another, the act of passing back an exception (even a known one) causes a lot of scary log messages about the (presumed to be) error case. This patch adds a client_exceptions decorator common/rpc/common.py, which allows RPC services to declare the list of expected exceptions for each method. If such an exception is raised during the RPC dispatch, it is wrapped in a ClientException so that the RPC layer can gracefully pass it back without overly-verbose logging. This will allow us to fix nova bug 1084707 Change-Id: I4e7b19dc730342091fd70a717065741d56da4555
Diffstat (limited to 'openstack/common/rpc/common.py')
-rw-r--r--openstack/common/rpc/common.py41
1 files changed, 38 insertions, 3 deletions
diff --git a/openstack/common/rpc/common.py b/openstack/common/rpc/common.py
index c56c9a6..efdf26f 100644
--- a/openstack/common/rpc/common.py
+++ b/openstack/common/rpc/common.py
@@ -18,6 +18,7 @@
# under the License.
import copy
+import sys
import traceback
from openstack.common.gettextutils import _
@@ -195,7 +196,7 @@ def _safe_log(log_func, msg, msg_data):
return log_func(msg, msg_data)
-def serialize_remote_exception(failure_info):
+def serialize_remote_exception(failure_info, log_failure=True):
"""Prepares exception data to be sent over rpc.
Failure_info should be a sys.exc_info() tuple.
@@ -203,8 +204,9 @@ def serialize_remote_exception(failure_info):
"""
tb = traceback.format_exception(*failure_info)
failure = failure_info[1]
- LOG.error(_("Returning exception %s to caller"), unicode(failure))
- LOG.error(tb)
+ if log_failure:
+ LOG.error(_("Returning exception %s to caller"), unicode(failure))
+ LOG.error(tb)
kwargs = {}
if hasattr(failure, 'kwargs'):
@@ -309,3 +311,36 @@ class CommonRpcContext(object):
context.values['read_deleted'] = read_deleted
return context
+
+
+class ClientException(Exception):
+ """This encapsulates some actual exception that is expected to be
+ hit by an RPC proxy object. Merely instantiating it records the
+ current exception information, which will be passed back to the
+ RPC client without exceptional logging."""
+ def __init__(self):
+ self._exc_info = sys.exc_info()
+
+
+def catch_client_exception(exceptions, func, *args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except Exception, e:
+ if type(e) in exceptions:
+ raise ClientException()
+ else:
+ raise
+
+
+def client_exceptions(*exceptions):
+ """Decorator for manager methods that raise expected exceptions.
+ Marking a Manager method with this decorator allows the declaration
+ of expected exceptions that the RPC layer should not consider fatal,
+ and not log as if they were generated in a real error scenario. Note
+ that this will cause listed exceptions to be wrapped in a
+ ClientException, which is used internally by the RPC layer."""
+ def outer(func):
+ def inner(*args, **kwargs):
+ return catch_client_exception(exceptions, func, *args, **kwargs)
+ return inner
+ return outer