From 052323348365ed81c899657dcaed33c98fed6d0b Mon Sep 17 00:00:00 2001 From: Alex Boten Date: Tue, 28 Apr 2020 13:54:58 -0700 Subject: [PATCH 01/19] infra: reduce build time by running longest job early --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b531cfb3384..999abc7f43e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,12 @@ language: python cache: pip python: + - 'pypy3' + - '3.8' - '3.4' - '3.5' - '3.6' - '3.7' - - '3.8' - - 'pypy3' #matrix: # allow_failures: From 99600e27eaddb137d312d4b94c93ce5a161dabff Mon Sep 17 00:00:00 2001 From: Alex Boten Date: Tue, 28 Apr 2020 15:19:21 -0700 Subject: [PATCH 02/19] don't run flake on generated code --- .flake8 | 1 + 1 file changed, 1 insertion(+) diff --git a/.flake8 b/.flake8 index 0c2204782fc..5922f31d8f3 100644 --- a/.flake8 +++ b/.flake8 @@ -18,3 +18,4 @@ exclude = ext/opentelemetry-ext-jaeger/src/opentelemetry/ext/jaeger/gen/ ext/opentelemetry-ext-jaeger/build/* docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/grpc/gen/ + docs/examples/opentelemetry-example-app/build/* From 4adf1bbf011e4c793e06c1104ae54f25e1ee2084 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 8 Apr 2020 22:49:11 -0600 Subject: [PATCH 03/19] Fix the auto instrumentation command Fixes #566 --- docs/examples/auto-instrumentation/README.md | 2 +- .../auto_instrumentation.py | 20 ++++++------- .../auto_instrumentation/sitecustomize.py | 28 +++++++++++++++++++ 3 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/sitecustomize.py diff --git a/docs/examples/auto-instrumentation/README.md b/docs/examples/auto-instrumentation/README.md index 46b0b44b2c8..c3c2728489a 100644 --- a/docs/examples/auto-instrumentation/README.md +++ b/docs/examples/auto-instrumentation/README.md @@ -92,7 +92,7 @@ Span(name="serv_request", context=SpanContext(trace_id=0x9c0e0ce8f7b7dbb51d1d6e7 Now, kill the execution of `server_instrumented.py` with `ctrl + c` and run this instead: ```sh -$ opentelemetry-auto-instrumentation opentelemetry-python/opentelemetry-auto-instrumentation/example/server_uninstrumented.py +$ opentelemetry-auto-instrumentation python opentelemetry-python/opentelemetry-auto-instrumentation/example/server_uninstrumented.py ``` In the console where you previously executed `client.py`, run again this again: diff --git a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py index 00ccf6a0ea9..086bf1dabbe 100644 --- a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py +++ b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py @@ -15,22 +15,22 @@ # limitations under the License. from logging import getLogger -from runpy import run_path +from os import environ, execl +from os.path import abspath, dirname, pathsep +from shutil import which from sys import argv -from pkg_resources import iter_entry_points - logger = getLogger(__file__) def run() -> None: - for entry_point in iter_entry_points("opentelemetry_instrumentor"): - try: - entry_point.load()().instrument() # type: ignore - logger.debug("Instrumented %s", entry_point.name) + python_path = environ.get("PYTHONPATH", "") + filedir_path = dirname(abspath(__file__)) + + if filedir_path not in python_path: + environ["PYTHONPATH"] = pathsep.join([filedir_path, python_path]) - except Exception: # pylint: disable=broad-except - logger.exception("Instrumenting of %s failed", entry_point.name) + executable = which(argv[1]) - run_path(argv[1], run_name="__main__") # type: ignore + execl(executable, executable, *argv[2:]) diff --git a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/sitecustomize.py b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/sitecustomize.py new file mode 100644 index 00000000000..b070bf5d773 --- /dev/null +++ b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/sitecustomize.py @@ -0,0 +1,28 @@ +# Copyright The OpenTelemetry Authors +# +# 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. + +from logging import getLogger + +from pkg_resources import iter_entry_points + +logger = getLogger(__file__) + + +for entry_point in iter_entry_points("opentelemetry_instrumentor"): + try: + entry_point.load()().instrument() # type: ignore + logger.debug("Instrumented %s", entry_point.name) + + except Exception: # pylint: disable=broad-except + logger.exception("Instrumenting of %s failed", entry_point.name) From 80d716738bb2f8da4d7fc5cc7d9323c482191bf2 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 17 Apr 2020 22:14:50 -0600 Subject: [PATCH 04/19] Make sure filedir is at the beginning of PYTHONPATH --- .../auto_instrumentation.py | 12 ++++-- .../tests/test_instrumentor.py | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py index 086bf1dabbe..584e17d567e 100644 --- a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py +++ b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py @@ -25,11 +25,17 @@ def run() -> None: - python_path = environ.get("PYTHONPATH", "") + python_path = environ.get("PYTHONPATH", []) + + if python_path: + python_path = python_path.split(pathsep) + filedir_path = dirname(abspath(__file__)) - if filedir_path not in python_path: - environ["PYTHONPATH"] = pathsep.join([filedir_path, python_path]) + if filedir_path in python_path: + python_path.remove(filedir_path) + + environ["PYTHONPATH"] = pathsep.join([filedir_path, *python_path]) executable = which(argv[1]) diff --git a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py index 40e762230af..3f4b62fac85 100644 --- a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py +++ b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py @@ -14,8 +14,12 @@ # type: ignore from logging import WARNING +from os import environ +from os.path import abspath, dirname, pathsep from unittest import TestCase +from unittest.mock import patch +from opentelemetry.auto_instrumentation import auto_instrumentation from opentelemetry.auto_instrumentation.instrumentor import BaseInstrumentor @@ -44,3 +48,41 @@ def test_protect(self): def test_singleton(self): self.assertIs(self.Instrumentor(), self.Instrumentor()) + + +class TestRun(TestCase): + auto_instrumentation_path = dirname(abspath(auto_instrumentation.__file__)) + + @patch.dict("os.environ", {"PYTHONPATH": ""}) + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.argv") + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") + def test_run_empty( + self, mock_execl, mock_argv + ): # pylint: disable=unused-argument + auto_instrumentation.run() + assert environ["PYTHONPATH"] == self.auto_instrumentation_path + + @patch.dict("os.environ", {"PYTHONPATH": "abc"}) + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.argv") + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") + def test_run_non_empty( + self, mock_execl, mock_argv + ): # pylint: disable=unused-argument + auto_instrumentation.run() + assert environ["PYTHONPATH"] == pathsep.join( + [self.auto_instrumentation_path, "abc"] + ) + + @patch.dict( + "os.environ", + {"PYTHONPATH": pathsep.join(["abc", auto_instrumentation_path])}, + ) + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.argv") + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") + def test_run_after_path( + self, mock_execl, mock_argv + ): # pylint: disable=unused-argument + auto_instrumentation.run() + assert environ["PYTHONPATH"] == pathsep.join( + [self.auto_instrumentation_path, "abc"] + ) From b18b3cf1b7ccc0d883dacb9061509cbccdf87b95 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Sat, 18 Apr 2020 16:00:47 -0600 Subject: [PATCH 05/19] Make the tests pass --- .../auto_instrumentation/auto_instrumentation.py | 7 ++++++- .../tests/test_instrumentor.py | 9 ++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py index 584e17d567e..b6fa16dfcc8 100644 --- a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py +++ b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py @@ -27,6 +27,9 @@ def run() -> None: python_path = environ.get("PYTHONPATH", []) + if not python_path: + python_path = [] + if python_path: python_path = python_path.split(pathsep) @@ -35,7 +38,9 @@ def run() -> None: if filedir_path in python_path: python_path.remove(filedir_path) - environ["PYTHONPATH"] = pathsep.join([filedir_path, *python_path]) + python_path.insert(0, filedir_path) + + environ["PYTHONPATH"] = pathsep.join(python_path) executable = which(argv[1]) diff --git a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py index 3f4b62fac85..1588b3be797 100644 --- a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py +++ b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py @@ -56,8 +56,9 @@ class TestRun(TestCase): @patch.dict("os.environ", {"PYTHONPATH": ""}) @patch("opentelemetry.auto_instrumentation.auto_instrumentation.argv") @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.which") def test_run_empty( - self, mock_execl, mock_argv + self, mock_which, mock_execl, mock_argv ): # pylint: disable=unused-argument auto_instrumentation.run() assert environ["PYTHONPATH"] == self.auto_instrumentation_path @@ -65,8 +66,9 @@ def test_run_empty( @patch.dict("os.environ", {"PYTHONPATH": "abc"}) @patch("opentelemetry.auto_instrumentation.auto_instrumentation.argv") @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.which") def test_run_non_empty( - self, mock_execl, mock_argv + self, mock_which, mock_execl, mock_argv ): # pylint: disable=unused-argument auto_instrumentation.run() assert environ["PYTHONPATH"] == pathsep.join( @@ -79,8 +81,9 @@ def test_run_non_empty( ) @patch("opentelemetry.auto_instrumentation.auto_instrumentation.argv") @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.which") def test_run_after_path( - self, mock_execl, mock_argv + self, mock_which, mock_execl, mock_argv ): # pylint: disable=unused-argument auto_instrumentation.run() assert environ["PYTHONPATH"] == pathsep.join( From 038a1de9d98ad3db4ec00315948a92af0ccb6555 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Sat, 18 Apr 2020 16:04:26 -0600 Subject: [PATCH 06/19] Updating documentation --- .../src/opentelemetry/auto_instrumentation/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/__init__.py b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/__init__.py index adfb4fd461d..0d8d7dff271 100644 --- a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/__init__.py +++ b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/__init__.py @@ -20,9 +20,9 @@ :: - opentelemetry-auto-instrumentation program.py + opentelemetry-auto-instrumentation python program.py The code in ``program.py`` needs to use one of the packages for which there is -an OpenTelemetry extension. For a list of the available extensions please check -`here `_. +an OpenTelemetry integration. For a list of the available integrations please +check `here `_. """ From 82ac06c9208431f9b245b3583b5aa9f61797823e Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 23 Apr 2020 16:46:31 -0600 Subject: [PATCH 07/19] Fix assertions --- .../tests/test_instrumentor.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py index 1588b3be797..311b011374f 100644 --- a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py +++ b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py @@ -61,7 +61,7 @@ def test_run_empty( self, mock_which, mock_execl, mock_argv ): # pylint: disable=unused-argument auto_instrumentation.run() - assert environ["PYTHONPATH"] == self.auto_instrumentation_path + self.assertEqual(environ["PYTHONPATH"], self.auto_instrumentation_path) @patch.dict("os.environ", {"PYTHONPATH": "abc"}) @patch("opentelemetry.auto_instrumentation.auto_instrumentation.argv") @@ -71,8 +71,11 @@ def test_run_non_empty( self, mock_which, mock_execl, mock_argv ): # pylint: disable=unused-argument auto_instrumentation.run() - assert environ["PYTHONPATH"] == pathsep.join( - [self.auto_instrumentation_path, "abc"] + self.assertEqual( + environ["PYTHONPATH"], + pathsep.join( + [self.auto_instrumentation_path, "abc"] + ) ) @patch.dict( @@ -86,6 +89,8 @@ def test_run_after_path( self, mock_which, mock_execl, mock_argv ): # pylint: disable=unused-argument auto_instrumentation.run() - assert environ["PYTHONPATH"] == pathsep.join( - [self.auto_instrumentation_path, "abc"] + self.assertEqual( + environ["PYTHONPATH"] == pathsep.join( + [self.auto_instrumentation_path, "abc"] + ) ) From fc9a1069d22c52de2b818eca9440b80b7ea14d30 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 23 Apr 2020 16:48:48 -0600 Subject: [PATCH 08/19] More fixing --- .../tests/test_instrumentor.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py index 311b011374f..12f16fd6722 100644 --- a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py +++ b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py @@ -75,7 +75,7 @@ def test_run_non_empty( environ["PYTHONPATH"], pathsep.join( [self.auto_instrumentation_path, "abc"] - ) + ), ) @patch.dict( @@ -90,7 +90,8 @@ def test_run_after_path( ): # pylint: disable=unused-argument auto_instrumentation.run() self.assertEqual( - environ["PYTHONPATH"] == pathsep.join( + environ["PYTHONPATH"], + pathsep.join( [self.auto_instrumentation_path, "abc"] - ) + ), ) From d8d4149a3b3f7e079443fa9f8ad1786b3e79576f Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 23 Apr 2020 17:25:23 -0600 Subject: [PATCH 09/19] Add lint fixes --- .../tests/test_instrumentor.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py index 12f16fd6722..c938d7ad668 100644 --- a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py +++ b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py @@ -73,9 +73,7 @@ def test_run_non_empty( auto_instrumentation.run() self.assertEqual( environ["PYTHONPATH"], - pathsep.join( - [self.auto_instrumentation_path, "abc"] - ), + pathsep.join([self.auto_instrumentation_path, "abc"]), ) @patch.dict( @@ -91,7 +89,5 @@ def test_run_after_path( auto_instrumentation.run() self.assertEqual( environ["PYTHONPATH"], - pathsep.join( - [self.auto_instrumentation_path, "abc"] - ), + pathsep.join([self.auto_instrumentation_path, "abc"]), ) From b0f0a84a5a9160c6da8fc1fc7071fc2264aa9a07 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 24 Apr 2020 15:45:17 -0600 Subject: [PATCH 10/19] Add more tests --- .../auto_instrumentation.py | 3 +- .../tests/test_instrumentor.py | 47 ---------- .../tests/test_run.py | 86 +++++++++++++++++++ 3 files changed, 87 insertions(+), 49 deletions(-) create mode 100644 opentelemetry-auto-instrumentation/tests/test_run.py diff --git a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py index b6fa16dfcc8..c1caf733c6a 100644 --- a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py +++ b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py @@ -35,8 +35,7 @@ def run() -> None: filedir_path = dirname(abspath(__file__)) - if filedir_path in python_path: - python_path.remove(filedir_path) + python_path = [path for path in python_path if path != filedir_path] python_path.insert(0, filedir_path) diff --git a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py index c938d7ad668..40e762230af 100644 --- a/opentelemetry-auto-instrumentation/tests/test_instrumentor.py +++ b/opentelemetry-auto-instrumentation/tests/test_instrumentor.py @@ -14,12 +14,8 @@ # type: ignore from logging import WARNING -from os import environ -from os.path import abspath, dirname, pathsep from unittest import TestCase -from unittest.mock import patch -from opentelemetry.auto_instrumentation import auto_instrumentation from opentelemetry.auto_instrumentation.instrumentor import BaseInstrumentor @@ -48,46 +44,3 @@ def test_protect(self): def test_singleton(self): self.assertIs(self.Instrumentor(), self.Instrumentor()) - - -class TestRun(TestCase): - auto_instrumentation_path = dirname(abspath(auto_instrumentation.__file__)) - - @patch.dict("os.environ", {"PYTHONPATH": ""}) - @patch("opentelemetry.auto_instrumentation.auto_instrumentation.argv") - @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") - @patch("opentelemetry.auto_instrumentation.auto_instrumentation.which") - def test_run_empty( - self, mock_which, mock_execl, mock_argv - ): # pylint: disable=unused-argument - auto_instrumentation.run() - self.assertEqual(environ["PYTHONPATH"], self.auto_instrumentation_path) - - @patch.dict("os.environ", {"PYTHONPATH": "abc"}) - @patch("opentelemetry.auto_instrumentation.auto_instrumentation.argv") - @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") - @patch("opentelemetry.auto_instrumentation.auto_instrumentation.which") - def test_run_non_empty( - self, mock_which, mock_execl, mock_argv - ): # pylint: disable=unused-argument - auto_instrumentation.run() - self.assertEqual( - environ["PYTHONPATH"], - pathsep.join([self.auto_instrumentation_path, "abc"]), - ) - - @patch.dict( - "os.environ", - {"PYTHONPATH": pathsep.join(["abc", auto_instrumentation_path])}, - ) - @patch("opentelemetry.auto_instrumentation.auto_instrumentation.argv") - @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") - @patch("opentelemetry.auto_instrumentation.auto_instrumentation.which") - def test_run_after_path( - self, mock_which, mock_execl, mock_argv - ): # pylint: disable=unused-argument - auto_instrumentation.run() - self.assertEqual( - environ["PYTHONPATH"], - pathsep.join([self.auto_instrumentation_path, "abc"]), - ) diff --git a/opentelemetry-auto-instrumentation/tests/test_run.py b/opentelemetry-auto-instrumentation/tests/test_run.py new file mode 100644 index 00000000000..b2af20b40ce --- /dev/null +++ b/opentelemetry-auto-instrumentation/tests/test_run.py @@ -0,0 +1,86 @@ +# Copyright The OpenTelemetry Authors +# +# 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. +# type: ignore + +from os import environ +from os.path import abspath, dirname, pathsep +from unittest import TestCase +from unittest.mock import patch + +from opentelemetry.auto_instrumentation import auto_instrumentation + + +class TestRun(TestCase): + auto_instrumentation_path = dirname(abspath(auto_instrumentation.__file__)) + + @classmethod + def setUpClass(cls): + cls.argv_patcher = patch( + "opentelemetry.auto_instrumentation.auto_instrumentation.argv" + ) + cls.execl_patcher = patch( + "opentelemetry.auto_instrumentation.auto_instrumentation.execl" + ) + cls.which_patcher = patch( + "opentelemetry.auto_instrumentation.auto_instrumentation.which" + ) + + cls.argv_patcher.start() + cls.execl_patcher.start() + cls.which_patcher.start() + + @classmethod + def tearDownClass(cls): + cls.argv_patcher.stop() + cls.execl_patcher.stop() + cls.which_patcher.stop() + + @patch.dict("os.environ", {"PYTHONPATH": ""}) + def test_empty(self): + auto_instrumentation.run() + self.assertEqual(environ["PYTHONPATH"], self.auto_instrumentation_path) + + @patch.dict("os.environ", {"PYTHONPATH": "abc"}) + def test_non_empty(self): + auto_instrumentation.run() + self.assertEqual( + environ["PYTHONPATH"], + pathsep.join([self.auto_instrumentation_path, "abc"]), + ) + + @patch.dict( + "os.environ", + {"PYTHONPATH": pathsep.join(["abc", auto_instrumentation_path])}, + ) + def test_after_path(self): + auto_instrumentation.run() + self.assertEqual( + environ["PYTHONPATH"], + pathsep.join([self.auto_instrumentation_path, "abc"]), + ) + + @patch.dict( + "os.environ", + { + "PYTHONPATH": pathsep.join( + [auto_instrumentation_path, "abc", auto_instrumentation_path] + ) + }, + ) + def test_single_path(self): + auto_instrumentation.run() + self.assertEqual( + environ["PYTHONPATH"], + pathsep.join([self.auto_instrumentation_path, "abc"]), + ) From e3bd21b6cf96560ed60470d423d9405011246f60 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 24 Apr 2020 18:52:55 -0600 Subject: [PATCH 11/19] Adding execl test --- .../tests/test_run.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/opentelemetry-auto-instrumentation/tests/test_run.py b/opentelemetry-auto-instrumentation/tests/test_run.py index b2af20b40ce..baa1254d8de 100644 --- a/opentelemetry-auto-instrumentation/tests/test_run.py +++ b/opentelemetry-auto-instrumentation/tests/test_run.py @@ -84,3 +84,18 @@ def test_single_path(self): environ["PYTHONPATH"], pathsep.join([self.auto_instrumentation_path, "abc"]), ) + + +class TestExecl(TestCase): + @patch( + "opentelemetry.auto_instrumentation.auto_instrumentation.argv", + new=[1, 2, 3] + ) + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.which") + @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") + def test_execl(self, mock_execl, mock_which): + mock_which.configure_mock(**{"return_value": "python"}) + + auto_instrumentation.run() + + mock_execl.assert_called_with("python", "python", 3) From 791eda855010f89a0b5cc0e1d9dff6244feff289 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 24 Apr 2020 19:03:20 -0600 Subject: [PATCH 12/19] Fix conditional --- .../opentelemetry/auto_instrumentation/auto_instrumentation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py index c1caf733c6a..98a5bdd0a60 100644 --- a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py +++ b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py @@ -30,7 +30,7 @@ def run() -> None: if not python_path: python_path = [] - if python_path: + else: python_path = python_path.split(pathsep) filedir_path = dirname(abspath(__file__)) From 1e43a14dbaad30ad65626fa93df65dbd09fc3ced Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 24 Apr 2020 19:06:20 -0600 Subject: [PATCH 13/19] Remove unnecessary argument --- .../opentelemetry/auto_instrumentation/auto_instrumentation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py index 98a5bdd0a60..9cd35b96ed4 100644 --- a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py +++ b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py @@ -25,7 +25,7 @@ def run() -> None: - python_path = environ.get("PYTHONPATH", []) + python_path = environ.get("PYTHONPATH") if not python_path: python_path = [] From f8a654b4c9774e9352d3ee6f39a331e7706c6133 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Sat, 25 Apr 2020 15:26:54 -0600 Subject: [PATCH 14/19] Fix lint --- opentelemetry-auto-instrumentation/tests/test_run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-auto-instrumentation/tests/test_run.py b/opentelemetry-auto-instrumentation/tests/test_run.py index baa1254d8de..2228c91ad05 100644 --- a/opentelemetry-auto-instrumentation/tests/test_run.py +++ b/opentelemetry-auto-instrumentation/tests/test_run.py @@ -89,7 +89,7 @@ def test_single_path(self): class TestExecl(TestCase): @patch( "opentelemetry.auto_instrumentation.auto_instrumentation.argv", - new=[1, 2, 3] + new=[1, 2, 3], ) @patch("opentelemetry.auto_instrumentation.auto_instrumentation.which") @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") From 65d9d6f0fa070be90f5a7d653d7fadf7908099b6 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Sat, 25 Apr 2020 16:13:21 -0600 Subject: [PATCH 15/19] More lint fixing --- opentelemetry-auto-instrumentation/tests/test_run.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/opentelemetry-auto-instrumentation/tests/test_run.py b/opentelemetry-auto-instrumentation/tests/test_run.py index 2228c91ad05..12eeae74611 100644 --- a/opentelemetry-auto-instrumentation/tests/test_run.py +++ b/opentelemetry-auto-instrumentation/tests/test_run.py @@ -93,7 +93,9 @@ class TestExecl(TestCase): ) @patch("opentelemetry.auto_instrumentation.auto_instrumentation.which") @patch("opentelemetry.auto_instrumentation.auto_instrumentation.execl") - def test_execl(self, mock_execl, mock_which): + def test_execl( + self, mock_execl, mock_which + ): # pylint: disable=no-self-use mock_which.configure_mock(**{"return_value": "python"}) auto_instrumentation.run() From 2cbeeff0ff36878d977cd64d412962f441e3208c Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Sat, 25 Apr 2020 18:59:45 -0600 Subject: [PATCH 16/19] Add current working directory --- .../auto_instrumentation/auto_instrumentation.py | 7 ++++++- .../tests/test_run.py | 13 ++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py index 9cd35b96ed4..fedd314f5c9 100644 --- a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py +++ b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py @@ -15,7 +15,7 @@ # limitations under the License. from logging import getLogger -from os import environ, execl +from os import environ, execl, getcwd from os.path import abspath, dirname, pathsep from shutil import which from sys import argv @@ -33,6 +33,11 @@ def run() -> None: else: python_path = python_path.split(pathsep) + cwd_path = getcwd() + + if cwd_path not in python_path: + python_path.insert(0, cwd_path) + filedir_path = dirname(abspath(__file__)) python_path = [path for path in python_path if path != filedir_path] diff --git a/opentelemetry-auto-instrumentation/tests/test_run.py b/opentelemetry-auto-instrumentation/tests/test_run.py index 12eeae74611..8b37882f5b9 100644 --- a/opentelemetry-auto-instrumentation/tests/test_run.py +++ b/opentelemetry-auto-instrumentation/tests/test_run.py @@ -13,7 +13,7 @@ # limitations under the License. # type: ignore -from os import environ +from os import environ, getcwd from os.path import abspath, dirname, pathsep from unittest import TestCase from unittest.mock import patch @@ -49,14 +49,17 @@ def tearDownClass(cls): @patch.dict("os.environ", {"PYTHONPATH": ""}) def test_empty(self): auto_instrumentation.run() - self.assertEqual(environ["PYTHONPATH"], self.auto_instrumentation_path) + self.assertEqual( + environ["PYTHONPATH"], + pathsep.join([self.auto_instrumentation_path, getcwd()]), + ) @patch.dict("os.environ", {"PYTHONPATH": "abc"}) def test_non_empty(self): auto_instrumentation.run() self.assertEqual( environ["PYTHONPATH"], - pathsep.join([self.auto_instrumentation_path, "abc"]), + pathsep.join([self.auto_instrumentation_path, getcwd(), "abc"]), ) @patch.dict( @@ -67,7 +70,7 @@ def test_after_path(self): auto_instrumentation.run() self.assertEqual( environ["PYTHONPATH"], - pathsep.join([self.auto_instrumentation_path, "abc"]), + pathsep.join([self.auto_instrumentation_path, getcwd(), "abc"]), ) @patch.dict( @@ -82,7 +85,7 @@ def test_single_path(self): auto_instrumentation.run() self.assertEqual( environ["PYTHONPATH"], - pathsep.join([self.auto_instrumentation_path, "abc"]), + pathsep.join([self.auto_instrumentation_path, getcwd(), "abc"]), ) From 45542ab157d39a7bdc8dd2d05b8b965bcbee9dfb Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Tue, 28 Apr 2020 17:55:03 -0600 Subject: [PATCH 17/19] Add comment --- .../opentelemetry/auto_instrumentation/auto_instrumentation.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py index fedd314f5c9..893b8939b93 100644 --- a/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py +++ b/opentelemetry-auto-instrumentation/src/opentelemetry/auto_instrumentation/auto_instrumentation.py @@ -35,6 +35,9 @@ def run() -> None: cwd_path = getcwd() + # This is being added to support applications that are being run from their + # own executable, like Django. + # FIXME investigate if there is another way to achieve this if cwd_path not in python_path: python_path.insert(0, cwd_path) From 91a95ea7bcb1166f11feaab1411bc29db2690e6a Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 29 Apr 2020 18:15:03 -0600 Subject: [PATCH 18/19] Update docs/examples/auto-instrumentation/README.md Co-Authored-By: Chris Kleinknecht --- docs/examples/auto-instrumentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/auto-instrumentation/README.md b/docs/examples/auto-instrumentation/README.md index c3c2728489a..94682780746 100644 --- a/docs/examples/auto-instrumentation/README.md +++ b/docs/examples/auto-instrumentation/README.md @@ -92,7 +92,7 @@ Span(name="serv_request", context=SpanContext(trace_id=0x9c0e0ce8f7b7dbb51d1d6e7 Now, kill the execution of `server_instrumented.py` with `ctrl + c` and run this instead: ```sh -$ opentelemetry-auto-instrumentation python opentelemetry-python/opentelemetry-auto-instrumentation/example/server_uninstrumented.py +$ opentelemetry-auto-instrumentation python docs/examples/auto-instrumentation/server_uninstrumented.py ``` In the console where you previously executed `client.py`, run again this again: From 91adb4377598f716cec28c6eb32dfe6b19f10592 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 30 Apr 2020 11:36:42 -0600 Subject: [PATCH 19/19] Fix example --- docs/examples/auto-instrumentation/README.md | 79 ++++++++++++++++--- .../server_instrumented.py | 3 + 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/docs/examples/auto-instrumentation/README.md b/docs/examples/auto-instrumentation/README.md index 94682780746..7ed40f6b96e 100644 --- a/docs/examples/auto-instrumentation/README.md +++ b/docs/examples/auto-instrumentation/README.md @@ -55,11 +55,9 @@ $ source auto_instrumentation/bin/activate # Installation ```sh -$ pip install opentelemetry-api $ pip install opentelemetry-sdk $ pip install opentelemetry-auto-instrumentation -$ pip install ext/opentelemetry-ext-flask -$ pip install flask +$ pip install opentelemetry-ext-flask $ pip install requests ``` @@ -71,20 +69,46 @@ This is done in 2 separate consoles, one to run each of the scripts that make up ```sh $ source auto_instrumentation/bin/activate -$ python opentelemetry-python/opentelemetry-auto-instrumentation/example/server_instrumented.py +$ python opentelemetry-python/docs/examples/auto-instrumentation/server_instrumented.py ``` ```sh $ source auto_instrumentation/bin/activate -$ python opentelemetry-python/opentelemetry-auto-instrumentation/example/client.py testing +$ python opentelemetry-python/docs/examples/auto-instrumentation/client.py testing ``` The execution of `server_instrumented.py` should return an output similar to: ```sh -Hello, testing! -Span(name="serv_request", context=SpanContext(trace_id=0x9c0e0ce8f7b7dbb51d1d6e744a4dad49, span_id=0xd1ba3ec4c76a0d7f, trace_state={}), kind=SpanKind.INTERNAL, parent=None, start_time=2020-03-19T00:06:31.275719Z, end_time=2020-03-19T00:06:31.275920Z) -127.0.0.1 - - [18/Mar/2020 18:06:31] "GET /serv_request?helloStr=Hello%2C+testing%21 HTTP/1.1" 200 - +{ + "name": "server_request", + "context": { + "trace_id": "0xfa002aad260b5f7110db674a9ddfcd23", + "span_id": "0x8b8bbaf3ca9c5131", + "trace_state": "{}" + }, + "kind": "SpanKind.SERVER", + "parent_id": null, + "start_time": "2020-04-30T17:28:57.886397Z", + "end_time": "2020-04-30T17:28:57.886490Z", + "status": { + "canonical_code": "OK" + }, + "attributes": { + "component": "http", + "http.method": "GET", + "http.server_name": "127.0.0.1", + "http.scheme": "http", + "host.port": 8082, + "http.host": "localhost:8082", + "http.target": "/server_request?param=testing", + "net.peer.ip": "127.0.0.1", + "net.peer.port": 52872, + "http.flavor": "1.1" + }, + "events": [], + "links": [] +} ``` ## Execution of an automatically instrumented server @@ -98,15 +122,44 @@ $ opentelemetry-auto-instrumentation python docs/examples/auto-instrumentation/s In the console where you previously executed `client.py`, run again this again: ```sh -$ python opentelemetry-python/opentelemetry-auto-instrumentation/example/client.py testing +$ python opentelemetry-python/docs/examples/auto-instrumentation/client.py testing ``` The execution of `server_uninstrumented.py` should return an output similar to: ```sh -Hello, testing! -Span(name="serv_request", context=SpanContext(trace_id=0xf26b28b5243e48f5f96bfc753f95f3f0, span_id=0xbeb179a095d087ed, trace_state={}), kind=SpanKind.SERVER, parent=, start_time=2020-03-19T00:24:18.828561Z, end_time=2020-03-19T00:24:18.845127Z) -127.0.0.1 - - [18/Mar/2020 18:24:18] "GET /serv_request?helloStr=Hello%2C+testing%21 HTTP/1.1" 200 - +{ + "name": "server_request", + "context": { + "trace_id": "0x9f528e0b76189f539d9c21b1a7a2fc24", + "span_id": "0xd79760685cd4c269", + "trace_state": "{}" + }, + "kind": "SpanKind.SERVER", + "parent_id": "0xb4fb7eee22ef78e4", + "start_time": "2020-04-30T17:10:02.400604Z", + "end_time": "2020-04-30T17:10:02.401858Z", + "status": { + "canonical_code": "OK" + }, + "attributes": { + "component": "http", + "http.method": "GET", + "http.server_name": "127.0.0.1", + "http.scheme": "http", + "host.port": 8082, + "http.host": "localhost:8082", + "http.target": "/server_request?param=testing", + "net.peer.ip": "127.0.0.1", + "net.peer.port": 48240, + "http.flavor": "1.1", + "http.route": "/server_request", + "http.status_text": "OK", + "http.status_code": 200 + }, + "events": [], + "links": [] +} ``` -As you can see, both outputs are equivalentsince the automatic instrumentation does what the manual instrumentation does too. +Both outputs are equivalent since the automatic instrumentation does what the manual instrumentation does too. diff --git a/docs/examples/auto-instrumentation/server_instrumented.py b/docs/examples/auto-instrumentation/server_instrumented.py index 1c78aab15d8..528b107e03c 100644 --- a/docs/examples/auto-instrumentation/server_instrumented.py +++ b/docs/examples/auto-instrumentation/server_instrumented.py @@ -15,6 +15,7 @@ from flask import Flask, request from opentelemetry import propagators, trace +from opentelemetry.ext.wsgi import collect_request_attributes from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( ConsoleSpanExporter, @@ -38,6 +39,8 @@ def server_request(): parent=propagators.extract( lambda dict_, key: dict_.get(key, []), request.headers )["current-span"], + kind=trace.SpanKind.SERVER, + attributes=collect_request_attributes(request.environ), ): print(request.args.get("param")) return "served"