Hello community,

here is the log from the commit of package python-osprofiler for 
openSUSE:Factory checked in at 2018-01-17 21:56:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-osprofiler (Old)
 and      /work/SRC/openSUSE:Factory/.python-osprofiler.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-osprofiler"

Wed Jan 17 21:56:39 2018 rev:5 rq:565775 version:1.14.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-osprofiler/python-osprofiler.changes      
2017-08-28 15:30:00.400435309 +0200
+++ /work/SRC/openSUSE:Factory/.python-osprofiler.new/python-osprofiler.changes 
2018-01-17 21:56:41.491767995 +0100
@@ -1,0 +2,16 @@
+Mon Jan 15 12:04:06 UTC 2018 - cloud-de...@suse.de
+
+- update to version 1.14.0
+  - Remove unused parameters from Profiler class
+  - Make dependency on oslo.messaging runtime only
+  - Update reno for stable/pike
+  - Add loading local static files option of template.html
+  - Do not require OpenStack authentication to run osprofiler CLI
+  - Improve unit test coverage
+  - Make test_notifier independent of test case execution order
+  - Remove dependency on oslo.log library
+  - Extend messaging driver to support reporting
+  - Handle and report SQLAlchemy errors
+  - Add function/sql results to trace info
+
+-------------------------------------------------------------------

Old:
----
  osprofiler-1.11.0.tar.gz

New:
----
  osprofiler-1.14.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-osprofiler.spec ++++++
--- /var/tmp/diff_new_pack.8PDYwi/_old  2018-01-17 21:56:42.163736562 +0100
+++ /var/tmp/diff_new_pack.8PDYwi/_new  2018-01-17 21:56:42.171736188 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-osprofiler
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,39 +16,63 @@
 #
 
 
-%global sname osprofiler
 Name:           python-osprofiler
-Version:        1.11.0
+Version:        1.14.0
 Release:        0
 Summary:        OpenStack Profiler Library
 License:        Apache-2.0
 Group:          Development/Languages/Python
 Url:            https://launchpad.net/osprofiler
-Source0:        
https://pypi.io/packages/source/o/%{sname}/%{sname}-%{version}.tar.gz
+Source0:        
https://files.pythonhosted.org/packages/source/o/osprofiler/osprofiler-1.14.0.tar.gz
 BuildRequires:  openstack-macros
-BuildRequires:  python-WebOb >= 1.7.1
-BuildRequires:  python-ceilometerclient >= 2.5.0
-BuildRequires:  python-ddt >= 1.0.1
 BuildRequires:  python-devel
-BuildRequires:  python-elasticsearch >= 2.0.0
-BuildRequires:  python-mock >= 2.0
-BuildRequires:  python-oslo.concurrency >= 3.8.0
-BuildRequires:  python-oslo.config >= 4.0.0
-BuildRequires:  python-oslo.log >= 3.22.0
-BuildRequires:  python-oslo.utils >= 3.20.0
-BuildRequires:  python-pymongo >= 3.0.2
-BuildRequires:  python-python-subunit >= 0.0.18
-BuildRequires:  python-redis >= 2.10.0
-BuildRequires:  python-six >= 1.9.0
-BuildRequires:  python-testrepository >= 0.0.18
-BuildRequires:  python-testtools >= 1.4.0
+BuildRequires:  python2-WebOb >= 1.7.1
+BuildRequires:  python2-ceilometerclient >= 2.5.0
+BuildRequires:  python2-ddt >= 1.0.1
+BuildRequires:  python2-elasticsearch >= 2.0.0
+BuildRequires:  python2-mock >= 2.0.0
+BuildRequires:  python2-oslo.concurrency >= 3.20.0
+BuildRequires:  python2-oslo.config >= 4.6.0
+BuildRequires:  python2-oslo.log >= 3.30.0
+BuildRequires:  python2-oslo.utils >= 3.31.0
+BuildRequires:  python2-pymongo >= 3.0.2
+BuildRequires:  python2-python-subunit >= 1.0.0
+BuildRequires:  python2-redis >= 2.10.0
+BuildRequires:  python2-six >= 1.10.0
+BuildRequires:  python2-testrepository >= 0.0.18
+BuildRequires:  python2-testtools >= 2.2.0
+BuildRequires:  python3-WebOb >= 1.7.1
+BuildRequires:  python3-ceilometerclient >= 2.5.0
+BuildRequires:  python3-ddt >= 1.0.1
+BuildRequires:  python3-devel
+BuildRequires:  python3-elasticsearch >= 2.0.0
+BuildRequires:  python3-mock >= 2.0.0
+BuildRequires:  python3-oslo.concurrency >= 3.20.0
+BuildRequires:  python3-oslo.config >= 4.6.0
+BuildRequires:  python3-oslo.log >= 3.30.0
+BuildRequires:  python3-oslo.utils >= 3.31.0
+BuildRequires:  python3-pymongo >= 3.0.2
+BuildRequires:  python3-python-subunit >= 1.0.0
+BuildRequires:  python3-redis >= 2.10.0
+BuildRequires:  python3-six >= 1.10.0
+BuildRequires:  python3-testrepository >= 0.0.18
+BuildRequires:  python3-testtools >= 2.2.0
 Requires:       python-WebOb >= 1.7.1
-Requires:       python-oslo.concurrency >= 3.8.0
-Requires:       python-oslo.config >= 4.0.0
-Requires:       python-oslo.log >= 3.22.0
-Requires:       python-oslo.utils >= 3.20.0
-Requires:       python-six >= 1.9.0
+Requires:       python-oslo.concurrency >= 3.20.0
+Requires:       python-oslo.config >= 4.6.0
+Requires:       python-oslo.log >= 3.30.0
+Requires:       python-oslo.utils >= 3.31.0
+Requires:       python-six >= 1.10.0
 BuildArch:      noarch
+%if 0%{?suse_version}
+Requires(post): update-alternatives
+Requires(postun): update-alternatives
+%else
+# on RDO, update-alternatives is in chkconfig
+Requires(post): chkconfig
+Requires(postun): chkconfig
+%endif
+%python_subpackages
 
 %description
 OSProfiler provides a tiny but powerful library that is used by
@@ -58,42 +82,51 @@
 to build a tree of calls which can be quite handy for a variety of
 reasons (for example in isolating cross-project performance issues).
 
-%package doc
+%package -n python-osprofiler-doc
 Summary:        Documentation for OSProfiler
 Group:          Development/Languages/Python
 BuildRequires:  python-Sphinx
-BuildRequires:  python-openstackdocstheme >= 1.11.0
+BuildRequires:  python-openstackdocstheme >= 1.17.0
 
-%description doc
+%description -n python-osprofiler-doc
 Documentation for OSProfiler.
 
 %prep
-%autosetup -n %{sname}-%{version}
+%autosetup -p1 -n osprofiler-1.14.0
 %py_req_cleanup
 sed -i 's/^warning-is-error.*/warning-is-error = 0/g' setup.cfg
 
 %build
-%{py2_build}
+%{python_build}
 
 %install
