{"action":"created","comment":{"url":"https://api.github.com/repos/opentracing/opentracing-python/pulls/comments/125200979","pull_request_review_id":47567596,"id":125200979,"diff_hunk":"@@ -228,3 +223,58 @@ def log(self, **kwargs):\n         if 'timestamp' in kwargs:\n             timestamp = kwargs['timestamp']\n         return self.log_kv(key_values, timestamp)\n+\n+\n+class ContinuationMixin(object):\n+    \"\"\"\n+    Continuation mixin that provides additional primitives to a `Span` class,\n+    so that it can be deactivated and resumed later during in-process\n+    propagation.\n+\n+    If the application needs to defer work that should be part of the same\n+    `Span`, the `ContinuationMixin` provides a `capture` method that increments\n+    a counter to the span so that it can be deactivated without finishing. In\n+    another asynchronous executor and/or thread, it can be resumed.\n+    \"\"\"\n+    def capture(self):\n+        \"\"\"\n+        Capture the `Span` tracing session as well as any 3rd-party execution\n+        context of interest. After calling this method, the `Span` may be used\n+        later in a closure or callback function where it may be resumed and\n+        reactivated using the tracer `active_span_source.make_active()`.\n+\n+        IMPORTANT: the caller MUST activate and then deactivate the `Span`\n+        otherwise it will never automatically finish. That is, calling\n+        `capture()` increments a refcount that must be decremented somewhere\n+        else.\n+        \"\"\"\n+        pass\n+\n+    def deactivate(self):\n+        \"\"\"\n+        Mark the end of the active period for the current `Span` in this\n+        asynchronous executor and/or thread. When the last refcount has been\n+        decremented through `deactivate()`, it is automatically finished.\n+\n+        NOTE: Calling `deactivate()` more than once on a single `Span` instance\n+        leads to undefined behavior.\n+        \"\"\"\n+        self.finish()\n+\n+\n+class Span(ContinuationMixin, BaseSpan):","path":"opentracing/span.py","position":95,"original_position":95,"commit_id":"2bfff7b0305479811452ce1ce4b062abce4c8360","original_commit_id":"2bfff7b0305479811452ce1ce4b062abce4c8360","user":{"login":"carlosalberto","id":260065,"avatar_url":"https://avatars2.githubusercontent.com/u/260065?v=3","gravatar_id":"","url":"https://api.github.com/users/carlosalberto","html_url":"https://github.com/carlosalberto","followers_url":"https://api.github.com/users/carlosalberto/followers","following_url":"https://api.github.com/users/carlosalberto/following{/other_user}","gists_url":"https://api.github.com/users/carlosalberto/gists{/gist_id}","starred_url":"https://api.github.com/users/carlosalberto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/carlosalberto/subscriptions","organizations_url":"https://api.github.com/users/carlosalberto/orgs","repos_url":"https://api.github.com/users/carlosalberto/repos","events_url":"https://api.github.com/users/carlosalberto/events{/privacy}","received_events_url":"https://api.github.com/users/carlosalberto/received_events","type":"User","site_admin":false},"body":"@bhs @palazzem Upon further research while preparing test cases and test scenarios, I came upon a few things to add here:\r\n\r\nWhen it comes to the `to_restore` part, the only place where I can actually see that happening is when using a thread pool (through `concurrent.futures`), as at least both Gevent/asyncio keep their context-locals new for each new task, no no need to restore anything. \r\n\r\nAnd for the mentioned thread pool, observe threads *do not* get suspended/reactivated (as I suspect happens for Java+Futures+ExecutorService or C#+async). So in theory you would always get a thread that *doesn't need* to keep its previous state (`Continuation` objects would still be needed, though, of course).\r\n\r\nThat being said:\r\n\r\n1) Most of the time the user wouldn't simply need to do a capture/activate cycle, for both the async frameworks and the multi threaded approaches. And when the user needs it, `Continuation` can be available, and any slightly usability issue around it is probably fine at that point. \r\n2) If we were to provide an `ActiveSpan` just as Java does (say, for sanity purposes on restoring *any* previous data), how much would it actually impact the most common scenarios? Since `ActiveSpan` is basically a proxy, and the main difference is the `finish` vs `deactivate` methods (which are meant to be used through a context manager) is not such a big burden on the API IHMO.","created_at":"2017-07-03T02:17:32Z","updated_at":"2017-07-03T02:17:32Z","html_url":"https://github.com/opentracing/opentracing-python/pull/52#discussion_r125200979","pull_request_url":"https://api.github.com/repos/opentracing/opentracing-python/pulls/52","_links":{"self":{"href":"https://api.github.com/repos/opentracing/opentracing-python/pulls/comments/125200979"},"html":{"href":"https://github.com/opentracing/opentracing-python/pull/52#discussion_r125200979"},"pull_request":{"href":"https://api.github.com/repos/opentracing/opentracing-python/pulls/52"}}},"pull_request":{"url":"https://api.github.com/repos/opentracing/opentracing-python/pulls/52","id":124920689,"html_url":"https://github.com/opentracing/opentracing-python/pull/52","diff_url":"https://github.com/opentracing/opentracing-python/pull/52.diff","patch_url":"https://github.com/opentracing/opentracing-python/pull/52.patch","issue_url":"https://api.github.com/repos/opentracing/opentracing-python/issues/52","number":52,"state":"open","locked":false,"title":"ActiveSpanSource for in-process context propagation","user":{"login":"palazzem","id":1560405,"avatar_url":"https://avatars1.githubusercontent.com/u/1560405?v=3","gravatar_id":"","url":"https://api.github.com/users/palazzem","html_url":"https://github.com/palazzem","followers_url":"https://api.github.com/users/palazzem/followers","following_url":"https://api.github.com/users/palazzem/following{/other_user}","gists_url":"https://api.github.com/users/palazzem/gists{/gist_id}","starred_url":"https://api.github.com/users/palazzem/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palazzem/subscriptions","organizations_url":"https://api.github.com/users/palazzem/orgs","repos_url":"https://api.github.com/users/palazzem/repos","events_url":"https://api.github.com/users/palazzem/events{/privacy}","received_events_url":"https://api.github.com/users/palazzem/received_events","type":"User","site_admin":false},"body":"### Overview\r\n\r\nThis PR aims to solve in-process context propagation fro Python. It has three aims:\r\n\r\n- adding a simple, high level API that allows very simple tracing that will handle 90% of use cases\r\n- a low-level API that allows more control for tracing complex async operations\r\n- a pluggable interface that allows tracing async operations with all the common frameworks - threads, asyncio, tornado, etc\r\n\r\nImplementation details may be discussed here: https://github.com/opentracing/basictracer-python/pull/23\r\n\r\nWe'd like to keep two types of feedback separate - nomenclature vs structural. If everybody agrees on the structure / semantics of the PR, then we can debate naming and nomenclature. Cool?\r\n\r\n### Details\r\n\r\nThe main idea is having one or more specific `ActiveSpanSource` implementations that keeps track of the current active `Span` so that the high-level API provides:\r\n\r\n```python\r\nwith tracer.start_active_span(\"web.request\") as span:\r\n    span.set_tag(\"url\", \"/home\")\r\n    data = get_data()\r\n\r\n    with tracer.start_active_span(\"template.render\"):\r\n        return \"%s\" % (data)\r\n```\r\n\r\nWhen more control is needed, we can interact with the current active `Span` stack, see examples below:\r\n* Propagation when callbacks are used ([link][8])\r\n* Fake server implementation that executes asynchronous jobs ([link][1])\r\n* Propagation between different threads ([link][2])\r\n* Propagation in `asyncio` ([link][3])\r\n* Propagation in `gevent` ([link][4])\r\n* Propagation in Tornado using a `StackContext` ([link][5])\r\n\r\nNote: we might want to include these in an official OT library or helper module at some point ---^\r\n\r\nThis API is flexible when handling some edge cases that could happen in simple or complex applications. Currently, `asyncio`, `gevent`, Tornado and threading are supported with [specific implementations][6] and with some [helpers][7] that may become part of some `opentracing-contrib-*` package.\r\n\r\n### Nomenclature Questions\r\n\r\n- this assumes that we want to leave `start_span` untouched. In an ideal world, I think `start_active_span` should be the method used 99% of the time, so we should consider using something shorter / cleaner here like `start_span`, `span` or `trace`. \r\n\r\nWhat's missing and that will be completed after an initial review:\r\n* [ ] tests for the `ActiveSpanSource` API\r\n* [x] `start_span` must be a `@deprecated` function (at the moment it has been fully replaced by `start_manual_span(...)`. or can we use `start_span` all the time?\r\n* [ ] instrument a real complex application before merging\r\n* [ ] update the documentation providing both manual and automatic propagation\r\n\r\n[1]: https://github.com/palazzem/ot-examples/blob/master/examples/server.py\r\n[2]: https://github.com/palazzem/ot-examples/blob/master/examples/threads.py\r\n[3]: https://github.com/palazzem/ot-examples/blob/master/examples/asyncio.py\r\n[4]: https://github.com/palazzem/ot-examples/blob/master/examples/gevent.py\r\n[5]: https://github.com/palazzem/ot-examples/blob/master/examples/tornado.py\r\n[6]: https://github.com/palazzem/ot-examples/blob/master/ext/active_span_source.py\r\n[7]: https://github.com/palazzem/ot-examples/blob/master/ext/helpers.py\r\n[8]: https://gist.github.com/palazzem/270648ac5e15dc2b71de54f8e941b4ba","created_at":"2017-06-09T18:04:13Z","updated_at":"2017-07-03T02:17:32Z","closed_at":null,"merged_at":null,"merge_commit_sha":"76cb126660a8caf932a7ec48cd5ca1b1c518bb0e","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/opentracing/opentracing-python/pulls/52/commits","review_comments_url":"https://api.github.com/repos/opentracing/opentracing-python/pulls/52/comments","review_comment_url":"https://api.github.com/repos/opentracing/opentracing-python/pulls/comments{/number}","comments_url":"https://api.github.com/repos/opentracing/opentracing-python/issues/52/comments","statuses_url":"https://api.github.com/repos/opentracing/opentracing-python/statuses/2bfff7b0305479811452ce1ce4b062abce4c8360","head":{"label":"palazzem:palazzem/context-propagation","ref":"palazzem/context-propagation","sha":"2bfff7b0305479811452ce1ce4b062abce4c8360","user":{"login":"palazzem","id":1560405,"avatar_url":"https://avatars1.githubusercontent.com/u/1560405?v=3","gravatar_id":"","url":"https://api.github.com/users/palazzem","html_url":"https://github.com/palazzem","followers_url":"https://api.github.com/users/palazzem/followers","following_url":"https://api.github.com/users/palazzem/following{/other_user}","gists_url":"https://api.github.com/users/palazzem/gists{/gist_id}","starred_url":"https://api.github.com/users/palazzem/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palazzem/subscriptions","organizations_url":"https://api.github.com/users/palazzem/orgs","repos_url":"https://api.github.com/users/palazzem/repos","events_url":"https://api.github.com/users/palazzem/events{/privacy}","received_events_url":"https://api.github.com/users/palazzem/received_events","type":"User","site_admin":false},"repo":{"id":93884208,"name":"opentracing-python","full_name":"palazzem/opentracing-python","owner":{"login":"palazzem","id":1560405,"avatar_url":"https://avatars1.githubusercontent.com/u/1560405?v=3","gravatar_id":"","url":"https://api.github.com/users/palazzem","html_url":"https://github.com/palazzem","followers_url":"https://api.github.com/users/palazzem/followers","following_url":"https://api.github.com/users/palazzem/following{/other_user}","gists_url":"https://api.github.com/users/palazzem/gists{/gist_id}","starred_url":"https://api.github.com/users/palazzem/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palazzem/subscriptions","organizations_url":"https://api.github.com/users/palazzem/orgs","repos_url":"https://api.github.com/users/palazzem/repos","events_url":"https://api.github.com/users/palazzem/events{/privacy}","received_events_url":"https://api.github.com/users/palazzem/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/palazzem/opentracing-python","description":"OpenTracing API for Python","fork":true,"url":"https://api.github.com/repos/palazzem/opentracing-python","forks_url":"https://api.github.com/repos/palazzem/opentracing-python/forks","keys_url":"https://api.github.com/repos/palazzem/opentracing-python/keys{/key_id}","collaborators_url":"https://api.github.com/repos/palazzem/opentracing-python/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/palazzem/opentracing-python/teams","hooks_url":"https://api.github.com/repos/palazzem/opentracing-python/hooks","issue_events_url":"https://api.github.com/repos/palazzem/opentracing-python/issues/events{/number}","events_url":"https://api.github.com/repos/palazzem/opentracing-python/events","assignees_url":"https://api.github.com/repos/palazzem/opentracing-python/assignees{/user}","branches_url":"https://api.github.com/repos/palazzem/opentracing-python/branches{/branch}","tags_url":"https://api.github.com/repos/palazzem/opentracing-python/tags","blobs_url":"https://api.github.com/repos/palazzem/opentracing-python/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/palazzem/opentracing-python/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/palazzem/opentracing-python/git/refs{/sha}","trees_url":"https://api.github.com/repos/palazzem/opentracing-python/git/trees{/sha}","statuses_url":"https://api.github.com/repos/palazzem/opentracing-python/statuses/{sha}","languages_url":"https://api.github.com/repos/palazzem/opentracing-python/languages","stargazers_url":"https://api.github.com/repos/palazzem/opentracing-python/stargazers","contributors_url":"https://api.github.com/repos/palazzem/opentracing-python/contributors","subscribers_url":"https://api.github.com/repos/palazzem/opentracing-python/subscribers","subscription_url":"https://api.github.com/repos/palazzem/opentracing-python/subscription","commits_url":"https://api.github.com/repos/palazzem/opentracing-python/commits{/sha}","git_commits_url":"https://api.github.com/repos/palazzem/opentracing-python/git/commits{/sha}","comments_url":"https://api.github.com/repos/palazzem/opentracing-python/comments{/number}","issue_comment_url":"https://api.github.com/repos/palazzem/opentracing-python/issues/comments{/number}","contents_url":"https://api.github.com/repos/palazzem/opentracing-python/contents/{+path}","compare_url":"https://api.github.com/repos/palazzem/opentracing-python/compare/{base}...{head}","merges_url":"https://api.github.com/repos/palazzem/opentracing-python/merges","archive_url":"https://api.github.com/repos/palazzem/opentracing-python/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/palazzem/opentracing-python/downloads","issues_url":"https://api.github.com/repos/palazzem/opentracing-python/issues{/number}","pulls_url":"https://api.github.com/repos/palazzem/opentracing-python/pulls{/number}","milestones_url":"https://api.github.com/repos/palazzem/opentracing-python/milestones{/number}","notifications_url":"https://api.github.com/repos/palazzem/opentracing-python/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/palazzem/opentracing-python/labels{/name}","releases_url":"https://api.github.com/repos/palazzem/opentracing-python/releases{/id}","deployments_url":"https://api.github.com/repos/palazzem/opentracing-python/deployments","created_at":"2017-06-09T18:00:07Z","updated_at":"2017-06-09T18:00:08Z","pushed_at":"2017-06-25T17:15:36Z","git_url":"git://github.com/palazzem/opentracing-python.git","ssh_url":"git@github.com:palazzem/opentracing-python.git","clone_url":"https://github.com/palazzem/opentracing-python.git","svn_url":"https://github.com/palazzem/opentracing-python","homepage":"http://opentracing.io","size":209,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"opentracing:master","ref":"master","sha":"a86ee3d49df569691433e0ce0101105638ca8be8","user":{"login":"opentracing","id":15482765,"avatar_url":"https://avatars2.githubusercontent.com/u/15482765?v=3","gravatar_id":"","url":"https://api.github.com/users/opentracing","html_url":"https://github.com/opentracing","followers_url":"https://api.github.com/users/opentracing/followers","following_url":"https://api.github.com/users/opentracing/following{/other_user}","gists_url":"https://api.github.com/users/opentracing/gists{/gist_id}","starred_url":"https://api.github.com/users/opentracing/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/opentracing/subscriptions","organizations_url":"https://api.github.com/users/opentracing/orgs","repos_url":"https://api.github.com/users/opentracing/repos","events_url":"https://api.github.com/users/opentracing/events{/privacy}","received_events_url":"https://api.github.com/users/opentracing/received_events","type":"Organization","site_admin":false},"repo":{"id":49166869,"name":"opentracing-python","full_name":"opentracing/opentracing-python","owner":{"login":"opentracing","id":15482765,"avatar_url":"https://avatars2.githubusercontent.com/u/15482765?v=3","gravatar_id":"","url":"https://api.github.com/users/opentracing","html_url":"https://github.com/opentracing","followers_url":"https://api.github.com/users/opentracing/followers","following_url":"https://api.github.com/users/opentracing/following{/other_user}","gists_url":"https://api.github.com/users/opentracing/gists{/gist_id}","starred_url":"https://api.github.com/users/opentracing/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/opentracing/subscriptions","organizations_url":"https://api.github.com/users/opentracing/orgs","repos_url":"https://api.github.com/users/opentracing/repos","events_url":"https://api.github.com/users/opentracing/events{/privacy}","received_events_url":"https://api.github.com/users/opentracing/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/opentracing/opentracing-python","description":"OpenTracing API for Python","fork":false,"url":"https://api.github.com/repos/opentracing/opentracing-python","forks_url":"https://api.github.com/repos/opentracing/opentracing-python/forks","keys_url":"https://api.github.com/repos/opentracing/opentracing-python/keys{/key_id}","collaborators_url":"https://api.github.com/repos/opentracing/opentracing-python/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/opentracing/opentracing-python/teams","hooks_url":"https://api.github.com/repos/opentracing/opentracing-python/hooks","issue_events_url":"https://api.github.com/repos/opentracing/opentracing-python/issues/events{/number}","events_url":"https://api.github.com/repos/opentracing/opentracing-python/events","assignees_url":"https://api.github.com/repos/opentracing/opentracing-python/assignees{/user}","branches_url":"https://api.github.com/repos/opentracing/opentracing-python/branches{/branch}","tags_url":"https://api.github.com/repos/opentracing/opentracing-python/tags","blobs_url":"https://api.github.com/repos/opentracing/opentracing-python/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/opentracing/opentracing-python/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/opentracing/opentracing-python/git/refs{/sha}","trees_url":"https://api.github.com/repos/opentracing/opentracing-python/git/trees{/sha}","statuses_url":"https://api.github.com/repos/opentracing/opentracing-python/statuses/{sha}","languages_url":"https://api.github.com/repos/opentracing/opentracing-python/languages","stargazers_url":"https://api.github.com/repos/opentracing/opentracing-python/stargazers","contributors_url":"https://api.github.com/repos/opentracing/opentracing-python/contributors","subscribers_url":"https://api.github.com/repos/opentracing/opentracing-python/subscribers","subscription_url":"https://api.github.com/repos/opentracing/opentracing-python/subscription","commits_url":"https://api.github.com/repos/opentracing/opentracing-python/commits{/sha}","git_commits_url":"https://api.github.com/repos/opentracing/opentracing-python/git/commits{/sha}","comments_url":"https://api.github.com/repos/opentracing/opentracing-python/comments{/number}","issue_comment_url":"https://api.github.com/repos/opentracing/opentracing-python/issues/comments{/number}","contents_url":"https://api.github.com/repos/opentracing/opentracing-python/contents/{+path}","compare_url":"https://api.github.com/repos/opentracing/opentracing-python/compare/{base}...{head}","merges_url":"https://api.github.com/repos/opentracing/opentracing-python/merges","archive_url":"https://api.github.com/repos/opentracing/opentracing-python/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/opentracing/opentracing-python/downloads","issues_url":"https://api.github.com/repos/opentracing/opentracing-python/issues{/number}","pulls_url":"https://api.github.com/repos/opentracing/opentracing-python/pulls{/number}","milestones_url":"https://api.github.com/repos/opentracing/opentracing-python/milestones{/number}","notifications_url":"https://api.github.com/repos/opentracing/opentracing-python/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/opentracing/opentracing-python/labels{/name}","releases_url":"https://api.github.com/repos/opentracing/opentracing-python/releases{/id}","deployments_url":"https://api.github.com/repos/opentracing/opentracing-python/deployments","created_at":"2016-01-06T22:57:00Z","updated_at":"2017-07-03T01:46:02Z","pushed_at":"2017-06-25T17:15:37Z","git_url":"git://github.com/opentracing/opentracing-python.git","ssh_url":"git@github.com:opentracing/opentracing-python.git","clone_url":"https://github.com/opentracing/opentracing-python.git","svn_url":"https://github.com/opentracing/opentracing-python","homepage":"http://opentracing.io","size":185,"stargazers_count":183,"watchers_count":183,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":23,"mirror_url":null,"open_issues_count":5,"forks":23,"open_issues":5,"watchers":183,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/opentracing/opentracing-python/pulls/52"},"html":{"href":"https://github.com/opentracing/opentracing-python/pull/52"},"issue":{"href":"https://api.github.com/repos/opentracing/opentracing-python/issues/52"},"comments":{"href":"https://api.github.com/repos/opentracing/opentracing-python/issues/52/comments"},"review_comments":{"href":"https://api.github.com/repos/opentracing/opentracing-python/pulls/52/comments"},"review_comment":{"href":"https://api.github.com/repos/opentracing/opentracing-python/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/opentracing/opentracing-python/pulls/52/commits"},"statuses":{"href":"https://api.github.com/repos/opentracing/opentracing-python/statuses/2bfff7b0305479811452ce1ce4b062abce4c8360"}}}}
{"actor":{"display_login":"carlosalberto"}}