From 650defaf4647559f3857c9e2bbe8608b61e8060d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl>
Date: Wed, 5 Aug 2020 17:14:46 +0200
Subject: [PATCH] add trace_future

---
 CHANGELOG.md                    |  2 ++
 docs/index.rst                  |  1 +
 docs/opentracing.rst            | 10 +++++++++
 satella/__init__.py             |  2 +-
 satella/opentracing/__init__.py |  3 +++
 satella/opentracing/trace.py    | 37 +++++++++++++++++++++++++++++++++
 setup.py                        |  3 ++-
 7 files changed, 56 insertions(+), 2 deletions(-)
 create mode 100644 docs/opentracing.rst
 create mode 100644 satella/opentracing/__init__.py
 create mode 100644 satella/opentracing/trace.py

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 07382368..6ca1434d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,2 +1,4 @@
 # v2.9.15
 
+* add `trace_future`
+
diff --git a/docs/index.rst b/docs/index.rst
index 4c0f60fc..73a6aae6 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -30,6 +30,7 @@ Visit the project's page at GitHub_!
            exceptions
            processes
            cassandra
+           opentracing
 
 
 Indices and tables
diff --git a/docs/opentracing.rst b/docs/opentracing.rst
new file mode 100644
index 00000000..8cf8cd5c
--- /dev/null
+++ b/docs/opentracing.rst
@@ -0,0 +1,10 @@
+**This module is available only if you have opentracing installed**
+
+OpenTracing
+===========
+
+trace_future
+------------
+
+.. autofunction:: satella.opentracing.trace_future
+
diff --git a/satella/__init__.py b/satella/__init__.py
index de249f24..392a9ae7 100644
--- a/satella/__init__.py
+++ b/satella/__init__.py
@@ -1 +1 @@
-__version__ = '2.9.15_a1'
+__version__ = '2.9.15_a2'
diff --git a/satella/opentracing/__init__.py b/satella/opentracing/__init__.py
new file mode 100644
index 00000000..5d411434
--- /dev/null
+++ b/satella/opentracing/__init__.py
@@ -0,0 +1,3 @@
+from .trace import trace_future
+
+__all__ = ['trace_future']
diff --git a/satella/opentracing/trace.py b/satella/opentracing/trace.py
new file mode 100644
index 00000000..81be1cd7
--- /dev/null
+++ b/satella/opentracing/trace.py
@@ -0,0 +1,37 @@
+import typing as tp
+from concurrent.futures import Future
+try:
+    from opentracing import Span
+except ImportError:
+    class Span:
+        pass
+
+try:
+    from cassandra.cluster import ResponseFuture
+except ImportError:
+    class ResponseFuture:
+        pass
+
+
+def trace_future(future: tp.Union[ResponseFuture, Future], span: Span):
+    """
+    Install a handler that will close a span upon a future completing, attaching the exception
+    contents if the future ends with an exception.
+
+    :param future: can be either a normal Future or a Cassandra's ResponseFuture
+    :param span: span to close
+    """
+    if isinstance(future, ResponseFuture):
+        def close_exception(exc):
+            Span._on_error(span, type(exc), exc, '<unavailable>')
+            span.finish()
+
+        future.add_callback(span.finish)
+        future.add_errback(close_exception)
+    else:
+        def close_future(fut):
+            exc = fut.exception()
+            if exc is not None:
+                Span._on_error(span, type(exc), exc, '<unavailable>')
+            span.finish()
+        future.add_done_callback(close_future)
diff --git a/setup.py b/setup.py
index e43515d9..729eeac1 100644
--- a/setup.py
+++ b/setup.py
@@ -15,6 +15,7 @@ setup(keywords=['ha', 'high availability', 'scalable', 'scalability', 'server',
             'YAMLSource': ['pyyaml'],
             'TOMLSource': ['toml'],
             'FasterJSONSource': ['ujson'],
-            'cassandra': ['cassandra-driver']
+            'cassandra': ['cassandra-driver'],
+            'opentracing': ['opentracing']
       }
       )
-- 
GitLab