-%{py2_install}
+%{python_install}
+%python_clone -a %{buildroot}%{_bindir}/osprofiler
 
 # generate html docs
 %{__python2} setup.py build_sphinx
 # remove the sphinx-build leftovers
 rm -rf doc/build/html/.{doctrees,buildinfo}
 
+%post
+%python_install_alternative osprofiler
+
+%postun
+%python_uninstall_alternative osprofiler
+
 %check
-%{__python2} setup.py testr
+%{python_expand rm -rf .testrepository
+$python setup.py testr
+}
 
-%files
+%files %{python_files}
 %license LICENSE
 %doc README.rst ChangeLog
-%{python2_sitelib}/osprofiler
-%{python2_sitelib}/*.egg-info
-%{_bindir}/osprofiler
+%{python_sitelib}/osprofiler
+%{python_sitelib}/*.egg-info
+%python_alternative %{_bindir}/osprofiler
 
-%files doc
+%files -n python-osprofiler-doc
 %license LICENSE
 %doc doc/build/html
 

++++++ _service ++++++
--- /var/tmp/diff_new_pack.8PDYwi/_old  2018-01-17 21:56:42.211734317 +0100
+++ /var/tmp/diff_new_pack.8PDYwi/_new  2018-01-17 21:56:42.211734317 +0100
@@ -1,8 +1,8 @@
 <services>
   <service mode="disabled" name="renderspec">
-    <param 
name="input-template">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/pike/openstack/osprofiler/osprofiler.spec.j2</param>
+    <param 
name="input-template">https://raw.githubusercontent.com/openstack/rpm-packaging/master/openstack/osprofiler/osprofiler.spec.j2</param>
     <param name="output-name">python-osprofiler.spec</param>
-    <param 
name="requirements">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/pike/global-requirements.txt</param>
+    <param 
name="requirements">https://raw.githubusercontent.com/openstack/rpm-packaging/master/requirements.txt</param>
     <param name="changelog-email">cloud-de...@suse.de</param>
     <param name="changelog-provider">gh,openstack,osprofiler</param>
   </service>

++++++ osprofiler-1.11.0.tar.gz -> osprofiler-1.14.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/AUTHORS 
new/osprofiler-1.14.0/AUTHORS
--- old/osprofiler-1.11.0/AUTHORS       2017-07-18 15:11:04.000000000 +0200
+++ new/osprofiler-1.14.0/AUTHORS       2017-11-13 16:32:10.000000000 +0100
@@ -38,6 +38,8 @@
 Vipin Balachandran <vb...@vmware.com>
 Vu Cong Tuan <tua...@vn.fujitsu.com>
 Zhi Yan Liu <zhiy...@cn.ibm.com>
+Zuul <z...@review.openstack.org>
+chenxu <424024...@qq.com>
 gecong1973 <ge.c...@zte.com.cn>
 howardlee <lihongwe...@inspur.com>
 kavithahr <kavith...@nectechnologies.in>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/ChangeLog 
new/osprofiler-1.14.0/ChangeLog
--- old/osprofiler-1.11.0/ChangeLog     2017-07-18 15:11:03.000000000 +0200
+++ new/osprofiler-1.14.0/ChangeLog     2017-11-13 16:32:10.000000000 +0100
@@ -1,6 +1,29 @@
 CHANGES
 =======
 
+1.14.0
+------
+
+* Extend messaging driver to support reporting
+* Handle and report SQLAlchemy errors
+
+1.13.0
+------
+
+* Remove dependency on oslo.log library
+
+1.12.0
+------
+
+* Do not require OpenStack authentication to run osprofiler CLI
+* Make dependency on oslo.messaging runtime only
+* Make test\_notifier independent of test case execution order
+* Add function/sql results to trace info
+* Improve unit test coverage
+* Remove unused parameters from Profiler class
+* Add loading local static files option of template.html
+* Update reno for stable/pike
+
 1.11.0
 ------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/PKG-INFO 
new/osprofiler-1.14.0/PKG-INFO
--- old/osprofiler-1.11.0/PKG-INFO      2017-07-18 15:11:04.000000000 +0200
+++ new/osprofiler-1.14.0/PKG-INFO      2017-11-13 16:32:11.000000000 +0100
@@ -1,11 +1,12 @@
 Metadata-Version: 1.1
 Name: osprofiler
-Version: 1.11.0
+Version: 1.14.0
 Summary: OpenStack Profiler Library
 Home-page: https://docs.openstack.org/osprofiler/latest/
 Author: OpenStack
 Author-email: openstack-...@lists.openstack.org
 License: UNKNOWN
+Description-Content-Type: UNKNOWN
 Description: ========================
         Team and repository tags
         ========================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler/cmd/commands.py 
new/osprofiler-1.14.0/osprofiler/cmd/commands.py
--- old/osprofiler-1.11.0/osprofiler/cmd/commands.py    2017-07-18 
15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/cmd/commands.py    2017-11-13 
16:29:18.000000000 +0100
@@ -37,10 +37,18 @@
                   help="Storage driver's connection string. Defaults to "
                        "env[OSPROFILER_CONNECTION_STRING] if set, else "
                        "ceilometer://")
+    @cliutils.arg("--transport-url", dest="transport_url",
+                  help="Oslo.messaging transport URL (for messaging:// driver "
+                       "only), e.g. rabbit://user:password@host:5672/")
+    @cliutils.arg("--idle-timeout", dest="idle_timeout", type=int, default=1,
+                  help="How long to wait for the trace to finish, in seconds "
+                       "(for messaging:// driver only)")
     @cliutils.arg("--json", dest="use_json", action="store_true",
                   help="show trace in JSON")
     @cliutils.arg("--html", dest="use_html", action="store_true",
                   help="show trace in HTML")
+    @cliutils.arg("--local-libs", dest="local_libs", action="store_true",
+                  help="use local static files of html in /libs/")
     @cliutils.arg("--dot", dest="use_dot", action="store_true",
                   help="show trace in DOT language")
     @cliutils.arg("--render-dot", dest="render_dot_filename",
@@ -87,6 +95,10 @@
                     "$DATA", json.dumps(trace, indent=4,
                                         separators=(",", ": "),
                                         default=datetime_json_serialize))
+                if args.local_libs:
+                    output = output.replace("$LOCAL", "true")
+                else:
+                    output = output.replace("$LOCAL", "false")
         elif args.use_dot:
             dot_graph = self._create_dot_graph(trace)
             output = dot_graph.source
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler/cmd/shell.py 
new/osprofiler-1.14.0/osprofiler/cmd/shell.py
--- old/osprofiler-1.11.0/osprofiler/cmd/shell.py       2017-07-18 
15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/cmd/shell.py       2017-11-13 
16:29:18.000000000 +0100
@@ -37,31 +37,6 @@
         args = self._get_base_parser().parse_args(argv)
         opts.set_defaults(cfg.CONF)
 
-        if not (args.os_auth_token and args.ceilometer_url):
-            if not args.os_username:
-                raise exc.CommandError(
-                    "You must provide a username via either --os-username or "
-                    "via env[OS_USERNAME]")
-
-            if not args.os_password:
-                raise exc.CommandError(
-                    "You must provide a password via either --os-password or "
-                    "via env[OS_PASSWORD]")
-
-            if self._no_project_and_domain_set(args):
-                # steer users towards Keystone V3 API
-                raise exc.CommandError(
-                    "You must provide a project_id via either --os-project-id "
-                    "or via env[OS_PROJECT_ID] and a domain_name via either "
-                    "--os-user-domain-name or via env[OS_USER_DOMAIN_NAME] or "
-                    "a domain_id via either --os-user-domain-id or via "
-                    "env[OS_USER_DOMAIN_ID]")
-
-            if not args.os_auth_url:
-                raise exc.CommandError(
-                    "You must provide an auth url via either --os-auth-url or "
-                    "via env[OS_AUTH_URL]")
-
         args.func(args)
 
     def _get_base_parser(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler/cmd/template.html 
new/osprofiler-1.14.0/osprofiler/cmd/template.html
--- old/osprofiler-1.11.0/osprofiler/cmd/template.html  2017-07-18 
15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/cmd/template.html  2017-11-13 
16:29:18.000000000 +0100
@@ -2,12 +2,6 @@
 <html ng-app="app">
 
 <head>
-    <link rel="stylesheet" 
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css";>
-    <link rel="stylesheet" 
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/styles/github.min.css";>
-    <script 
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js";></script>
-    <script 
src="https://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.3.1.min.js";></script>
-    <script 
src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/highlight.min.js";></script>
-    <script 
src="https://pc035860.github.io/angular-highlightjs/angular-highlightjs.min.js";></script>
     <style>
         .trace {
             min-width: 900px;
@@ -77,6 +71,28 @@
 
     </style>
     <script>
+        var static_files = $LOCAL;
+        if (static_files){
+            document.write('<link rel="stylesheet" 
href="/libs/bootstrap.min.css">');
+            document.write('<link rel="stylesheet" 
href="/libs/github.min.css">');
+            document.write('<script type="text/javascript" 
src="/libs/angular.min.js"><\/script>');
+            document.write('<script type="text/javascript" 
src="/libs/ui-bootstrap-tpls-2.3.1.min.js"><\/script>');
+            document.write('<script type="text/javascript" 
src="/libs/highlight.min.js"><\/script>');
+            document.write('<script type="text/javascript" 
src="/libs/angular-highlightjs.min.js"><\/script>');
+        }
+        else{
+            document.write('<link rel="stylesheet" 
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css";>');
+            document.write('<link rel="stylesheet" 
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/styles/github.min.css";>');
+            document.write('<script type="text/javascript" 
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js";><\/script>');
+            document.write('<script type="text/javascript" 
src="https://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.3.1.min.js";><\/script>');
+            document.write('<script type="text/javascript" 
src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/highlight.min.js";><\/script>');
+            document.write('<script type="text/javascript" 
src="https://pc035860.github.io/angular-highlightjs/angular-highlightjs.min.js";><\/script>');
+        }
+    </script>
+</head>
+
+<body>
+    <script>
         (function(angular) {
             'use strict';
 
@@ -208,9 +224,6 @@
             }
         })(window.angular);
     </script>
-</head>
-
-<body>
     <!--Tree item template-->
     <script type="text/ng-template" id="tree_item_renderer.html">
         <div ng-init="hide_children=false">
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler/drivers/base.py 
new/osprofiler-1.14.0/osprofiler/drivers/base.py
--- old/osprofiler-1.11.0/osprofiler/drivers/base.py    2017-07-18 
15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/drivers/base.py    2017-11-13 
16:29:18.000000000 +0100
@@ -14,13 +14,13 @@
 #    under the License.
 
 import datetime
+import logging
 
-from oslo_log import log
 import six.moves.urllib.parse as urlparse
 
 from osprofiler import _utils
 
-LOG = log.getLogger(__name__)
+LOG = logging.getLogger(__name__)
 
 
 def get_driver(connection_string, *args, **kwargs):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler/drivers/messaging.py 
new/osprofiler-1.14.0/osprofiler/drivers/messaging.py
--- old/osprofiler-1.11.0/osprofiler/drivers/messaging.py       2017-07-18 
15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/drivers/messaging.py       2017-11-13 
16:29:18.000000000 +0100
@@ -13,25 +13,66 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import functools
+import signal
+import time
+
+from oslo_utils import importutils
+
 from osprofiler.drivers import base
 
 
 class Messaging(base.Driver):
-    def __init__(self, connection_str, messaging=None, context=None,
-                 transport=None, project=None, service=None,
-                 host=None, **kwargs):
-        """Driver sending notifications via message queues."""
+    def __init__(self, connection_str, project=None, service=None, host=None,
+                 context=None, conf=None, transport_url=None,
+                 idle_timeout=1, **kwargs):
+        """Driver that uses messaging as transport for notifications
+
+        :param connection_str: OSProfiler driver connection string,
+               equals to messaging://
+        :param project: project name that will be included into notification
+        :param service: service name that will be included into notification
+        :param host: host name that will be included into notification
+        :param context: oslo.messaging context
+        :param conf: oslo.config CONF object
+        :param transport_url: oslo.messaging transport, e.g.
+               rabbit://rabbit:password@devstack:5672/
+        :param idle_timeout: how long to wait for new notifications after
+               the last one seen in the trace; this parameter is useful to
+               collect full trace of asynchronous commands, e.g. when user
+               runs `osprofiler` right after `openstack server create`
+        :param kwargs: black hole for any other parameters
+        """
+
+        self.oslo_messaging = importutils.try_import("oslo_messaging")
+        if not self.oslo_messaging:
+            raise ValueError("Oslo.messaging library is required for "
+                             "messaging driver")
 
         super(Messaging, self).__init__(connection_str, project=project,
                                         service=service, host=host)
 
-        self.messaging = messaging
         self.context = context
 
-        self.client = messaging.Notifier(
-            transport, publisher_id=self.host, driver="messaging",
+        if not conf:
+            oslo_config = importutils.try_import("oslo_config")
+            if not oslo_config:
+                raise ValueError("Oslo.config library is required for "
+                                 "messaging driver")
+            conf = oslo_config.cfg.CONF
+
+        transport_kwargs = {}
+        if transport_url:
+            transport_kwargs["url"] = transport_url
+
+        self.transport = self.oslo_messaging.get_notification_transport(
+            conf, **transport_kwargs)
+        self.client = self.oslo_messaging.Notifier(
+            self.transport, publisher_id=self.host, driver="messaging",
             topics=["profiler"], retry=0)
 
+        self.idle_timeout = idle_timeout
+
     @classmethod
     def get_name(cls):
         return "messaging"
@@ -60,3 +101,98 @@
         self.client.info(context or self.context,
                          "profiler.%s" % info["service"],
                          info)
+
+    def get_report(self, base_id):
+        notification_endpoint = NotifyEndpoint(self.oslo_messaging, base_id)
+        endpoints = [notification_endpoint]
+        targets = [self.oslo_messaging.Target(topic="profiler")]
+        server = self.oslo_messaging.notify.get_notification_listener(
+            self.transport, targets, endpoints, executor="threading")
+
+        state = dict(running=False)
+        sfn = functools.partial(signal_handler, state=state)
+
+        # modify signal handlers to handle interruption gracefully
+        old_sigterm_handler = signal.signal(signal.SIGTERM, sfn)
+        old_sigint_handler = signal.signal(signal.SIGINT, sfn)
+
+        try:
+            server.start()
+        except self.oslo_messaging.server.ServerListenError:
+            # failed to start the server
+            raise
+        except SignalExit:
+            print("Execution interrupted while trying to connect to "
+                  "messaging server. No data was collected.")
+            return {}
+
+        # connected to server, now read the data
+        try:
+            # run until the trace is complete
+            state["running"] = True
+
+            while state["running"]:
+                last_read_time = notification_endpoint.get_last_read_time()
+                wait = self.idle_timeout - (time.time() - last_read_time)
+                if wait < 0:
+                    state["running"] = False
+                else:
+                    time.sleep(wait)
+        except SignalExit:
+            print("Execution interrupted. Terminating")
+        finally:
+            server.stop()
+            server.wait()
+
+        # restore original signal handlers
+        signal.signal(signal.SIGTERM, old_sigterm_handler)
+        signal.signal(signal.SIGINT, old_sigint_handler)
+
+        events = notification_endpoint.get_messages()
+
+        if not events:
+            print("No events are collected for Trace UUID %s. Please note "
+                  "that osprofiler has read ALL events from profiler topic, "
+                  "but has not found any for specified Trace UUID." % base_id)
+
+        for n in events:
+            trace_id = n["trace_id"]
+            parent_id = n["parent_id"]
+            name = n["name"]
+            project = n["project"]
+            service = n["service"]
+            host = n["info"]["host"]
+            timestamp = n["timestamp"]
+
+            self._append_results(trace_id, parent_id, name, project, service,
+                                 host, timestamp, n)
+
+        return self._parse_results()
+
+
+class NotifyEndpoint(object):
+
+    def __init__(self, oslo_messaging, base_id):
+        self.received_messages = []
+        self.last_read_time = time.time()
+        self.filter_rule = oslo_messaging.NotificationFilter(
+            payload={"base_id": base_id})
+
+    def info(self, ctxt, publisher_id, event_type, payload, metadata):
+        self.received_messages.append(payload)
+        self.last_read_time = time.time()
+
+    def get_messages(self):
+        return self.received_messages
+
+    def get_last_read_time(self):
+        return self.last_read_time  # time when the latest event was received
+
+
+class SignalExit(BaseException):
+    pass
+
+
+def signal_handler(signum, frame, state):
+    state["running"] = False
+    raise SignalExit()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler/initializer.py 
new/osprofiler-1.14.0/osprofiler/initializer.py
--- old/osprofiler-1.11.0/osprofiler/initializer.py     2017-07-18 
15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/initializer.py     2017-11-13 
16:29:18.000000000 +0100
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import oslo_messaging
-
 from osprofiler import notifier
 from osprofiler import web
 
@@ -30,17 +28,12 @@
                  running on.
     """
     connection_str = conf.profiler.connection_string
-    kwargs = {}
-    if connection_str.startswith("messaging"):
-        kwargs = {"messaging": oslo_messaging,
-                  "transport": oslo_messaging.get_notification_transport(conf)}
     _notifier = notifier.create(
         connection_str,
         context=context,
         project=project,
         service=service,
         host=host,
-        conf=conf,
-        **kwargs)
+        conf=conf)
     notifier.set(_notifier)
     web.enable(conf.profiler.hmac_keys)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler/profiler.py 
new/osprofiler-1.14.0/osprofiler/profiler.py
--- old/osprofiler-1.11.0/osprofiler/profiler.py        2017-07-18 
15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/profiler.py        2017-11-13 
16:29:18.000000000 +0100
@@ -44,8 +44,7 @@
                              % (attr_name, traced_times))
 
 
-def init(hmac_key, base_id=None, parent_id=None, connection_str=None,
-         project=None, service=None):
+def init(hmac_key, base_id=None, parent_id=None):
     """Init profiler instance for current thread.
 
     You should call profiler.init() before using osprofiler.
@@ -54,16 +53,10 @@
     :param hmac_key: secret key to sign trace information.
     :param base_id: Used to bind all related traces.
     :param parent_id: Used to build tree of traces.
-    :param connection_str: Connection string to the backend to use for
-                           notifications.
-    :param project: Project name that is under profiling
-    :param service: Service name that is under profiling
     :returns: Profiler instance
     """
     __local_ctx.profiler = _Profiler(hmac_key, base_id=base_id,
-                                     parent_id=parent_id,
-                                     connection_str=connection_str,
-                                     project=project, service=service)
+                                     parent_id=parent_id)
     return __local_ctx.profiler
 
 
@@ -94,7 +87,8 @@
         profiler.stop(info=info)
 
 
-def trace(name, info=None, hide_args=False, allow_multiple_trace=True):
+def trace(name, info=None, hide_args=False, hide_result=True,
+          allow_multiple_trace=True):
     """Trace decorator for functions.
 
     Very useful if you would like to add trace point on existing function:
@@ -109,6 +103,9 @@
     :param hide_args: Don't push to trace info args and kwargs. Quite useful
                       if you have some info in args that you wont to share,
                       e.g. passwords.
+    :param hide_result: Boolean value to hide/show function result in trace.
+                        True - hide function result (default).
+                        False - show function result in trace.
     :param allow_multiple_trace: If the wrapped function has already been
                                  traced either allow the new trace to occur
                                  or raise a value error denoting that multiple
@@ -140,24 +137,43 @@
 
         @functools.wraps(f)
         def wrapper(*args, **kwargs):
-            if "name" not in info["function"]:
+            # NOTE(tovin07): Workaround for this issue
+            # F823 local variable 'info'
+            # (defined in enclosing scope on line xxx)
+            # referenced before assignment
+            info_ = info
+            if "name" not in info_["function"]:
                 # Get this once (as it should **not** be changing in
                 # subsequent calls).
-                info["function"]["name"] = reflection.get_callable_name(f)
+                info_["function"]["name"] = reflection.get_callable_name(f)
 
             if not hide_args:
-                info["function"]["args"] = str(args)
-                info["function"]["kwargs"] = str(kwargs)
+                info_["function"]["args"] = str(args)
+                info_["function"]["kwargs"] = str(kwargs)
 
-            with Trace(name, info=info):
-                return f(*args, **kwargs)
+            stop_info = None
+            try:
+                start(name, info=info_)
+                result = f(*args, **kwargs)
+            except Exception as ex:
+                stop_info = {"etype": reflection.get_class_name(ex)}
+                raise
+            else:
+                if not hide_result:
+                    stop_info = {"function": {"result": repr(result)}}
+                return result
+            finally:
+                if stop_info:
+                    stop(info=stop_info)
+                else:
+                    stop()
 
         return wrapper
 
     return decorator
 
 
-def trace_cls(name, info=None, hide_args=False,
+def trace_cls(name, info=None, hide_args=False, hide_result=True,
               trace_private=False, allow_multiple_trace=True,
               trace_class_methods=False, trace_static_methods=False):
     """Trace decorator for instances of class .
@@ -180,6 +196,9 @@
     :param hide_args: Don't push to trace info args and kwargs. Quite useful
                       if you have some info in args that you wont to share,
                       e.g. passwords.
+    :param hide_result: Boolean value to hide/show function result in trace.
+                        True - hide function result (default).
+                        False - show function result in trace.
     :param trace_private: Trace methods that starts with "_". It wont trace
                           methods that starts "__" even if it is turned on.
     :param trace_static_methods: Trace staticmethods. This may be prone to
@@ -233,7 +252,8 @@
             # halfway trace this class).
             _ensure_no_multiple_traced(traceable_attrs)
         for i, (attr_name, attr) in enumerate(traceable_attrs):
-            wrapped_method = trace(name, info=info, hide_args=hide_args)(attr)
+            wrapped_method = trace(name, info=info, hide_args=hide_args,
+                                   hide_result=hide_result)(attr)
             wrapper = traceable_wrappers[i]
             if wrapper is not None:
                 wrapped_method = wrapper(wrapped_method)
@@ -253,6 +273,7 @@
     >>>      __trace_args__ = {'name': 'rpc',
     >>>                        'info': None,
     >>>                        'hide_args': False,
+    >>>                        'hide_result': True,
     >>>                        'trace_private': False}
     >>>
     >>>      def my_method(self, some_args):
@@ -329,17 +350,13 @@
 
 class _Profiler(object):
 
-    def __init__(self, hmac_key, base_id=None, parent_id=None,
-                 connection_str=None, project=None, service=None):
+    def __init__(self, hmac_key, base_id=None, parent_id=None):
         self.hmac_key = hmac_key
         if not base_id:
             base_id = str(uuidutils.generate_uuid())
         self._trace_stack = collections.deque([base_id, parent_id or base_id])
         self._name = collections.deque()
         self._host = socket.gethostname()
-        self._connection_str = connection_str
-        self._project = project
-        self._service = service
 
     def get_base_id(self):
         """Return base id of a trace.
@@ -373,8 +390,6 @@
 
         info = info or {}
         info["host"] = self._host
-        info["project"] = self._project
-        info["service"] = self._service
         self._name.append(name)
         self._trace_stack.append(str(uuidutils.generate_uuid()))
         self._notify("%s-start" % name, info)
@@ -388,8 +403,6 @@
         """
         info = info or {}
         info["host"] = self._host
-        info["project"] = self._project
-        info["service"] = self._service
         self._notify("%s-stop" % self._name.pop(), info)
         self._trace_stack.pop()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler/sqlalchemy.py 
new/osprofiler-1.14.0/osprofiler/sqlalchemy.py
--- old/osprofiler-1.11.0/osprofiler/sqlalchemy.py      2017-07-18 
15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/sqlalchemy.py      2017-11-13 
16:29:18.000000000 +0100
@@ -14,9 +14,13 @@
 #    under the License.
 
 import contextlib
+import logging as log
+
+from oslo_utils import reflection
 
 from osprofiler import profiler
 
+LOG = log.getLogger(__name__)
 
 _DISABLED = False
 
@@ -34,14 +38,17 @@
     _DISABLED = False
 
 
-def add_tracing(sqlalchemy, engine, name):
+def add_tracing(sqlalchemy, engine, name, hide_result=True):
     """Add tracing to all sqlalchemy calls."""
 
     if not _DISABLED:
         sqlalchemy.event.listen(engine, "before_cursor_execute",
                                 _before_cursor_execute(name))
-        sqlalchemy.event.listen(engine, "after_cursor_execute",
-                                _after_cursor_execute())
+        sqlalchemy.event.listen(
+            engine, "after_cursor_execute",
+            _after_cursor_execute(hide_result=hide_result)
+        )
+        sqlalchemy.event.listen(engine, "handle_error", handle_error)
 
 
 @contextlib.contextmanager
@@ -66,10 +73,43 @@
     return handler
 
 
-def _after_cursor_execute():
-    """Add listener that will send trace info after query is executed."""
+def _after_cursor_execute(hide_result=True):
+    """Add listener that will send trace info after query is executed.
+
+    :param hide_result: Boolean value to hide or show SQL result in trace.
+                        True - hide SQL result (default).
+                        False - show SQL result in trace.
+    """
 
     def handler(conn, cursor, statement, params, context, executemany):
-        profiler.stop()
+        if not hide_result:
+            # Add SQL result to trace info in *-stop phase
+            info = {
+                "db": {
+                    "result": str(cursor._rows)
+                }
+            }
+            profiler.stop(info=info)
+        else:
+            profiler.stop()
 
     return handler
+
+
+def handle_error(exception_context):
+    """Handle SQLAlchemy errors"""
+    exception_class_name = reflection.get_class_name(
+        exception_context.original_exception)
+    original_exception = str(exception_context.original_exception)
+    chained_exception = str(exception_context.chained_exception)
+
+    info = {
+        "etype": exception_class_name,
+        "db": {
+            "original_exception": original_exception,
+            "chained_exception": chained_exception
+        }
+    }
+    profiler.stop(info=info)
+    LOG.debug("OSProfiler has handled SQLAlchemy error: %s",
+              original_exception)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osprofiler-1.11.0/osprofiler/tests/functional/test_driver.py 
new/osprofiler-1.14.0/osprofiler/tests/functional/test_driver.py
--- old/osprofiler-1.11.0/osprofiler/tests/functional/test_driver.py    
2017-07-18 15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/tests/functional/test_driver.py    
2017-11-13 16:29:18.000000000 +0100
@@ -61,10 +61,7 @@
                     "project": self.PROJECT}
         self._assert_dict(child["info"], **exp_info)
 
-        exp_raw_info = {"project": self.PROJECT,
-                        "service": self.SERVICE}
         raw_start = child["info"]["meta.raw_payload.%s-start" % name]
-        self._assert_dict(raw_start["info"], **exp_raw_info)
         self.assertEqual(fn_name, raw_start["info"]["function"]["name"])
         exp_raw = {"name": "%s-start" % name,
                    "service": self.SERVICE,
@@ -74,14 +71,13 @@
         self._assert_dict(raw_start, **exp_raw)
 
         raw_stop = child["info"]["meta.raw_payload.%s-stop" % name]
-        self._assert_dict(raw_stop["info"], **exp_raw_info)
         exp_raw["name"] = "%s-stop" % name
         self._assert_dict(raw_stop, **exp_raw)
 
     def test_get_report(self):
         initializer.init_from_conf(
             CONF, None, self.PROJECT, self.SERVICE, "host")
-        profiler.init("SECRET_KEY", project=self.PROJECT, service=self.SERVICE)
+        profiler.init("SECRET_KEY")
 
         foo = DriverTestCase.Foo()
         foo.bar(1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osprofiler-1.11.0/osprofiler/tests/unit/cmd/test_shell.py 
new/osprofiler-1.14.0/osprofiler/tests/unit/cmd/test_shell.py
--- old/osprofiler-1.11.0/osprofiler/tests/unit/cmd/test_shell.py       
2017-07-18 15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/tests/unit/cmd/test_shell.py       
2017-11-13 16:29:18.000000000 +0100
@@ -92,39 +92,6 @@
                 "Expected: `osprofiler.exc.CommandError` is raised with "
                 "message: '%s'." % expected_message)
 
-    def test_username_is_not_presented(self):
-        os.environ.pop("OS_USERNAME")
-        msg = ("You must provide a username via either --os-username or "
-               "via env[OS_USERNAME]")
-        self._test_with_command_error(self._trace_show_cmd(), msg)
-
-    def test_password_is_not_presented(self):
-        os.environ.pop("OS_PASSWORD")
-        msg = ("You must provide a password via either --os-password or "
-               "via env[OS_PASSWORD]")
-        self._test_with_command_error(self._trace_show_cmd(), msg)
-
-    def test_auth_url(self):
-        os.environ.pop("OS_AUTH_URL")
-        msg = ("You must provide an auth url via either --os-auth-url or "
-               "via env[OS_AUTH_URL]")
-        self._test_with_command_error(self._trace_show_cmd(), msg)
-
-    def test_no_project_and_domain_set(self):
-        os.environ.pop("OS_PROJECT_ID")
-        os.environ.pop("OS_PROJECT_NAME")
-        os.environ.pop("OS_TENANT_ID")
-        os.environ.pop("OS_TENANT_NAME")
-        os.environ.pop("OS_USER_DOMAIN_ID")
-        os.environ.pop("OS_USER_DOMAIN_NAME")
-
-        msg = ("You must provide a project_id via either --os-project-id or "
-               "via env[OS_PROJECT_ID] and a domain_name via either "
-               "--os-user-domain-name or via env[OS_USER_DOMAIN_NAME] or a "
-               "domain_id via either --os-user-domain-id or via "
-               "env[OS_USER_DOMAIN_ID]")
-        self._test_with_command_error(self._trace_show_cmd(), msg)
-
     def test_trace_show_ceilometerclient_is_missed(self):
         sys.modules["ceilometerclient"] = None
         sys.modules["ceilometerclient.client"] = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osprofiler-1.11.0/osprofiler/tests/unit/drivers/test_base.py 
new/osprofiler-1.14.0/osprofiler/tests/unit/drivers/test_base.py
--- old/osprofiler-1.11.0/osprofiler/tests/unit/drivers/test_base.py    
2017-07-18 15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/tests/unit/drivers/test_base.py    
2017-11-13 16:29:18.000000000 +0100
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import mock
-
 from osprofiler.drivers import base
 from osprofiler.tests import test
 
@@ -55,10 +53,6 @@
                           "Driver not found for connection string: "
                           "nonexisting://")
 
-    def test_plugins_are_imported(self):
-        base.get_driver("messaging://", mock.MagicMock(), "context",
-                        "transport", "host")
-
     def test_build_empty_tree(self):
         class C(base.Driver):
             @classmethod
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osprofiler-1.11.0/osprofiler/tests/unit/drivers/test_messaging.py 
new/osprofiler-1.14.0/osprofiler/tests/unit/drivers/test_messaging.py
--- old/osprofiler-1.11.0/osprofiler/tests/unit/drivers/test_messaging.py       
2017-07-18 15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/tests/unit/drivers/test_messaging.py       
2017-11-13 16:29:18.000000000 +0100
@@ -21,20 +21,37 @@
 
 class MessagingTestCase(test.TestCase):
 
-    def test_init_and_notify(self):
+    @mock.patch("oslo_utils.importutils.try_import")
+    def test_init_no_oslo_messaging(self, try_import_mock):
+        try_import_mock.return_value = None
+
+        self.assertRaises(
+            ValueError, base.get_driver,
+            "messaging://", project="project", service="service",
+            host="host", context={})
 
-        messaging = mock.MagicMock()
+    @mock.patch("oslo_utils.importutils.try_import")
+    def test_init_and_notify(self, try_import_mock):
         context = "context"
         transport = "transport"
         project = "project"
         service = "service"
         host = "host"
 
+        # emulate dynamic load of oslo.messaging library
+        oslo_messaging_mock = mock.Mock()
+        try_import_mock.return_value = oslo_messaging_mock
+
+        # mock oslo.messaging APIs
+        notifier_mock = mock.Mock()
+        oslo_messaging_mock.Notifier.return_value = notifier_mock
+        oslo_messaging_mock.get_notification_transport.return_value = transport
+
         notify_func = base.get_driver(
-            "messaging://", messaging, context, transport,
-            project, service, host).notify
+            "messaging://", project=project, service=service,
+            context=context, host=host).notify
 
-        messaging.Notifier.assert_called_once_with(
+        oslo_messaging_mock.Notifier.assert_called_once_with(
             transport, publisher_id=host, driver="messaging",
             topics=["profiler"], retry=0)
 
@@ -46,10 +63,10 @@
         }
         notify_func(info)
 
-        messaging.Notifier().info.assert_called_once_with(
+        notifier_mock.info.assert_called_once_with(
             context, "profiler.service", info)
 
-        messaging.reset_mock()
+        notifier_mock.reset_mock()
         notify_func(info, context="my_context")
-        messaging.Notifier().info.assert_called_once_with(
+        notifier_mock.info.assert_called_once_with(
             "my_context", "profiler.service", info)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osprofiler-1.11.0/osprofiler/tests/unit/test_initializer.py 
new/osprofiler-1.14.0/osprofiler/tests/unit/test_initializer.py
--- old/osprofiler-1.11.0/osprofiler/tests/unit/test_initializer.py     
1970-01-01 01:00:00.000000000 +0100
+++ new/osprofiler-1.14.0/osprofiler/tests/unit/test_initializer.py     
2017-11-13 16:29:18.000000000 +0100
@@ -0,0 +1,43 @@
+#    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.
+
+import mock
+import testtools
+
+from osprofiler import initializer
+
+
+class InitializerTestCase(testtools.TestCase):
+
+    @mock.patch("osprofiler.notifier.set")
+    @mock.patch("osprofiler.notifier.create")
+    @mock.patch("osprofiler.web.enable")
+    def test_initializer(self, web_enable_mock, notifier_create_mock,
+                         notifier_set_mock):
+        conf = mock.Mock()
+        conf.profiler.connection_string = "driver://"
+        conf.profiler.hmac_keys = "hmac_keys"
+        context = {}
+        project = "my-project"
+        service = "my-service"
+        host = "my-host"
+
+        notifier_mock = mock.Mock()
+        notifier_create_mock.return_value = notifier_mock
+
+        initializer.init_from_conf(conf, context, project, service, host)
+
+        notifier_create_mock.assert_called_once_with(
+            "driver://", context=context, project=project, service=service,
+            host=host, conf=conf)
+        notifier_set_mock.assert_called_once_with(notifier_mock)
+        web_enable_mock.assert_called_once_with("hmac_keys")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osprofiler-1.11.0/osprofiler/tests/unit/test_notifier.py 
new/osprofiler-1.14.0/osprofiler/tests/unit/test_notifier.py
--- old/osprofiler-1.11.0/osprofiler/tests/unit/test_notifier.py        
2017-07-18 15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/tests/unit/test_notifier.py        
2017-11-13 16:29:18.000000000 +0100
@@ -22,7 +22,7 @@
 class NotifierTestCase(test.TestCase):
 
     def tearDown(self):
-        notifier.__notifier = notifier._noop_notifier
+        notifier.set(notifier._noop_notifier)  # restore defaults
         super(NotifierTestCase, self).tearDown()
 
     def test_set(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osprofiler-1.11.0/osprofiler/tests/unit/test_profiler.py 
new/osprofiler-1.14.0/osprofiler/tests/unit/test_profiler.py
--- old/osprofiler-1.11.0/osprofiler/tests/unit/test_profiler.py        
2017-07-18 15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/tests/unit/test_profiler.py        
2017-11-13 16:29:18.000000000 +0100
@@ -171,7 +171,7 @@
 
 
 @profiler.trace("function", info={"info": "some_info"})
-def tracede_func(i):
+def traced_func(i):
     return i
 
 
@@ -180,6 +180,16 @@
     return (a, i)
 
 
+@profiler.trace("foo", hide_args=True)
+def test_fn_exc():
+    raise ValueError()
+
+
+@profiler.trace("hide_result", hide_result=False)
+def trace_with_result_func(a, i=10):
+    return (a, i)
+
+
 class TraceDecoratorTestCase(test.TestCase):
 
     @mock.patch("osprofiler.profiler.stop")
@@ -198,11 +208,11 @@
     @mock.patch("osprofiler.profiler.stop")
     @mock.patch("osprofiler.profiler.start")
     def test_with_args(self, mock_start, mock_stop):
-        self.assertEqual(1, tracede_func(1))
+        self.assertEqual(1, traced_func(1))
         expected_info = {
             "info": "some_info",
             "function": {
-                "name": "osprofiler.tests.unit.test_profiler.tracede_func",
+                "name": "osprofiler.tests.unit.test_profiler.traced_func",
                 "args": str((1,)),
                 "kwargs": str({})
             }
@@ -223,6 +233,41 @@
         mock_start.assert_called_once_with("hide_args", info=expected_info)
         mock_stop.assert_called_once_with()
 
+    @mock.patch("osprofiler.profiler.stop")
+    @mock.patch("osprofiler.profiler.start")
+    def test_with_exception(self, mock_start, mock_stop):
+
+        self.assertRaises(ValueError, test_fn_exc)
+        expected_info = {
+            "function": {
+                "name": "osprofiler.tests.unit.test_profiler.test_fn_exc"
+            }
+        }
+        expected_stop_info = {"etype": "ValueError"}
+        mock_start.assert_called_once_with("foo", info=expected_info)
+        mock_stop.assert_called_once_with(info=expected_stop_info)
+
+    @mock.patch("osprofiler.profiler.stop")
+    @mock.patch("osprofiler.profiler.start")
+    def test_with_result(self, mock_start, mock_stop):
+        self.assertEqual((1, 2), trace_with_result_func(1, i=2))
+        start_info = {
+            "function": {
+                "name": "osprofiler.tests.unit.test_profiler"
+                        ".trace_with_result_func",
+                "args": str((1,)),
+                "kwargs": str({"i": 2})
+            }
+        }
+
+        stop_info = {
+            "function": {
+                "result": str((1, 2))
+            }
+        }
+        mock_start.assert_called_once_with("hide_result", info=start_info)
+        mock_stop.assert_called_once_with(info=stop_info)
+
 
 class FakeTracedCls(object):
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osprofiler-1.11.0/osprofiler/tests/unit/test_sqlalchemy.py 
new/osprofiler-1.14.0/osprofiler/tests/unit/test_sqlalchemy.py
--- old/osprofiler-1.11.0/osprofiler/tests/unit/test_sqlalchemy.py      
2017-07-18 15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler/tests/unit/test_sqlalchemy.py      
2017-11-13 16:29:18.000000000 +0100
@@ -37,9 +37,43 @@
         handler(mock.MagicMock(), 1, 2, 3, 4, 5)
         mock_profiler.stop.assert_called_once_with()
 
+    @mock.patch("osprofiler.sqlalchemy.profiler")
+    def test_after_execute_with_sql_result(self, mock_profiler):
+        handler = sqlalchemy._after_cursor_execute(hide_result=False)
+        cursor = mock.MagicMock()
+        cursor._rows = (1,)
+        handler(1, cursor, 2, 3, 4, 5)
+        info = {
+            "db": {
+                "result": str(cursor._rows)
+            }
+        }
+        mock_profiler.stop.assert_called_once_with(info=info)
+
+    @mock.patch("osprofiler.sqlalchemy.profiler")
+    def test_handle_error(self, mock_profiler):
+        original_exception = Exception("error")
+        chained_exception = Exception("error and the reason")
+
+        sqlalchemy_exception_ctx = mock.MagicMock()
+        sqlalchemy_exception_ctx.original_exception = original_exception
+        sqlalchemy_exception_ctx.chained_exception = chained_exception
+
+        sqlalchemy.handle_error(sqlalchemy_exception_ctx)
+        expected_info = {
+            "etype": "Exception",
+            "db": {
+                "original_exception": str(original_exception),
+                "chained_exception": str(chained_exception),
+            }
+        }
+        mock_profiler.stop.assert_called_once_with(info=expected_info)
+
+    @mock.patch("osprofiler.sqlalchemy.handle_error")
     @mock.patch("osprofiler.sqlalchemy._before_cursor_execute")
     @mock.patch("osprofiler.sqlalchemy._after_cursor_execute")
-    def test_add_tracing(self, mock_after_exc, mock_before_exc):
+    def test_add_tracing(self, mock_after_exc, mock_before_exc,
+                         mock_handle_error):
         sa = mock.MagicMock()
         engine = mock.MagicMock()
 
@@ -49,16 +83,20 @@
         sqlalchemy.add_tracing(sa, engine, "sql")
 
         mock_before_exc.assert_called_once_with("sql")
-        mock_after_exc.assert_called_once_with()
+        # Default set hide_result=True
+        mock_after_exc.assert_called_once_with(hide_result=True)
         expected_calls = [
             mock.call(engine, "before_cursor_execute", "before"),
-            mock.call(engine, "after_cursor_execute", "after")
+            mock.call(engine, "after_cursor_execute", "after"),
+            mock.call(engine, "handle_error", mock_handle_error),
         ]
         self.assertEqual(sa.event.listen.call_args_list, expected_calls)
 
+    @mock.patch("osprofiler.sqlalchemy.handle_error")
     @mock.patch("osprofiler.sqlalchemy._before_cursor_execute")
     @mock.patch("osprofiler.sqlalchemy._after_cursor_execute")
-    def test_wrap_session(self, mock_after_exc, mock_before_exc):
+    def test_wrap_session(self, mock_after_exc, mock_before_exc,
+                          mock_handle_error):
         sa = mock.MagicMock()
 
         @contextlib.contextmanager
@@ -78,14 +116,40 @@
             pass
 
         mock_before_exc.assert_called_once_with("db")
-        mock_after_exc.assert_called_once_with()
+        # Default set hide_result=True
+        mock_after_exc.assert_called_once_with(hide_result=True)
         expected_calls = [
             mock.call(sess.bind, "before_cursor_execute", "before"),
-            mock.call(sess.bind, "after_cursor_execute", "after")
+            mock.call(sess.bind, "after_cursor_execute", "after"),
+            mock.call(sess.bind, "handle_error", mock_handle_error),
         ]
 
         self.assertEqual(sa.event.listen.call_args_list, expected_calls)
 
+    @mock.patch("osprofiler.sqlalchemy.handle_error")
+    @mock.patch("osprofiler.sqlalchemy._before_cursor_execute")
+    @mock.patch("osprofiler.sqlalchemy._after_cursor_execute")
+    @mock.patch("osprofiler.profiler")
+    def test_with_sql_result(self, mock_profiler, mock_after_exc,
+                             mock_before_exc, mock_handle_error):
+        sa = mock.MagicMock()
+        engine = mock.MagicMock()
+
+        mock_before_exc.return_value = "before"
+        mock_after_exc.return_value = "after"
+
+        sqlalchemy.add_tracing(sa, engine, "sql", hide_result=False)
+
+        mock_before_exc.assert_called_once_with("sql")
+        # Default set hide_result=True
+        mock_after_exc.assert_called_once_with(hide_result=False)
+        expected_calls = [
+            mock.call(engine, "before_cursor_execute", "before"),
+            mock.call(engine, "after_cursor_execute", "after"),
+            mock.call(engine, "handle_error", mock_handle_error),
+        ]
+        self.assertEqual(sa.event.listen.call_args_list, expected_calls)
+
     @mock.patch("osprofiler.sqlalchemy._before_cursor_execute")
     @mock.patch("osprofiler.sqlalchemy._after_cursor_execute")
     def test_disable_and_enable(self, mock_after_exc, mock_before_exc):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler.egg-info/PKG-INFO 
new/osprofiler-1.14.0/osprofiler.egg-info/PKG-INFO
--- old/osprofiler-1.11.0/osprofiler.egg-info/PKG-INFO  2017-07-18 
15:11:04.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler.egg-info/PKG-INFO  2017-11-13 
16:32:10.000000000 +0100
@@ -1,11 +1,12 @@
 Metadata-Version: 1.1
 Name: osprofiler
-Version: 1.11.0
+Version: 1.14.0
 Summary: OpenStack Profiler Library
 Home-page: https://docs.openstack.org/osprofiler/latest/
 Author: OpenStack
 Author-email: openstack-...@lists.openstack.org
 License: UNKNOWN
+Description-Content-Type: UNKNOWN
 Description: ========================
         Team and repository tags
         ========================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler.egg-info/SOURCES.txt 
new/osprofiler-1.14.0/osprofiler.egg-info/SOURCES.txt
--- old/osprofiler-1.11.0/osprofiler.egg-info/SOURCES.txt       2017-07-18 
15:11:04.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler.egg-info/SOURCES.txt       2017-11-13 
16:32:11.000000000 +0100
@@ -69,6 +69,7 @@
 osprofiler/tests/functional/config.cfg
 osprofiler/tests/functional/test_driver.py
 osprofiler/tests/unit/__init__.py
+osprofiler/tests/unit/test_initializer.py
 osprofiler/tests/unit/test_notifier.py
 osprofiler/tests/unit/test_opts.py
 osprofiler/tests/unit/test_profiler.py
@@ -91,6 +92,7 @@
 releasenotes/source/conf.py
 releasenotes/source/index.rst
 releasenotes/source/ocata.rst
+releasenotes/source/pike.rst
 releasenotes/source/unreleased.rst
 releasenotes/source/_static/.placeholder
 releasenotes/source/_templates/.placeholder
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler.egg-info/pbr.json 
new/osprofiler-1.14.0/osprofiler.egg-info/pbr.json
--- old/osprofiler-1.11.0/osprofiler.egg-info/pbr.json  2017-07-18 
15:11:04.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler.egg-info/pbr.json  2017-11-13 
16:32:10.000000000 +0100
@@ -1 +1 @@
-{"git_version": "ba4732d", "is_release": true}
\ No newline at end of file
+{"git_version": "ffd8d7d", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/osprofiler.egg-info/requires.txt 
new/osprofiler-1.14.0/osprofiler.egg-info/requires.txt
--- old/osprofiler-1.11.0/osprofiler.egg-info/requires.txt      2017-07-18 
15:11:04.000000000 +0200
+++ new/osprofiler-1.14.0/osprofiler.egg-info/requires.txt      2017-11-13 
16:32:10.000000000 +0100
@@ -1,6 +1,4 @@
 six>=1.9.0
-oslo.messaging>=5.2.0
-oslo.log>=3.11.0
 oslo.utils>=3.16.0
 WebOb>=1.6.0
 requests>=2.10.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/releasenotes/source/index.rst 
new/osprofiler-1.14.0/releasenotes/source/index.rst
--- old/osprofiler-1.11.0/releasenotes/source/index.rst 2017-07-18 
15:08:28.000000000 +0200
+++ new/osprofiler-1.14.0/releasenotes/source/index.rst 2017-11-13 
16:29:18.000000000 +0100
@@ -6,4 +6,5 @@
     :maxdepth: 1
 
     unreleased
+    pike
     ocata
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/releasenotes/source/pike.rst 
new/osprofiler-1.14.0/releasenotes/source/pike.rst
--- old/osprofiler-1.11.0/releasenotes/source/pike.rst  1970-01-01 
01:00:00.000000000 +0100
+++ new/osprofiler-1.14.0/releasenotes/source/pike.rst  2017-11-13 
16:29:18.000000000 +0100
@@ -0,0 +1,6 @@
+===================================
+ Pike Series Release Notes
+===================================
+
+.. release-notes::
+   :branch: stable/pike
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osprofiler-1.11.0/requirements.txt 
new/osprofiler-1.14.0/requirements.txt
--- old/osprofiler-1.11.0/requirements.txt      2017-07-18 15:08:28.000000000 
+0200
+++ new/osprofiler-1.14.0/requirements.txt      2017-11-13 16:29:18.000000000 
+0100
@@ -1,6 +1,4 @@
 six>=1.9.0 # MIT
-oslo.messaging>=5.2.0 # Apache-2.0
-oslo.log>=3.11.0 # Apache-2.0
 oslo.utils>=3.16.0 # Apache-2.0
 WebOb>=1.6.0 # MIT
 requests>=2.10.0 # Apache-2.0


Reply via email to