Skip to content

Commit c68ce46

Browse files
authored
Add Global Error Handler (#1080)
1 parent a71d383 commit c68ce46

File tree

19 files changed

+712
-0
lines changed

19 files changed

+712
-0
lines changed

docs/examples/error_hander/README.rst

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
Global Error Handler
2+
====================
3+
4+
Overview
5+
--------
6+
7+
This example shows how to use the global error handler.
8+
9+
10+
Preparation
11+
-----------
12+
13+
This example will be executed in a separate virtual environment:
14+
15+
.. code:: sh
16+
17+
$ mkdir global_error_handler
18+
$ virtualenv global_error_handler
19+
$ source global_error_handler/bin/activate
20+
21+
Installation
22+
------------
23+
24+
Here we install first ``opentelemetry-sdk``, the only dependency. Afterwards, 2
25+
error handlers are installed: ``error_handler_0`` will handle
26+
``ZeroDivisionError`` exceptions, ``error_handler_1`` will handle
27+
``IndexError`` and ``KeyError`` exceptions.
28+
29+
.. code:: sh
30+
31+
$ pip install opentelemetry-sdk
32+
$ git clone https://github.com/open-telemetry/opentelemetry-python.git
33+
$ pip install -e opentelemetry-python/docs/examples/error_handler/error_handler_0
34+
$ pip install -e opentelemetry-python/docs/examples/error_handler/error_handler_1
35+
36+
Execution
37+
---------
38+
39+
An example is provided in the
40+
``opentelemetry-python/docs/examples/error_handler/example.py``.
41+
42+
You can just run it, you should get output similar to this one:
43+
44+
.. code:: pytb
45+
46+
ErrorHandler0 handling a ZeroDivisionError
47+
Traceback (most recent call last):
48+
File "test.py", line 5, in <module>
49+
1 / 0
50+
ZeroDivisionError: division by zero
51+
52+
ErrorHandler1 handling an IndexError
53+
Traceback (most recent call last):
54+
File "test.py", line 11, in <module>
55+
[1][2]
56+
IndexError: list index out of range
57+
58+
ErrorHandler1 handling a KeyError
59+
Traceback (most recent call last):
60+
File "test.py", line 17, in <module>
61+
{1: 2}[2]
62+
KeyError: 2
63+
64+
Error handled by default error handler:
65+
Traceback (most recent call last):
66+
File "test.py", line 23, in <module>
67+
assert False
68+
AssertionError
69+
70+
No error raised
71+
72+
The ``opentelemetry-sdk.error_handler`` module includes documentation that
73+
explains how this works. We recommend you read it also, here is just a small
74+
summary.
75+
76+
In ``example.py`` we use ``GlobalErrorHandler`` as a context manager in several
77+
places, for example:
78+
79+
80+
.. code:: python
81+
82+
with GlobalErrorHandler():
83+
{1: 2}[2]
84+
85+
Running that code will raise a ``KeyError`` exception.
86+
``GlobalErrorHandler`` will "capture" that exception and pass it down to the
87+
registered error handlers. If there is one that handles ``KeyError`` exceptions
88+
then it will handle it. That can be seen in the result of the execution of
89+
``example.py``:
90+
91+
.. code::
92+
93+
ErrorHandler1 handling a KeyError
94+
Traceback (most recent call last):
95+
File "test.py", line 17, in <module>
96+
{1: 2}[2]
97+
KeyError: 2
98+
99+
There is no registered error handler that can handle ``AssertionError``
100+
exceptions so this kind of errors are handled by the default error handler
101+
which just logs the exception to standard logging, as seen here:
102+
103+
.. code::
104+
105+
Error handled by default error handler:
106+
Traceback (most recent call last):
107+
File "test.py", line 23, in <module>
108+
assert False
109+
AssertionError
110+
111+
When no exception is raised, the code inside the scope of
112+
``GlobalErrorHandler`` is exectued normally:
113+
114+
.. code::
115+
116+
No error raised
117+
118+
Users can create Python packages that provide their own custom error handlers
119+
and install them in their virtual environments before running their code which
120+
instantiates ``GlobalErrorHandler`` context managers. ``error_handler_0`` and
121+
``error_handler_1`` can be used as examples to create these custom error
122+
handlers.
123+
124+
In order for the error handlers to be registered, they need to create a class
125+
that inherits from ``opentelemetry.sdk.error_handler.ErrorHandler`` and at
126+
least one ``Exception``-type class. For example, this is an error handler that
127+
handles ``ZeroDivisionError`` exceptions:
128+
129+
.. code:: python
130+
131+
from opentelemetry.sdk.error_handler import ErrorHandler
132+
from logging import getLogger
133+
134+
logger = getLogger(__name__)
135+
136+
137+
class ErrorHandler0(ErrorHandler, ZeroDivisionError):
138+
139+
def handle(self, error: Exception, *args, **kwargs):
140+
141+
logger.exception("ErrorHandler0 handling a ZeroDivisionError")
142+
143+
To register this error handler, use the ``opentelemetry_error_handler`` entry
144+
point in the setup of the error handler package:
145+
146+
.. code::
147+
148+
[options.entry_points]
149+
opentelemetry_error_handler =
150+
error_handler_0 = error_handler_0:ErrorHandler0
151+
152+
This entry point should point to the error handler class, ``ErrorHandler0`` in
153+
this case.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Error Handler 0
2+
===============
3+
4+
This is just an error handler for this example.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Copyright The OpenTelemetry 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+
[metadata]
16+
name = error-handler-0
17+
description = This is just an error handler example package
18+
author = OpenTelemetry Authors
19+
author_email = [email protected]
20+
platforms = any
21+
license = Apache-2.0
22+
classifiers =
23+
Development Status :: 4 - Beta
24+
Intended Audience :: Developers
25+
License :: OSI Approved :: Apache Software License
26+
Programming Language :: Python
27+
Programming Language :: Python :: 3
28+
Programming Language :: Python :: 3.5
29+
Programming Language :: Python :: 3.6
30+
Programming Language :: Python :: 3.7
31+
Programming Language :: Python :: 3.8
32+
33+
[options]
34+
python_requires = >=3.5
35+
package_dir=
36+
=src
37+
packages=find_namespace:
38+
install_requires =
39+
opentelemetry-sdk == 0.14.dev0
40+
41+
[options.packages.find]
42+
where = src
43+
44+
[options.entry_points]
45+
opentelemetry_error_handler =
46+
error_handler_0 = error_handler_0:ErrorHandler0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright The OpenTelemetry 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+
import os
15+
16+
import setuptools
17+
18+
BASE_DIR = os.path.dirname(__file__)
19+
VERSION_FILENAME = os.path.join(
20+
BASE_DIR, "src", "error_handler_0", "version.py"
21+
)
22+
PACKAGE_INFO = {}
23+
with open(VERSION_FILENAME) as f:
24+
exec(f.read(), PACKAGE_INFO)
25+
26+
setuptools.setup(version=PACKAGE_INFO["__version__"])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright The OpenTelemetry 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 logging import getLogger
16+
17+
from opentelemetry.sdk.error_handler import ErrorHandler
18+
19+
logger = getLogger(__name__)
20+
21+
22+
class ErrorHandler0(ErrorHandler, ZeroDivisionError):
23+
def _handle(self, error: Exception, *args, **kwargs):
24+
25+
logger.exception("ErrorHandler0 handling a ZeroDivisionError")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright The OpenTelemetry 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+
__version__ = "0.14.dev0"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Error Handler 1
2+
===============
3+
4+
This is just an error handler for this example.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Copyright The OpenTelemetry 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+
[metadata]
16+
name = error_handler_1
17+
description = This is just an error handler example package
18+
author = OpenTelemetry Authors
19+
author_email = [email protected]
20+
platforms = any
21+
license = Apache-2.0
22+
classifiers =
23+
Development Status :: 4 - Beta
24+
Intended Audience :: Developers
25+
License :: OSI Approved :: Apache Software License
26+
Programming Language :: Python
27+
Programming Language :: Python :: 3
28+
Programming Language :: Python :: 3.5
29+
Programming Language :: Python :: 3.6
30+
Programming Language :: Python :: 3.7
31+
Programming Language :: Python :: 3.8
32+
33+
[options]
34+
python_requires = >=3.5
35+
package_dir=
36+
=src
37+
packages=find_namespace:
38+
install_requires =
39+
opentelemetry-sdk == 0.14.dev0
40+
41+
[options.packages.find]
42+
where = src
43+
44+
[options.entry_points]
45+
opentelemetry_error_handler =
46+
error_handler_1 = error_handler_1:ErrorHandler1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright The OpenTelemetry 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+
import os
15+
16+
import setuptools
17+
18+
BASE_DIR = os.path.dirname(__file__)
19+
VERSION_FILENAME = os.path.join(
20+
BASE_DIR, "src", "error_handler_1", "version.py"
21+
)
22+
PACKAGE_INFO = {}
23+
with open(VERSION_FILENAME) as f:
24+
exec(f.read(), PACKAGE_INFO)
25+
26+
setuptools.setup(version=PACKAGE_INFO["__version__"])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright The OpenTelemetry 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 logging import getLogger
16+
17+
from opentelemetry.sdk.error_handler import ErrorHandler
18+
19+
logger = getLogger(__name__)
20+
21+
22+
# pylint: disable=too-many-ancestors
23+
class ErrorHandler1(ErrorHandler, IndexError, KeyError):
24+
def _handle(self, error: Exception, *args, **kwargs):
25+
26+
if isinstance(error, IndexError):
27+
logger.exception("ErrorHandler1 handling an IndexError")
28+
29+
elif isinstance(error, KeyError):
30+
logger.exception("ErrorHandler1 handling a KeyError")

0 commit comments

Comments
 (0)