Skip to content
This repository was archived by the owner on Sep 17, 2025. It is now read-only.

Commit 9179476

Browse files
aberresreyang
authored andcommitted
Add package to provide gevent compatibiliy (#636)
Introduce opencensus-ext-gevent package.
1 parent 56d3d64 commit 9179476

12 files changed

Lines changed: 242 additions & 0 deletions

File tree

README.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ OpenCensus supports integration with popular web frameworks, client libraries an
185185

186186
- `Django`_
187187
- `Flask`_
188+
- `gevent`_
188189
- `Google Cloud Client Libraries`_
189190
- `gRPC`_
190191
- `httplib`_
@@ -216,6 +217,7 @@ Stats Exporter
216217
.. _Azure: https://github.com/census-instrumentation/opencensus-python/tree/master/contrib/opencensus-ext-azure
217218
.. _Django: https://github.com/census-instrumentation/opencensus-python/tree/master/contrib/opencensus-ext-django
218219
.. _Flask: https://github.com/census-instrumentation/opencensus-python/tree/master/contrib/opencensus-ext-flask
220+
.. _gevent: https://github.com/census-instrumentation/opencensus-python/tree/master/contrib/opencensus-ext-gevent
219221
.. _Google Cloud Client Libraries: https://github.com/census-instrumentation/opencensus-python/tree/master/contrib/opencensus-ext-google-cloud-clientlibs
220222
.. _gRPC: https://github.com/census-instrumentation/opencensus-python/tree/master/contrib/opencensus-ext-grpc
221223
.. _httplib: https://github.com/census-instrumentation/opencensus-python/tree/master/contrib/opencensus-ext-httplib
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Changelog
2+
3+
## Unreleased
4+
5+
- Initial version
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
OpenCensus gevent helper
2+
============================================================================
3+
4+
|pypi|
5+
6+
.. |pypi| image:: https://badge.fury.io/py/opencensus-ext-gevent.svg
7+
:target: https://pypi.org/project/opencensus-ext-gevent/
8+
9+
Installation
10+
------------
11+
12+
::
13+
14+
pip install opencensus-ext-gevent
15+
16+
Usage
17+
-----
18+
19+
As gevent is to date `incompatible <https://github.com/gevent/gevent/issues/1407>`_ with
20+
the new context variables the **OpenCensus gevent helper** configures OpenCensus to use
21+
a compatible thread based runtime context implementation.
22+
23+
No action apart from installing the package is needed as it listens to events
24+
`emitted by gevent <http://www.gevent.org/api/gevent.monkey.html#plugins>`_ once
25+
patching via ``patch_all`` is complete.
26+
27+
28+
Warning
29+
-------
30+
31+
OpenCensus itself is completely compatible with gevent. Be aware though that not all
32+
available OpenCensus integrations are compatible.
33+
34+
You should check this on a case by case basis.
35+
36+
37+
References
38+
----------
39+
40+
* `OpenCensus Project <https://opencensus.io/>`_
41+
* `gevent <https://www.gevent.org/>`_
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import logging
2+
import gevent.monkey
3+
4+
5+
def patch_opencensus(event):
6+
# Switch from the default runtime context using ContextVar to one
7+
# using thread locals. Needed until gevent supports ContextVar.
8+
# See https://github.com/gevent/gevent/issues/1407
9+
import opencensus.common.runtime_context as runtime_context
10+
11+
if not gevent.monkey.is_module_patched("contextvars"):
12+
runtime_context.RuntimeContext = (
13+
runtime_context._ThreadLocalRuntimeContext()
14+
)
15+
16+
logging.warning("OpenCensus patched for gevent compatibility")
17+
else:
18+
logging.warning(
19+
"OpenCensus is already compatible with your gevent version. "
20+
"Feel free to uninstall the opencensus-ext-gevent package."
21+
)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[bdist_wheel]
2+
universal = 1
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright 2019, OpenCensus Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from setuptools import find_packages
16+
from setuptools import setup
17+
from version import __version__
18+
19+
setup(
20+
name='opencensus-ext-gevent',
21+
version=__version__, # noqa
22+
author='OpenCensus Authors',
23+
author_email='census-developers@googlegroups.com',
24+
classifiers=[
25+
'Intended Audience :: Developers',
26+
'Development Status :: 3 - Alpha',
27+
'Intended Audience :: Developers',
28+
'License :: OSI Approved :: Apache Software License',
29+
'Programming Language :: Python',
30+
'Programming Language :: Python :: 2',
31+
'Programming Language :: Python :: 2.7',
32+
'Programming Language :: Python :: 3',
33+
'Programming Language :: Python :: 3.4',
34+
'Programming Language :: Python :: 3.5',
35+
'Programming Language :: Python :: 3.6',
36+
'Programming Language :: Python :: 3.7',
37+
],
38+
description='OpenCensus gevent compatibility helper',
39+
include_package_data=True,
40+
long_description=open('README.rst').read(),
41+
install_requires=[
42+
'opencensus >= 0.6.dev0, < 1.0.0',
43+
'gevent >= 1.3'
44+
],
45+
extras_require={},
46+
license='Apache-2.0',
47+
packages=find_packages(exclude=('tests',)),
48+
namespace_packages=[],
49+
url='https://github.com/census-instrumentation/opencensus-python/tree/master/contrib/opencensus-ext-gevent', # noqa: E501
50+
zip_safe=False,
51+
entry_points={
52+
"gevent.plugins.monkey.did_patch_builtins": [
53+
"opencensus = opencensus.ext.gevent.geventcompatibility:patch_opencensus" # noqa: E501
54+
]
55+
},
56+
)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Copyright 2019, OpenCensus Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import unittest
16+
17+
import opencensus.common.runtime_context as runtime_context
18+
import gevent.monkey
19+
20+
import mock
21+
22+
23+
class TestPatching(unittest.TestCase):
24+
def setUp(self):
25+
self.original_context = runtime_context.RuntimeContext
26+
27+
def tearDown(self):
28+
runtime_context.RuntimeContext = self.original_context
29+
30+
@mock.patch("gevent.monkey.is_module_patched", return_value=False)
31+
def test_context_is_switched_without_contextvar_support(
32+
self, patched_is_module_patched
33+
):
34+
# patched_is_module_patched.return_value = False
35+
36+
# Trick gevent into thinking it is run for the first time.
37+
# Allows to run multiple tests.
38+
gevent.monkey.saved = {}
39+
40+
# All module patching is disabled to avoid the need of "unpatching".
41+
# The needed events are emitted nevertheless.
42+
gevent.monkey.patch_all(
43+
contextvar=False,
44+
socket=False,
45+
dns=False,
46+
time=False,
47+
select=False,
48+
thread=False,
49+
os=False,
50+
ssl=False,
51+
httplib=False,
52+
subprocess=False,
53+
sys=False,
54+
aggressive=False,
55+
Event=False,
56+
builtins=False,
57+
signal=False,
58+
queue=False
59+
)
60+
61+
assert isinstance(
62+
runtime_context.RuntimeContext,
63+
runtime_context._ThreadLocalRuntimeContext,
64+
)
65+
66+
@mock.patch("gevent.monkey.is_module_patched", return_value=True)
67+
def test_context_is_switched_with_contextvar_support(
68+
self, patched_is_module_patched
69+
):
70+
71+
# Trick gevent into thinking it is run for the first time.
72+
# Allows to run multiple tests.
73+
gevent.monkey.saved = {}
74+
75+
# All module patching is disabled to avoid the need of "unpatching".
76+
# The needed events are emitted nevertheless.
77+
gevent.monkey.patch_all(
78+
contextvar=False,
79+
socket=False,
80+
dns=False,
81+
time=False,
82+
select=False,
83+
thread=False,
84+
os=False,
85+
ssl=False,
86+
httplib=False,
87+
subprocess=False,
88+
sys=False,
89+
aggressive=False,
90+
Event=False,
91+
builtins=False,
92+
signal=False,
93+
queue=False
94+
)
95+
96+
assert runtime_context.RuntimeContext is self.original_context

0 commit comments

Comments
 (0)