mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-28 12:43:39 +08:00
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -6,7 +6,7 @@ on:
|
|||||||
- 'release/*'
|
- 'release/*'
|
||||||
pull_request:
|
pull_request:
|
||||||
env:
|
env:
|
||||||
CORE_REPO_SHA: c4cdffd0c8bd47b2e5c4f4a823722ca514f10db3
|
CORE_REPO_SHA: e78c9c460c1f1f062032a31f46245d7b1f9cdcd0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.3.0-0.22b0...HEAD)
|
## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.3.0-0.22b0...HEAD)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Move `opentelemetry-instrumentation` to the core repo.
|
||||||
|
([#595](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/595))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- `opentelemetry-instrumentation-tornado` properly instrument work done in tornado on_finish method.
|
- `opentelemetry-instrumentation-tornado` properly instrument work done in tornado on_finish method.
|
||||||
([#499](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/499))
|
([#499](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/499))
|
||||||
|
@ -6,7 +6,7 @@ sphinx-autodoc-typehints
|
|||||||
# doesn't work for pkg_resources.
|
# doesn't work for pkg_resources.
|
||||||
-e "git+https://github.com/open-telemetry/opentelemetry-python.git#egg=opentelemetry-api&subdirectory=opentelemetry-api"
|
-e "git+https://github.com/open-telemetry/opentelemetry-python.git#egg=opentelemetry-api&subdirectory=opentelemetry-api"
|
||||||
-e "git+https://github.com/open-telemetry/opentelemetry-python.git#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions"
|
-e "git+https://github.com/open-telemetry/opentelemetry-python.git#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions"
|
||||||
-e "git+https://github.com/open-telemetry/opentelemetry-python-contrib.git#egg=opentelemetry-instrumentation&subdirectory=opentelemetry-instrumentation"
|
-e "git+https://github.com/open-telemetry/opentelemetry-python.git#egg=opentelemetry-instrumentation&subdirectory=opentelemetry-instrumentation"
|
||||||
-e "git+https://github.com/open-telemetry/opentelemetry-python.git#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk"
|
-e "git+https://github.com/open-telemetry/opentelemetry-python.git#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk"
|
||||||
-e "git+https://github.com/open-telemetry/opentelemetry-python-contrib.git#egg=opentelemetry-util-http&subdirectory=util/opentelemetry-util-http"
|
-e "git+https://github.com/open-telemetry/opentelemetry-python-contrib.git#egg=opentelemetry-util-http&subdirectory=util/opentelemetry-util-http"
|
||||||
|
|
||||||
|
@ -25,7 +25,9 @@ from django.conf import settings
|
|||||||
settings.configure()
|
settings.configure()
|
||||||
|
|
||||||
source_dirs = [
|
source_dirs = [
|
||||||
os.path.abspath("../opentelemetry-instrumentation/src/"),
|
os.path.abspath(
|
||||||
|
"../opentelemetry-python-core/opentelemetry-instrumentation/src/"
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
exp = "../exporter"
|
exp = "../exporter"
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
prune tests
|
|
||||||
graft src
|
|
||||||
global-exclude *.pyc
|
|
||||||
global-exclude *.pyo
|
|
||||||
global-exclude __pycache__/*
|
|
||||||
include MANIFEST.in
|
|
||||||
include README.rst
|
|
@ -1,120 +0,0 @@
|
|||||||
OpenTelemetry Instrumentation
|
|
||||||
=============================
|
|
||||||
|
|
||||||
|pypi|
|
|
||||||
|
|
||||||
.. |pypi| image:: https://badge.fury.io/py/opentelemetry-instrumentation.svg
|
|
||||||
:target: https://pypi.org/project/opentelemetry-instrumentation/
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
pip install opentelemetry-instrumentation
|
|
||||||
|
|
||||||
|
|
||||||
This package provides a couple of commands that help automatically instruments a program:
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
You need to install a distro package to get auto instrumentation working. The ``opentelemetry-distro``
|
|
||||||
package contains the default distro and automatically configures some of the common options for users.
|
|
||||||
For more info about ``opentelemetry-distro`` check `here <https://opentelemetry-python.readthedocs.io/en/latest/examples/distro/README.html>`__
|
|
||||||
::
|
|
||||||
|
|
||||||
pip install opentelemetry-distro[otlp]
|
|
||||||
|
|
||||||
|
|
||||||
opentelemetry-bootstrap
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
opentelemetry-bootstrap --action=install|requirements
|
|
||||||
|
|
||||||
This commands inspects the active Python site-packages and figures out which
|
|
||||||
instrumentation packages the user might want to install. By default it prints out
|
|
||||||
a list of the suggested instrumentation packages which can be added to a requirements.txt
|
|
||||||
file. It also supports installing the suggested packages when run with :code:`--action=install`
|
|
||||||
flag.
|
|
||||||
|
|
||||||
|
|
||||||
opentelemetry-instrument
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
opentelemetry-instrument python program.py
|
|
||||||
|
|
||||||
The instrument command will try to automatically detect packages used by your python program
|
|
||||||
and when possible, apply automatic tracing instrumentation on them. This means your program
|
|
||||||
will get automatic distributed tracing for free without having to make any code changes
|
|
||||||
at all. This will also configure a global tracer and tracing exporter without you having to
|
|
||||||
make any code changes. By default, the instrument command will use the OTLP exporter but
|
|
||||||
this can be overriden when needed.
|
|
||||||
|
|
||||||
The command supports the following configuration options as CLI arguments and environment vars:
|
|
||||||
|
|
||||||
|
|
||||||
* ``--trace-exporter`` or ``OTEL_TRACE_EXPORTER``
|
|
||||||
|
|
||||||
Used to specify which trace exporter to use. Can be set to one or more of the well-known exporter
|
|
||||||
names (see below).
|
|
||||||
|
|
||||||
- Defaults to `otlp`.
|
|
||||||
- Can be set to `none` to disable automatic tracer initialization.
|
|
||||||
|
|
||||||
You can pass multiple values to configure multiple exporters e.g, ``zipkin,prometheus``
|
|
||||||
|
|
||||||
Well known trace exporter names:
|
|
||||||
|
|
||||||
- jaeger
|
|
||||||
- opencensus
|
|
||||||
- otlp
|
|
||||||
- otlp_proto_grpc_span
|
|
||||||
- zipkin
|
|
||||||
|
|
||||||
``otlp`` is an alias for ``otlp_proto_grpc_span``.
|
|
||||||
|
|
||||||
* ``--id-generator`` or ``OTEL_PYTHON_ID_GENERATOR``
|
|
||||||
|
|
||||||
Used to specify which IDs Generator to use for the global Tracer Provider. By default, it
|
|
||||||
will use the random IDs generator.
|
|
||||||
|
|
||||||
The code in ``program.py`` needs to use one of the packages for which there is
|
|
||||||
an OpenTelemetry integration. For a list of the available integrations please
|
|
||||||
check `here <https://opentelemetry-python.readthedocs.io/en/stable/index.html#integrations>`_
|
|
||||||
|
|
||||||
* ``OTEL_PYTHON_DISABLED_INSTRUMENTATIONS``
|
|
||||||
|
|
||||||
If set by the user, opentelemetry-instrument will read this environment variable to disable specific instrumentations.
|
|
||||||
e.g OTEL_PYTHON_DISABLED_INSTRUMENTATIONS = "requests,django"
|
|
||||||
|
|
||||||
|
|
||||||
Examples
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
opentelemetry-instrument --trace-exporter otlp flask run --port=3000
|
|
||||||
|
|
||||||
The above command will pass ``--trace-exporter otlp`` to the instrument command and ``--port=3000`` to ``flask run``.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
opentelemetry-instrument --trace-exporter zipkin,otlp celery -A tasks worker --loglevel=info
|
|
||||||
|
|
||||||
The above command will configure global trace provider, attach zipkin and otlp exporters to it and then
|
|
||||||
start celery with the rest of the arguments.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
opentelemetry-instrument --ids-generator random flask run --port=3000
|
|
||||||
|
|
||||||
The above command will configure the global trace provider to use the Random IDs Generator, and then
|
|
||||||
pass ``--port=3000`` to ``flask run``.
|
|
||||||
|
|
||||||
References
|
|
||||||
----------
|
|
||||||
|
|
||||||
* `OpenTelemetry Project <https://opentelemetry.io/>`_
|
|
@ -1,56 +0,0 @@
|
|||||||
# 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.
|
|
||||||
#
|
|
||||||
[metadata]
|
|
||||||
name = opentelemetry-instrumentation
|
|
||||||
description = Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python
|
|
||||||
long_description = file: README.rst
|
|
||||||
long_description_content_type = text/x-rst
|
|
||||||
author = OpenTelemetry Authors
|
|
||||||
author_email = cncf-opentelemetry-contributors@lists.cncf.io
|
|
||||||
url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/opentelemetry-instrumentation
|
|
||||||
platforms = any
|
|
||||||
license = Apache-2.0
|
|
||||||
classifiers =
|
|
||||||
Development Status :: 4 - Beta
|
|
||||||
Intended Audience :: Developers
|
|
||||||
License :: OSI Approved :: Apache Software License
|
|
||||||
Programming Language :: Python
|
|
||||||
Programming Language :: Python :: 3
|
|
||||||
Programming Language :: Python :: 3.6
|
|
||||||
Programming Language :: Python :: 3.7
|
|
||||||
Programming Language :: Python :: 3.8
|
|
||||||
Programming Language :: Python :: 3.9
|
|
||||||
|
|
||||||
[options]
|
|
||||||
python_requires = >=3.6
|
|
||||||
package_dir=
|
|
||||||
=src
|
|
||||||
packages=find_namespace:
|
|
||||||
zip_safe = False
|
|
||||||
include_package_data = True
|
|
||||||
install_requires =
|
|
||||||
opentelemetry-api ~= 1.3
|
|
||||||
wrapt >= 1.0.0, < 2.0.0
|
|
||||||
|
|
||||||
[options.packages.find]
|
|
||||||
where = src
|
|
||||||
|
|
||||||
[options.entry_points]
|
|
||||||
console_scripts =
|
|
||||||
opentelemetry-instrument = opentelemetry.instrumentation.auto_instrumentation:run
|
|
||||||
opentelemetry-bootstrap = opentelemetry.instrumentation.bootstrap:run
|
|
||||||
|
|
||||||
[options.extras_require]
|
|
||||||
test =
|
|
@ -1,27 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
import setuptools
|
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(__file__)
|
|
||||||
VERSION_FILENAME = os.path.join(
|
|
||||||
BASE_DIR, "src", "opentelemetry", "instrumentation", "version.py"
|
|
||||||
)
|
|
||||||
PACKAGE_INFO = {}
|
|
||||||
with open(VERSION_FILENAME) as f:
|
|
||||||
exec(f.read(), PACKAGE_INFO)
|
|
||||||
|
|
||||||
setuptools.setup(version=PACKAGE_INFO["__version__"],)
|
|
@ -1,109 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
from logging import getLogger
|
|
||||||
from os import environ, execl, getcwd
|
|
||||||
from os.path import abspath, dirname, pathsep
|
|
||||||
from shutil import which
|
|
||||||
|
|
||||||
from opentelemetry.environment_variables import (
|
|
||||||
OTEL_PYTHON_ID_GENERATOR,
|
|
||||||
OTEL_TRACES_EXPORTER,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = getLogger(__file__)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="""
|
|
||||||
opentelemetry-instrument automatically instruments a Python
|
|
||||||
program and it's dependencies and then runs the program.
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"--trace-exporter",
|
|
||||||
required=False,
|
|
||||||
help="""
|
|
||||||
Uses the specified exporter to export spans.
|
|
||||||
Accepts multiple exporters as comma separated values.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
--trace-exporter=jaeger
|
|
||||||
""",
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"--id-generator",
|
|
||||||
required=False,
|
|
||||||
help="""
|
|
||||||
The IDs Generator to be used with the Tracer Provider.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
--id-generator=random
|
|
||||||
""",
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument("command", help="Your Python application.")
|
|
||||||
parser.add_argument(
|
|
||||||
"command_args",
|
|
||||||
help="Arguments for your application.",
|
|
||||||
nargs=argparse.REMAINDER,
|
|
||||||
)
|
|
||||||
return parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
def load_config_from_cli_args(args):
|
|
||||||
if args.trace_exporter:
|
|
||||||
environ[OTEL_TRACES_EXPORTER] = args.trace_exporter
|
|
||||||
if args.id_generator:
|
|
||||||
environ[OTEL_PYTHON_ID_GENERATOR] = args.id_generator
|
|
||||||
|
|
||||||
|
|
||||||
def run() -> None:
|
|
||||||
args = parse_args()
|
|
||||||
load_config_from_cli_args(args)
|
|
||||||
|
|
||||||
python_path = environ.get("PYTHONPATH")
|
|
||||||
|
|
||||||
if not python_path:
|
|
||||||
python_path = []
|
|
||||||
|
|
||||||
else:
|
|
||||||
python_path = python_path.split(pathsep)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
filedir_path = dirname(abspath(__file__))
|
|
||||||
|
|
||||||
python_path = [path for path in python_path if path != filedir_path]
|
|
||||||
|
|
||||||
python_path.insert(0, filedir_path)
|
|
||||||
|
|
||||||
environ["PYTHONPATH"] = pathsep.join(python_path)
|
|
||||||
|
|
||||||
executable = which(args.command)
|
|
||||||
execl(executable, executable, *args.command_args)
|
|
@ -1,135 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
from logging import getLogger
|
|
||||||
from os import environ, path
|
|
||||||
from os.path import abspath, dirname, pathsep
|
|
||||||
from re import sub
|
|
||||||
|
|
||||||
from pkg_resources import iter_entry_points
|
|
||||||
|
|
||||||
from opentelemetry.environment_variables import (
|
|
||||||
OTEL_PYTHON_DISABLED_INSTRUMENTATIONS,
|
|
||||||
)
|
|
||||||
from opentelemetry.instrumentation.dependencies import (
|
|
||||||
get_dist_dependency_conflicts,
|
|
||||||
)
|
|
||||||
from opentelemetry.instrumentation.distro import BaseDistro, DefaultDistro
|
|
||||||
|
|
||||||
logger = getLogger(__file__)
|
|
||||||
|
|
||||||
|
|
||||||
def _load_distros() -> BaseDistro:
|
|
||||||
for entry_point in iter_entry_points("opentelemetry_distro"):
|
|
||||||
try:
|
|
||||||
distro = entry_point.load()()
|
|
||||||
if not isinstance(distro, BaseDistro):
|
|
||||||
logger.debug(
|
|
||||||
"%s is not an OpenTelemetry Distro. Skipping",
|
|
||||||
entry_point.name,
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
logger.debug(
|
|
||||||
"Distribution %s will be configured", entry_point.name
|
|
||||||
)
|
|
||||||
return distro
|
|
||||||
except Exception as exc: # pylint: disable=broad-except
|
|
||||||
logger.exception(
|
|
||||||
"Distribution %s configuration failed", entry_point.name
|
|
||||||
)
|
|
||||||
raise exc
|
|
||||||
return DefaultDistro()
|
|
||||||
|
|
||||||
|
|
||||||
def _load_instrumentors(distro):
|
|
||||||
package_to_exclude = environ.get(OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, [])
|
|
||||||
if isinstance(package_to_exclude, str):
|
|
||||||
package_to_exclude = package_to_exclude.split(",")
|
|
||||||
# to handle users entering "requests , flask" or "requests, flask" with spaces
|
|
||||||
package_to_exclude = [x.strip() for x in package_to_exclude]
|
|
||||||
|
|
||||||
for entry_point in iter_entry_points("opentelemetry_instrumentor"):
|
|
||||||
if entry_point.name in package_to_exclude:
|
|
||||||
logger.debug(
|
|
||||||
"Instrumentation skipped for library %s", entry_point.name
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
conflict = get_dist_dependency_conflicts(entry_point.dist)
|
|
||||||
if conflict:
|
|
||||||
logger.debug(
|
|
||||||
"Skipping instrumentation %s: %s",
|
|
||||||
entry_point.name,
|
|
||||||
conflict,
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# tell instrumentation to not run dep checks again as we already did it above
|
|
||||||
distro.load_instrumentor(entry_point, skip_dep_check=True)
|
|
||||||
logger.debug("Instrumented %s", entry_point.name)
|
|
||||||
except Exception as exc: # pylint: disable=broad-except
|
|
||||||
logger.exception("Instrumenting of %s failed", entry_point.name)
|
|
||||||
raise exc
|
|
||||||
|
|
||||||
|
|
||||||
def _load_configurators():
|
|
||||||
configured = None
|
|
||||||
for entry_point in iter_entry_points("opentelemetry_configurator"):
|
|
||||||
if configured is not None:
|
|
||||||
logger.warning(
|
|
||||||
"Configuration of %s not loaded, %s already loaded",
|
|
||||||
entry_point.name,
|
|
||||||
configured,
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
entry_point.load()().configure() # type: ignore
|
|
||||||
configured = entry_point.name
|
|
||||||
except Exception as exc: # pylint: disable=broad-except
|
|
||||||
logger.exception("Configuration of %s failed", entry_point.name)
|
|
||||||
raise exc
|
|
||||||
|
|
||||||
|
|
||||||
def initialize():
|
|
||||||
try:
|
|
||||||
distro = _load_distros()
|
|
||||||
distro.configure()
|
|
||||||
_load_configurators()
|
|
||||||
_load_instrumentors(distro)
|
|
||||||
except Exception: # pylint: disable=broad-except
|
|
||||||
logger.exception("Failed to auto initialize opentelemetry")
|
|
||||||
finally:
|
|
||||||
environ["PYTHONPATH"] = sub(
|
|
||||||
r"{}{}?".format(dirname(abspath(__file__)), pathsep),
|
|
||||||
"",
|
|
||||||
environ["PYTHONPATH"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
hasattr(sys, "argv")
|
|
||||||
and sys.argv[0].split(path.sep)[-1] == "celery"
|
|
||||||
and "worker" in sys.argv[1:]
|
|
||||||
):
|
|
||||||
from celery.signals import worker_process_init # pylint:disable=E0401
|
|
||||||
|
|
||||||
@worker_process_init.connect(weak=False)
|
|
||||||
def init_celery(*args, **kwargs):
|
|
||||||
initialize()
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
|
||||||
initialize()
|
|
@ -1,160 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import logging
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import pkg_resources
|
|
||||||
|
|
||||||
from opentelemetry.instrumentation.bootstrap_gen import (
|
|
||||||
default_instrumentations,
|
|
||||||
libraries,
|
|
||||||
)
|
|
||||||
from opentelemetry.instrumentation.version import __version__ as version
|
|
||||||
|
|
||||||
logger = logging.getLogger(__file__)
|
|
||||||
|
|
||||||
|
|
||||||
def _syscall(func):
|
|
||||||
def wrapper(package=None):
|
|
||||||
try:
|
|
||||||
if package:
|
|
||||||
return func(package)
|
|
||||||
return func()
|
|
||||||
except subprocess.SubprocessError as exp:
|
|
||||||
cmd = getattr(exp, "cmd", None)
|
|
||||||
if cmd:
|
|
||||||
msg = 'Error calling system command "{0}"'.format(
|
|
||||||
" ".join(cmd)
|
|
||||||
)
|
|
||||||
if package:
|
|
||||||
msg = '{0} for package "{1}"'.format(msg, package)
|
|
||||||
raise RuntimeError(msg)
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
@_syscall
|
|
||||||
def _sys_pip_install(package):
|
|
||||||
# explicit upgrade strategy to override potential pip config
|
|
||||||
subprocess.check_call(
|
|
||||||
[
|
|
||||||
sys.executable,
|
|
||||||
"-m",
|
|
||||||
"pip",
|
|
||||||
"install",
|
|
||||||
"-U",
|
|
||||||
"--upgrade-strategy",
|
|
||||||
"only-if-needed",
|
|
||||||
package,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _pip_check():
|
|
||||||
"""Ensures none of the instrumentations have dependency conflicts.
|
|
||||||
Clean check reported as:
|
|
||||||
'No broken requirements found.'
|
|
||||||
Dependency conflicts are reported as:
|
|
||||||
'opentelemetry-instrumentation-flask 1.0.1 has requirement opentelemetry-sdk<2.0,>=1.0, but you have opentelemetry-sdk 0.5.'
|
|
||||||
To not be too restrictive, we'll only check for relevant packages.
|
|
||||||
"""
|
|
||||||
# pylint: disable=consider-using-with
|
|
||||||
check_pipe = subprocess.Popen(
|
|
||||||
[sys.executable, "-m", "pip", "check"], stdout=subprocess.PIPE
|
|
||||||
)
|
|
||||||
pip_check = check_pipe.communicate()[0].decode()
|
|
||||||
pip_check_lower = pip_check.lower()
|
|
||||||
for package_tup in libraries.values():
|
|
||||||
for package in package_tup:
|
|
||||||
if package.lower() in pip_check_lower:
|
|
||||||
raise RuntimeError(
|
|
||||||
"Dependency conflict found: {}".format(pip_check)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _is_installed(req):
|
|
||||||
if req in sys.modules:
|
|
||||||
return True
|
|
||||||
|
|
||||||
try:
|
|
||||||
pkg_resources.get_distribution(req)
|
|
||||||
except pkg_resources.DistributionNotFound:
|
|
||||||
return False
|
|
||||||
except pkg_resources.VersionConflict as exc:
|
|
||||||
logger.warning(
|
|
||||||
"instrumentation for package %s is available but version %s is installed. Skipping.",
|
|
||||||
exc.req,
|
|
||||||
exc.dist.as_requirement(), # pylint: disable=no-member
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def _find_installed_libraries():
|
|
||||||
libs = default_instrumentations[:]
|
|
||||||
libs.extend(
|
|
||||||
[
|
|
||||||
v["instrumentation"]
|
|
||||||
for _, v in libraries.items()
|
|
||||||
if _is_installed(v["library"])
|
|
||||||
]
|
|
||||||
)
|
|
||||||
return libs
|
|
||||||
|
|
||||||
|
|
||||||
def _run_requirements():
|
|
||||||
logger.setLevel(logging.ERROR)
|
|
||||||
print("\n".join(_find_installed_libraries()), end="")
|
|
||||||
|
|
||||||
|
|
||||||
def _run_install():
|
|
||||||
for lib in _find_installed_libraries():
|
|
||||||
_sys_pip_install(lib)
|
|
||||||
_pip_check()
|
|
||||||
|
|
||||||
|
|
||||||
def run() -> None:
|
|
||||||
action_install = "install"
|
|
||||||
action_requirements = "requirements"
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="""
|
|
||||||
opentelemetry-bootstrap detects installed libraries and automatically
|
|
||||||
installs the relevant instrumentation packages for them.
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-a",
|
|
||||||
"--action",
|
|
||||||
choices=[action_install, action_requirements],
|
|
||||||
default=action_requirements,
|
|
||||||
help="""
|
|
||||||
install - uses pip to install the new requirements using to the
|
|
||||||
currently active site-package.
|
|
||||||
requirements - prints out the new requirements to stdout. Action can
|
|
||||||
be piped and appended to a requirements.txt file.
|
|
||||||
""",
|
|
||||||
)
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
cmd = {
|
|
||||||
action_install: _run_install,
|
|
||||||
action_requirements: _run_requirements,
|
|
||||||
}[args.action]
|
|
||||||
cmd()
|
|
@ -1,138 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
# DO NOT EDIT. THIS FILE WAS AUTOGENERATED FROM INSTRUMENTATION PACKAGES.
|
|
||||||
# RUN `python scripts/generate_instrumentation_bootstrap.py` TO REGENERATE.
|
|
||||||
|
|
||||||
libraries = {
|
|
||||||
"aiohttp": {
|
|
||||||
"library": "aiohttp ~= 3.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.23.dev0",
|
|
||||||
},
|
|
||||||
"aiopg": {
|
|
||||||
"library": "aiopg >= 0.13.0, < 1.3.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-aiopg==0.23.dev0",
|
|
||||||
},
|
|
||||||
"asgiref": {
|
|
||||||
"library": "asgiref ~= 3.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-asgi==0.23.dev0",
|
|
||||||
},
|
|
||||||
"asyncpg": {
|
|
||||||
"library": "asyncpg >= 0.12.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-asyncpg==0.23.dev0",
|
|
||||||
},
|
|
||||||
"boto": {
|
|
||||||
"library": "boto~=2.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-boto==0.23.dev0",
|
|
||||||
},
|
|
||||||
"botocore": {
|
|
||||||
"library": "botocore ~= 1.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-botocore==0.23.dev0",
|
|
||||||
},
|
|
||||||
"celery": {
|
|
||||||
"library": "celery >= 4.0, < 6.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-celery==0.23.dev0",
|
|
||||||
},
|
|
||||||
"django": {
|
|
||||||
"library": "django >= 1.10",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-django==0.23.dev0",
|
|
||||||
},
|
|
||||||
"elasticsearch": {
|
|
||||||
"library": "elasticsearch >= 2.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-elasticsearch==0.23.dev0",
|
|
||||||
},
|
|
||||||
"falcon": {
|
|
||||||
"library": "falcon ~= 2.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-falcon==0.23.dev0",
|
|
||||||
},
|
|
||||||
"fastapi": {
|
|
||||||
"library": "fastapi ~= 0.58.1",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-fastapi==0.23.dev0",
|
|
||||||
},
|
|
||||||
"flask": {
|
|
||||||
"library": "flask >= 1.0, < 3.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-flask==0.23.dev0",
|
|
||||||
},
|
|
||||||
"grpcio": {
|
|
||||||
"library": "grpcio ~= 1.27",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-grpc==0.23.dev0",
|
|
||||||
},
|
|
||||||
"httpx": {
|
|
||||||
"library": "httpx >= 0.18.0, < 0.19.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-httpx==0.23.dev0",
|
|
||||||
},
|
|
||||||
"jinja2": {
|
|
||||||
"library": "jinja2~=2.7",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-jinja2==0.23.dev0",
|
|
||||||
},
|
|
||||||
"mysql-connector-python": {
|
|
||||||
"library": "mysql-connector-python ~= 8.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-mysql==0.23.dev0",
|
|
||||||
},
|
|
||||||
"psycopg2": {
|
|
||||||
"library": "psycopg2 >= 2.7.3.1",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-psycopg2==0.23.dev0",
|
|
||||||
},
|
|
||||||
"pymemcache": {
|
|
||||||
"library": "pymemcache ~= 1.3",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-pymemcache==0.23.dev0",
|
|
||||||
},
|
|
||||||
"pymongo": {
|
|
||||||
"library": "pymongo ~= 3.1",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-pymongo==0.23.dev0",
|
|
||||||
},
|
|
||||||
"PyMySQL": {
|
|
||||||
"library": "PyMySQL ~= 0.10.1",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-pymysql==0.23.dev0",
|
|
||||||
},
|
|
||||||
"pyramid": {
|
|
||||||
"library": "pyramid >= 1.7",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-pyramid==0.23.dev0",
|
|
||||||
},
|
|
||||||
"redis": {
|
|
||||||
"library": "redis >= 2.6",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-redis==0.23.dev0",
|
|
||||||
},
|
|
||||||
"requests": {
|
|
||||||
"library": "requests ~= 2.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-requests==0.23.dev0",
|
|
||||||
},
|
|
||||||
"scikit-learn": {
|
|
||||||
"library": "scikit-learn ~= 0.24.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-sklearn==0.23.dev0",
|
|
||||||
},
|
|
||||||
"sqlalchemy": {
|
|
||||||
"library": "sqlalchemy",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-sqlalchemy==0.23.dev0",
|
|
||||||
},
|
|
||||||
"starlette": {
|
|
||||||
"library": "starlette ~= 0.13.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-starlette==0.23.dev0",
|
|
||||||
},
|
|
||||||
"tornado": {
|
|
||||||
"library": "tornado >= 6.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-tornado==0.23.dev0",
|
|
||||||
},
|
|
||||||
"urllib3": {
|
|
||||||
"library": "urllib3 >= 1.0.0, < 2.0.0",
|
|
||||||
"instrumentation": "opentelemetry-instrumentation-urllib3==0.23.dev0",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
default_instrumentations = [
|
|
||||||
"opentelemetry-instrumentation-dbapi==0.23.dev0",
|
|
||||||
"opentelemetry-instrumentation-logging==0.23.dev0",
|
|
||||||
"opentelemetry-instrumentation-sqlite3==0.23.dev0",
|
|
||||||
"opentelemetry-instrumentation-urllib==0.23.dev0",
|
|
||||||
"opentelemetry-instrumentation-wsgi==0.23.dev0",
|
|
||||||
]
|
|
@ -1,53 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
"""
|
|
||||||
OpenTelemetry Base Configurator
|
|
||||||
"""
|
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
from logging import getLogger
|
|
||||||
|
|
||||||
_LOG = getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseConfigurator(ABC):
|
|
||||||
"""An ABC for configurators
|
|
||||||
|
|
||||||
Configurators are used to configure
|
|
||||||
SDKs (i.e. TracerProvider, MeterProvider, Processors...)
|
|
||||||
to reduce the amount of manual configuration required.
|
|
||||||
"""
|
|
||||||
|
|
||||||
_instance = None
|
|
||||||
_is_instrumented = False
|
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
|
|
||||||
if cls._instance is None:
|
|
||||||
cls._instance = object.__new__(cls, *args, **kwargs)
|
|
||||||
|
|
||||||
return cls._instance
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def _configure(self, **kwargs):
|
|
||||||
"""Configure the SDK"""
|
|
||||||
|
|
||||||
def configure(self, **kwargs):
|
|
||||||
"""Configure the SDK"""
|
|
||||||
self._configure(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["BaseConfigurator"]
|
|
@ -1,64 +0,0 @@
|
|||||||
from logging import getLogger
|
|
||||||
from typing import Collection, Optional
|
|
||||||
|
|
||||||
from pkg_resources import (
|
|
||||||
Distribution,
|
|
||||||
DistributionNotFound,
|
|
||||||
RequirementParseError,
|
|
||||||
VersionConflict,
|
|
||||||
get_distribution,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = getLogger(__file__)
|
|
||||||
|
|
||||||
|
|
||||||
class DependencyConflict:
|
|
||||||
required: str = None
|
|
||||||
found: Optional[str] = None
|
|
||||||
|
|
||||||
def __init__(self, required, found=None):
|
|
||||||
self.required = required
|
|
||||||
self.found = found
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return 'DependencyConflict: requested: "{0}" but found: "{1}"'.format(
|
|
||||||
self.required, self.found
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_dist_dependency_conflicts(
|
|
||||||
dist: Distribution,
|
|
||||||
) -> Optional[DependencyConflict]:
|
|
||||||
main_deps = dist.requires()
|
|
||||||
instrumentation_deps = []
|
|
||||||
for dep in dist.requires(("instruments",)):
|
|
||||||
if dep not in main_deps:
|
|
||||||
# we set marker to none so string representation of the dependency looks like
|
|
||||||
# requests ~= 1.0
|
|
||||||
# instead of
|
|
||||||
# requests ~= 1.0; extra = "instruments"
|
|
||||||
# which does not work with `get_distribution()`
|
|
||||||
dep.marker = None
|
|
||||||
instrumentation_deps.append(str(dep))
|
|
||||||
|
|
||||||
return get_dependency_conflicts(instrumentation_deps)
|
|
||||||
|
|
||||||
|
|
||||||
def get_dependency_conflicts(
|
|
||||||
deps: Collection[str],
|
|
||||||
) -> Optional[DependencyConflict]:
|
|
||||||
for dep in deps:
|
|
||||||
try:
|
|
||||||
get_distribution(dep)
|
|
||||||
except VersionConflict as exc:
|
|
||||||
return DependencyConflict(dep, exc.dist)
|
|
||||||
except DistributionNotFound:
|
|
||||||
return DependencyConflict(dep)
|
|
||||||
except RequirementParseError as exc:
|
|
||||||
logger.warning(
|
|
||||||
'error parsing dependency, reporting as a conflict: "%s" - %s',
|
|
||||||
dep,
|
|
||||||
exc,
|
|
||||||
)
|
|
||||||
return DependencyConflict(dep)
|
|
||||||
return None
|
|
@ -1,71 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
"""
|
|
||||||
OpenTelemetry Base Distribution (Distro)
|
|
||||||
"""
|
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
from logging import getLogger
|
|
||||||
|
|
||||||
from pkg_resources import EntryPoint
|
|
||||||
|
|
||||||
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
||||||
|
|
||||||
_LOG = getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseDistro(ABC):
|
|
||||||
"""An ABC for distro"""
|
|
||||||
|
|
||||||
_instance = None
|
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
|
|
||||||
if cls._instance is None:
|
|
||||||
cls._instance = object.__new__(cls, *args, **kwargs)
|
|
||||||
|
|
||||||
return cls._instance
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def _configure(self, **kwargs):
|
|
||||||
"""Configure the distribution"""
|
|
||||||
|
|
||||||
def configure(self, **kwargs):
|
|
||||||
"""Configure the distribution"""
|
|
||||||
self._configure(**kwargs)
|
|
||||||
|
|
||||||
def load_instrumentor( # pylint: disable=no-self-use
|
|
||||||
self, entry_point: EntryPoint, **kwargs
|
|
||||||
):
|
|
||||||
"""Takes a collection of instrumentation entry points
|
|
||||||
and activates them by instantiating and calling instrument()
|
|
||||||
on each one.
|
|
||||||
|
|
||||||
Distros can override this method to customize the behavior by
|
|
||||||
inspecting each entry point and configuring them in special ways,
|
|
||||||
passing additional arguments, load a replacement/fork instead,
|
|
||||||
skip loading entirely, etc.
|
|
||||||
"""
|
|
||||||
instrumentor: BaseInstrumentor = entry_point.load()
|
|
||||||
instrumentor().instrument(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class DefaultDistro(BaseDistro):
|
|
||||||
def _configure(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["BaseDistro", "DefaultDistro"]
|
|
@ -1,132 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
"""
|
|
||||||
OpenTelemetry Base Instrumentor
|
|
||||||
"""
|
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
from logging import getLogger
|
|
||||||
from typing import Collection, Optional
|
|
||||||
|
|
||||||
from opentelemetry.instrumentation.dependencies import (
|
|
||||||
DependencyConflict,
|
|
||||||
get_dependency_conflicts,
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOG = getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseInstrumentor(ABC):
|
|
||||||
"""An ABC for instrumentors
|
|
||||||
|
|
||||||
Child classes of this ABC should instrument specific third
|
|
||||||
party libraries or frameworks either by using the
|
|
||||||
``opentelemetry-instrument`` command or by calling their methods
|
|
||||||
directly.
|
|
||||||
|
|
||||||
Since every third party library or framework is different and has different
|
|
||||||
instrumentation needs, more methods can be added to the child classes as
|
|
||||||
needed to provide practical instrumentation to the end user.
|
|
||||||
"""
|
|
||||||
|
|
||||||
_instance = None
|
|
||||||
_is_instrumented_by_opentelemetry = False
|
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
|
|
||||||
if cls._instance is None:
|
|
||||||
cls._instance = object.__new__(cls, *args, **kwargs)
|
|
||||||
|
|
||||||
return cls._instance
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_instrumented_by_opentelemetry(self):
|
|
||||||
return self._is_instrumented_by_opentelemetry
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def instrumentation_dependencies(self) -> Collection[str]:
|
|
||||||
"""Return a list of python packages with versions that the will be instrumented.
|
|
||||||
|
|
||||||
The format should be the same as used in requirements.txt or setup.py.
|
|
||||||
|
|
||||||
For example, if an instrumentation instruments requests 1.x, this method should look
|
|
||||||
like:
|
|
||||||
|
|
||||||
def instrumentation_dependencies(self) -> Collection[str]:
|
|
||||||
return ['requests ~= 1.0']
|
|
||||||
|
|
||||||
This will ensure that the instrumentation will only be used when the specified library
|
|
||||||
is present in the environment.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _instrument(self, **kwargs):
|
|
||||||
"""Instrument the library"""
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def _uninstrument(self, **kwargs):
|
|
||||||
"""Uninstrument the library"""
|
|
||||||
|
|
||||||
def _check_dependency_conflicts(self) -> Optional[DependencyConflict]:
|
|
||||||
dependencies = self.instrumentation_dependencies()
|
|
||||||
return get_dependency_conflicts(dependencies)
|
|
||||||
|
|
||||||
def instrument(self, **kwargs):
|
|
||||||
"""Instrument the library
|
|
||||||
|
|
||||||
This method will be called without any optional arguments by the
|
|
||||||
``opentelemetry-instrument`` command.
|
|
||||||
|
|
||||||
This means that calling this method directly without passing any
|
|
||||||
optional values should do the very same thing that the
|
|
||||||
``opentelemetry-instrument`` command does.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if self._is_instrumented_by_opentelemetry:
|
|
||||||
_LOG.warning("Attempting to instrument while already instrumented")
|
|
||||||
return None
|
|
||||||
|
|
||||||
# check if instrumentor has any missing or conflicting dependencies
|
|
||||||
skip_dep_check = kwargs.pop("skip_dep_check", False)
|
|
||||||
if not skip_dep_check:
|
|
||||||
conflict = self._check_dependency_conflicts()
|
|
||||||
if conflict:
|
|
||||||
_LOG.error(conflict)
|
|
||||||
return None
|
|
||||||
|
|
||||||
result = self._instrument( # pylint: disable=assignment-from-no-return
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
self._is_instrumented_by_opentelemetry = True
|
|
||||||
return result
|
|
||||||
|
|
||||||
def uninstrument(self, **kwargs):
|
|
||||||
"""Uninstrument the library
|
|
||||||
|
|
||||||
See ``BaseInstrumentor.instrument`` for more information regarding the
|
|
||||||
usage of ``kwargs``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if self._is_instrumented_by_opentelemetry:
|
|
||||||
result = self._uninstrument(**kwargs)
|
|
||||||
self._is_instrumented_by_opentelemetry = False
|
|
||||||
return result
|
|
||||||
|
|
||||||
_LOG.warning("Attempting to uninstrument while already uninstrumented")
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["BaseInstrumentor"]
|
|
@ -1,126 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
This module implements experimental propagators to inject trace context
|
|
||||||
into response carriers. This is useful for server side frameworks that start traces
|
|
||||||
when server requests and want to share the trace context with the client so the
|
|
||||||
client can add it's spans to the same trace.
|
|
||||||
|
|
||||||
This is part of an upcoming W3C spec and will eventually make it to the Otel spec.
|
|
||||||
|
|
||||||
https://w3c.github.io/trace-context/#trace-context-http-response-headers-format
|
|
||||||
"""
|
|
||||||
|
|
||||||
import typing
|
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
from opentelemetry import trace
|
|
||||||
from opentelemetry.context.context import Context
|
|
||||||
from opentelemetry.propagators import textmap
|
|
||||||
from opentelemetry.trace import format_span_id, format_trace_id
|
|
||||||
|
|
||||||
_HTTP_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers"
|
|
||||||
_RESPONSE_PROPAGATOR = None
|
|
||||||
|
|
||||||
|
|
||||||
def get_global_response_propagator():
|
|
||||||
return _RESPONSE_PROPAGATOR
|
|
||||||
|
|
||||||
|
|
||||||
def set_global_response_propagator(propagator):
|
|
||||||
global _RESPONSE_PROPAGATOR # pylint:disable=global-statement
|
|
||||||
_RESPONSE_PROPAGATOR = propagator
|
|
||||||
|
|
||||||
|
|
||||||
class Setter(ABC):
|
|
||||||
@abstractmethod
|
|
||||||
def set(self, carrier, key, value):
|
|
||||||
"""Inject the provided key value pair in carrier."""
|
|
||||||
|
|
||||||
|
|
||||||
class DictHeaderSetter(Setter):
|
|
||||||
def set(self, carrier, key, value): # pylint: disable=no-self-use
|
|
||||||
old_value = carrier.get(key, "")
|
|
||||||
if old_value:
|
|
||||||
value = "{0}, {1}".format(old_value, value)
|
|
||||||
carrier[key] = value
|
|
||||||
|
|
||||||
|
|
||||||
class FuncSetter(Setter):
|
|
||||||
"""FuncSetter coverts a function into a valid Setter. Any function that can
|
|
||||||
set values in a carrier can be converted into a Setter by using FuncSetter.
|
|
||||||
This is useful when injecting trace context into non-dict objects such
|
|
||||||
HTTP Response objects for different framework.
|
|
||||||
|
|
||||||
For example, it can be used to create a setter for Falcon response object as:
|
|
||||||
|
|
||||||
setter = FuncSetter(falcon.api.Response.append_header)
|
|
||||||
|
|
||||||
and then used with the propagator as:
|
|
||||||
|
|
||||||
propagator.inject(falcon_response, setter=setter)
|
|
||||||
|
|
||||||
This would essentially make the propagator call `falcon_response.append_header(key, value)`
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, func):
|
|
||||||
self._func = func
|
|
||||||
|
|
||||||
def set(self, carrier, key, value):
|
|
||||||
self._func(carrier, key, value)
|
|
||||||
|
|
||||||
|
|
||||||
default_setter = DictHeaderSetter()
|
|
||||||
|
|
||||||
|
|
||||||
class ResponsePropagator(ABC):
|
|
||||||
@abstractmethod
|
|
||||||
def inject(
|
|
||||||
self,
|
|
||||||
carrier: textmap.CarrierT,
|
|
||||||
context: typing.Optional[Context] = None,
|
|
||||||
setter: textmap.Setter = default_setter,
|
|
||||||
) -> None:
|
|
||||||
"""Injects SpanContext into the HTTP response carrier."""
|
|
||||||
|
|
||||||
|
|
||||||
class TraceResponsePropagator(ResponsePropagator):
|
|
||||||
"""Experimental propagator that injects tracecontext into HTTP responses."""
|
|
||||||
|
|
||||||
def inject(
|
|
||||||
self,
|
|
||||||
carrier: textmap.CarrierT,
|
|
||||||
context: typing.Optional[Context] = None,
|
|
||||||
setter: textmap.Setter = default_setter,
|
|
||||||
) -> None:
|
|
||||||
"""Injects SpanContext into the HTTP response carrier."""
|
|
||||||
span = trace.get_current_span(context)
|
|
||||||
span_context = span.get_span_context()
|
|
||||||
if span_context == trace.INVALID_SPAN_CONTEXT:
|
|
||||||
return
|
|
||||||
|
|
||||||
header_name = "traceresponse"
|
|
||||||
setter.set(
|
|
||||||
carrier,
|
|
||||||
header_name,
|
|
||||||
"00-{trace_id}-{span_id}-{:02x}".format(
|
|
||||||
span_context.trace_flags,
|
|
||||||
trace_id=format_trace_id(span_context.trace_id),
|
|
||||||
span_id=format_span_id(span_context.span_id),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
setter.set(
|
|
||||||
carrier, _HTTP_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS, header_name,
|
|
||||||
)
|
|
@ -1,68 +0,0 @@
|
|||||||
# 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 typing import Dict, Sequence
|
|
||||||
|
|
||||||
from wrapt import ObjectProxy
|
|
||||||
|
|
||||||
from opentelemetry.context import create_key
|
|
||||||
from opentelemetry.trace import StatusCode
|
|
||||||
|
|
||||||
# FIXME This is a temporary location for the suppress instrumentation key.
|
|
||||||
# Once the decision around how to suppress instrumentation is made in the
|
|
||||||
# spec, this key should be moved accordingly.
|
|
||||||
_SUPPRESS_INSTRUMENTATION_KEY = create_key("suppress_instrumentation")
|
|
||||||
|
|
||||||
|
|
||||||
def extract_attributes_from_object(
|
|
||||||
obj: any, attributes: Sequence[str], existing: Dict[str, str] = None
|
|
||||||
) -> Dict[str, str]:
|
|
||||||
extracted = {}
|
|
||||||
if existing:
|
|
||||||
extracted.update(existing)
|
|
||||||
for attr in attributes:
|
|
||||||
value = getattr(obj, attr, None)
|
|
||||||
if value is not None:
|
|
||||||
extracted[attr] = str(value)
|
|
||||||
return extracted
|
|
||||||
|
|
||||||
|
|
||||||
def http_status_to_status_code(
|
|
||||||
status: int, allow_redirect: bool = True
|
|
||||||
) -> StatusCode:
|
|
||||||
"""Converts an HTTP status code to an OpenTelemetry canonical status code
|
|
||||||
|
|
||||||
Args:
|
|
||||||
status (int): HTTP status code
|
|
||||||
"""
|
|
||||||
# See: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#status
|
|
||||||
if status < 100:
|
|
||||||
return StatusCode.ERROR
|
|
||||||
if status <= 299:
|
|
||||||
return StatusCode.UNSET
|
|
||||||
if status <= 399 and allow_redirect:
|
|
||||||
return StatusCode.UNSET
|
|
||||||
return StatusCode.ERROR
|
|
||||||
|
|
||||||
|
|
||||||
def unwrap(obj, attr: str):
|
|
||||||
"""Given a function that was wrapped by wrapt.wrap_function_wrapper, unwrap it
|
|
||||||
|
|
||||||
Args:
|
|
||||||
obj: Object that holds a reference to the wrapped function
|
|
||||||
attr (str): Name of the wrapped function
|
|
||||||
"""
|
|
||||||
func = getattr(obj, attr, None)
|
|
||||||
if func and isinstance(func, ObjectProxy) and hasattr(func, "__wrapped__"):
|
|
||||||
setattr(obj, attr, func.__wrapped__)
|
|
@ -1,15 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
__version__ = "0.23.dev0"
|
|
@ -1,86 +0,0 @@
|
|||||||
# 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 io import StringIO
|
|
||||||
from random import sample
|
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import call, patch
|
|
||||||
|
|
||||||
from opentelemetry.instrumentation import bootstrap
|
|
||||||
from opentelemetry.instrumentation.bootstrap_gen import libraries
|
|
||||||
|
|
||||||
|
|
||||||
def sample_packages(packages, rate):
|
|
||||||
return sample(list(packages), int(len(packages) * rate),)
|
|
||||||
|
|
||||||
|
|
||||||
class TestBootstrap(TestCase):
|
|
||||||
|
|
||||||
installed_libraries = {}
|
|
||||||
installed_instrumentations = {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(cls):
|
|
||||||
cls.installed_libraries = sample_packages(
|
|
||||||
[lib["instrumentation"] for lib in libraries.values()], 0.6
|
|
||||||
)
|
|
||||||
|
|
||||||
# treat 50% of sampled packages as pre-installed
|
|
||||||
cls.installed_instrumentations = sample_packages(
|
|
||||||
cls.installed_libraries, 0.5
|
|
||||||
)
|
|
||||||
|
|
||||||
cls.pkg_patcher = patch(
|
|
||||||
"opentelemetry.instrumentation.bootstrap._find_installed_libraries",
|
|
||||||
return_value=cls.installed_libraries,
|
|
||||||
)
|
|
||||||
|
|
||||||
cls.pip_install_patcher = patch(
|
|
||||||
"opentelemetry.instrumentation.bootstrap._sys_pip_install",
|
|
||||||
)
|
|
||||||
cls.pip_check_patcher = patch(
|
|
||||||
"opentelemetry.instrumentation.bootstrap._pip_check",
|
|
||||||
)
|
|
||||||
|
|
||||||
cls.pkg_patcher.start()
|
|
||||||
cls.mock_pip_install = cls.pip_install_patcher.start()
|
|
||||||
cls.mock_pip_check = cls.pip_check_patcher.start()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def tearDownClass(cls):
|
|
||||||
cls.pip_check_patcher.start()
|
|
||||||
cls.pip_install_patcher.start()
|
|
||||||
cls.pkg_patcher.stop()
|
|
||||||
|
|
||||||
@patch("sys.argv", ["bootstrap", "-a", "pipenv"])
|
|
||||||
def test_run_unknown_cmd(self):
|
|
||||||
with self.assertRaises(SystemExit):
|
|
||||||
bootstrap.run()
|
|
||||||
|
|
||||||
@patch("sys.argv", ["bootstrap", "-a", "requirements"])
|
|
||||||
def test_run_cmd_print(self):
|
|
||||||
with patch("sys.stdout", new=StringIO()) as fake_out:
|
|
||||||
bootstrap.run()
|
|
||||||
self.assertEqual(
|
|
||||||
fake_out.getvalue(), "\n".join(self.installed_libraries),
|
|
||||||
)
|
|
||||||
|
|
||||||
@patch("sys.argv", ["bootstrap", "-a", "install"])
|
|
||||||
def test_run_cmd_install(self):
|
|
||||||
bootstrap.run()
|
|
||||||
self.mock_pip_install.assert_has_calls(
|
|
||||||
[call(i) for i in self.installed_libraries], any_order=True,
|
|
||||||
)
|
|
||||||
self.assertEqual(self.mock_pip_check.call_count, 1)
|
|
@ -1,79 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
# pylint: disable=protected-access
|
|
||||||
|
|
||||||
import pkg_resources
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from opentelemetry.instrumentation.dependencies import (
|
|
||||||
DependencyConflict,
|
|
||||||
get_dependency_conflicts,
|
|
||||||
get_dist_dependency_conflicts,
|
|
||||||
)
|
|
||||||
from opentelemetry.test.test_base import TestBase
|
|
||||||
|
|
||||||
|
|
||||||
class TestDependencyConflicts(TestBase):
|
|
||||||
def setUp(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_get_dependency_conflicts_empty(self):
|
|
||||||
self.assertIsNone(get_dependency_conflicts([]))
|
|
||||||
|
|
||||||
def test_get_dependency_conflicts_no_conflict(self):
|
|
||||||
self.assertIsNone(get_dependency_conflicts(["pytest"]))
|
|
||||||
|
|
||||||
def test_get_dependency_conflicts_not_installed(self):
|
|
||||||
conflict = get_dependency_conflicts(["this-package-does-not-exist"])
|
|
||||||
self.assertTrue(conflict is not None)
|
|
||||||
self.assertTrue(isinstance(conflict, DependencyConflict))
|
|
||||||
self.assertEqual(
|
|
||||||
str(conflict),
|
|
||||||
'DependencyConflict: requested: "this-package-does-not-exist" but found: "None"',
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_get_dependency_conflicts_mismatched_version(self):
|
|
||||||
conflict = get_dependency_conflicts(["pytest == 5000"])
|
|
||||||
self.assertTrue(conflict is not None)
|
|
||||||
self.assertTrue(isinstance(conflict, DependencyConflict))
|
|
||||||
self.assertEqual(
|
|
||||||
str(conflict),
|
|
||||||
'DependencyConflict: requested: "pytest == 5000" but found: "pytest {0}"'.format(
|
|
||||||
pytest.__version__
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_get_dist_dependency_conflicts(self):
|
|
||||||
def mock_requires(extras=()):
|
|
||||||
if "instruments" in extras:
|
|
||||||
return [
|
|
||||||
pkg_resources.Requirement(
|
|
||||||
'test-pkg ~= 1.0; extra == "instruments"'
|
|
||||||
)
|
|
||||||
]
|
|
||||||
return []
|
|
||||||
|
|
||||||
dist = pkg_resources.Distribution(
|
|
||||||
project_name="test-instrumentation", version="1.0"
|
|
||||||
)
|
|
||||||
dist.requires = mock_requires
|
|
||||||
|
|
||||||
conflict = get_dist_dependency_conflicts(dist)
|
|
||||||
self.assertTrue(conflict is not None)
|
|
||||||
self.assertTrue(isinstance(conflict, DependencyConflict))
|
|
||||||
self.assertEqual(
|
|
||||||
str(conflict),
|
|
||||||
'DependencyConflict: requested: "test-pkg~=1.0" but found: "None"',
|
|
||||||
)
|
|
@ -1,58 +0,0 @@
|
|||||||
# 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 unittest import TestCase
|
|
||||||
|
|
||||||
from pkg_resources import EntryPoint
|
|
||||||
|
|
||||||
from opentelemetry.instrumentation.distro import BaseDistro
|
|
||||||
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
||||||
|
|
||||||
|
|
||||||
class MockInstrumetor(BaseInstrumentor):
|
|
||||||
def instrumentation_dependencies(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
def _instrument(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _uninstrument(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MockEntryPoint(EntryPoint):
|
|
||||||
def __init__(self, obj): # pylint: disable=super-init-not-called
|
|
||||||
self._obj = obj
|
|
||||||
|
|
||||||
def load(self, *args, **kwargs): # pylint: disable=signature-differs
|
|
||||||
return self._obj
|
|
||||||
|
|
||||||
|
|
||||||
class MockDistro(BaseDistro):
|
|
||||||
def _configure(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TestDistro(TestCase):
|
|
||||||
def test_load_instrumentor(self):
|
|
||||||
# pylint: disable=protected-access
|
|
||||||
distro = MockDistro()
|
|
||||||
|
|
||||||
instrumentor = MockInstrumetor()
|
|
||||||
entry_point = MockEntryPoint(MockInstrumetor)
|
|
||||||
|
|
||||||
self.assertFalse(instrumentor._is_instrumented_by_opentelemetry)
|
|
||||||
distro.load_instrumentor(entry_point)
|
|
||||||
self.assertTrue(instrumentor._is_instrumented_by_opentelemetry)
|
|
@ -1,50 +0,0 @@
|
|||||||
# 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 logging import WARNING
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
||||||
|
|
||||||
|
|
||||||
class TestInstrumentor(TestCase):
|
|
||||||
class Instrumentor(BaseInstrumentor):
|
|
||||||
def _instrument(self, **kwargs):
|
|
||||||
return "instrumented"
|
|
||||||
|
|
||||||
def _uninstrument(self, **kwargs):
|
|
||||||
return "uninstrumented"
|
|
||||||
|
|
||||||
def instrumentation_dependencies(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
def test_protect(self):
|
|
||||||
instrumentor = self.Instrumentor()
|
|
||||||
|
|
||||||
with self.assertLogs(level=WARNING):
|
|
||||||
self.assertIs(instrumentor.uninstrument(), None)
|
|
||||||
|
|
||||||
self.assertEqual(instrumentor.instrument(), "instrumented")
|
|
||||||
|
|
||||||
with self.assertLogs(level=WARNING):
|
|
||||||
self.assertIs(instrumentor.instrument(), None)
|
|
||||||
|
|
||||||
self.assertEqual(instrumentor.uninstrument(), "uninstrumented")
|
|
||||||
|
|
||||||
with self.assertLogs(level=WARNING):
|
|
||||||
self.assertIs(instrumentor.uninstrument(), None)
|
|
||||||
|
|
||||||
def test_singleton(self):
|
|
||||||
self.assertIs(self.Instrumentor(), self.Instrumentor())
|
|
@ -1,80 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
# pylint: disable=protected-access
|
|
||||||
|
|
||||||
from opentelemetry import trace
|
|
||||||
from opentelemetry.instrumentation import propagators
|
|
||||||
from opentelemetry.instrumentation.propagators import (
|
|
||||||
DictHeaderSetter,
|
|
||||||
TraceResponsePropagator,
|
|
||||||
get_global_response_propagator,
|
|
||||||
set_global_response_propagator,
|
|
||||||
)
|
|
||||||
from opentelemetry.test.test_base import TestBase
|
|
||||||
|
|
||||||
|
|
||||||
class TestGlobals(TestBase):
|
|
||||||
def test_get_set(self):
|
|
||||||
original = propagators._RESPONSE_PROPAGATOR
|
|
||||||
|
|
||||||
propagators._RESPONSE_PROPAGATOR = None
|
|
||||||
self.assertIsNone(get_global_response_propagator())
|
|
||||||
|
|
||||||
prop = TraceResponsePropagator()
|
|
||||||
set_global_response_propagator(prop)
|
|
||||||
self.assertIs(prop, get_global_response_propagator())
|
|
||||||
|
|
||||||
propagators._RESPONSE_PROPAGATOR = original
|
|
||||||
|
|
||||||
|
|
||||||
class TestDictHeaderSetter(TestBase):
|
|
||||||
def test_simple(self):
|
|
||||||
setter = DictHeaderSetter()
|
|
||||||
carrier = {}
|
|
||||||
setter.set(carrier, "kk", "vv")
|
|
||||||
self.assertIn("kk", carrier)
|
|
||||||
self.assertEqual(carrier["kk"], "vv")
|
|
||||||
|
|
||||||
def test_append(self):
|
|
||||||
setter = DictHeaderSetter()
|
|
||||||
carrier = {"kk": "old"}
|
|
||||||
setter.set(carrier, "kk", "vv")
|
|
||||||
self.assertIn("kk", carrier)
|
|
||||||
self.assertEqual(carrier["kk"], "old, vv")
|
|
||||||
|
|
||||||
|
|
||||||
class TestTraceResponsePropagator(TestBase):
|
|
||||||
def test_inject(self):
|
|
||||||
span = trace.NonRecordingSpan(
|
|
||||||
trace.SpanContext(
|
|
||||||
trace_id=1,
|
|
||||||
span_id=2,
|
|
||||||
is_remote=False,
|
|
||||||
trace_flags=trace.DEFAULT_TRACE_OPTIONS,
|
|
||||||
trace_state=trace.DEFAULT_TRACE_STATE,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx = trace.set_span_in_context(span)
|
|
||||||
prop = TraceResponsePropagator()
|
|
||||||
carrier = {}
|
|
||||||
prop.inject(carrier, ctx)
|
|
||||||
self.assertEqual(
|
|
||||||
carrier["Access-Control-Expose-Headers"], "traceresponse"
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
carrier["traceresponse"],
|
|
||||||
"00-00000000000000000000000000000001-0000000000000002-00",
|
|
||||||
)
|
|
@ -1,117 +0,0 @@
|
|||||||
# 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, getcwd
|
|
||||||
from os.path import abspath, dirname, pathsep
|
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
from opentelemetry.environment_variables import OTEL_TRACES_EXPORTER
|
|
||||||
from opentelemetry.instrumentation import auto_instrumentation
|
|
||||||
|
|
||||||
|
|
||||||
class TestRun(TestCase):
|
|
||||||
auto_instrumentation_path = dirname(abspath(auto_instrumentation.__file__))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(cls):
|
|
||||||
cls.execl_patcher = patch(
|
|
||||||
"opentelemetry.instrumentation.auto_instrumentation.execl"
|
|
||||||
)
|
|
||||||
cls.which_patcher = patch(
|
|
||||||
"opentelemetry.instrumentation.auto_instrumentation.which"
|
|
||||||
)
|
|
||||||
|
|
||||||
cls.execl_patcher.start()
|
|
||||||
cls.which_patcher.start()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def tearDownClass(cls):
|
|
||||||
cls.execl_patcher.stop()
|
|
||||||
cls.which_patcher.stop()
|
|
||||||
|
|
||||||
@patch("sys.argv", ["instrument", ""])
|
|
||||||
@patch.dict("os.environ", {"PYTHONPATH": ""})
|
|
||||||
def test_empty(self):
|
|
||||||
auto_instrumentation.run()
|
|
||||||
self.assertEqual(
|
|
||||||
environ["PYTHONPATH"],
|
|
||||||
pathsep.join([self.auto_instrumentation_path, getcwd()]),
|
|
||||||
)
|
|
||||||
|
|
||||||
@patch("sys.argv", ["instrument", ""])
|
|
||||||
@patch.dict("os.environ", {"PYTHONPATH": "abc"})
|
|
||||||
def test_non_empty(self):
|
|
||||||
auto_instrumentation.run()
|
|
||||||
self.assertEqual(
|
|
||||||
environ["PYTHONPATH"],
|
|
||||||
pathsep.join([self.auto_instrumentation_path, getcwd(), "abc"]),
|
|
||||||
)
|
|
||||||
|
|
||||||
@patch("sys.argv", ["instrument", ""])
|
|
||||||
@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, getcwd(), "abc"]),
|
|
||||||
)
|
|
||||||
|
|
||||||
@patch("sys.argv", ["instrument", ""])
|
|
||||||
@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, getcwd(), "abc"]),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TestExecl(TestCase):
|
|
||||||
@patch("sys.argv", ["1", "2", "3"])
|
|
||||||
@patch("opentelemetry.instrumentation.auto_instrumentation.which")
|
|
||||||
@patch("opentelemetry.instrumentation.auto_instrumentation.execl")
|
|
||||||
def test_execl(
|
|
||||||
self, mock_execl, mock_which
|
|
||||||
): # pylint: disable=no-self-use
|
|
||||||
mock_which.configure_mock(**{"return_value": "python"})
|
|
||||||
|
|
||||||
auto_instrumentation.run()
|
|
||||||
|
|
||||||
mock_execl.assert_called_with("python", "python", "3")
|
|
||||||
|
|
||||||
|
|
||||||
class TestArgs(TestCase):
|
|
||||||
@patch("opentelemetry.instrumentation.auto_instrumentation.execl")
|
|
||||||
def test_exporter(self, _): # pylint: disable=no-self-use
|
|
||||||
with patch("sys.argv", ["instrument", "2"]):
|
|
||||||
auto_instrumentation.run()
|
|
||||||
self.assertIsNone(environ.get(OTEL_TRACES_EXPORTER))
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"sys.argv", ["instrument", "--trace-exporter", "jaeger", "1", "2"]
|
|
||||||
):
|
|
||||||
auto_instrumentation.run()
|
|
||||||
self.assertEqual(environ.get(OTEL_TRACES_EXPORTER), "jaeger")
|
|
@ -1,45 +0,0 @@
|
|||||||
# 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 http import HTTPStatus
|
|
||||||
|
|
||||||
from opentelemetry.instrumentation.utils import http_status_to_status_code
|
|
||||||
from opentelemetry.test.test_base import TestBase
|
|
||||||
from opentelemetry.trace import StatusCode
|
|
||||||
|
|
||||||
|
|
||||||
class TestUtils(TestBase):
|
|
||||||
# See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#status
|
|
||||||
def test_http_status_to_status_code(self):
|
|
||||||
for status_code, expected in (
|
|
||||||
(HTTPStatus.OK, StatusCode.UNSET),
|
|
||||||
(HTTPStatus.ACCEPTED, StatusCode.UNSET),
|
|
||||||
(HTTPStatus.IM_USED, StatusCode.UNSET),
|
|
||||||
(HTTPStatus.MULTIPLE_CHOICES, StatusCode.UNSET),
|
|
||||||
(HTTPStatus.BAD_REQUEST, StatusCode.ERROR),
|
|
||||||
(HTTPStatus.UNAUTHORIZED, StatusCode.ERROR),
|
|
||||||
(HTTPStatus.FORBIDDEN, StatusCode.ERROR),
|
|
||||||
(HTTPStatus.NOT_FOUND, StatusCode.ERROR),
|
|
||||||
(HTTPStatus.UNPROCESSABLE_ENTITY, StatusCode.ERROR,),
|
|
||||||
(HTTPStatus.TOO_MANY_REQUESTS, StatusCode.ERROR,),
|
|
||||||
(HTTPStatus.NOT_IMPLEMENTED, StatusCode.ERROR),
|
|
||||||
(HTTPStatus.SERVICE_UNAVAILABLE, StatusCode.ERROR),
|
|
||||||
(HTTPStatus.GATEWAY_TIMEOUT, StatusCode.ERROR,),
|
|
||||||
(HTTPStatus.HTTP_VERSION_NOT_SUPPORTED, StatusCode.ERROR,),
|
|
||||||
(600, StatusCode.ERROR),
|
|
||||||
(99, StatusCode.ERROR),
|
|
||||||
):
|
|
||||||
with self.subTest(status_code=status_code):
|
|
||||||
actual = http_status_to_status_code(int(status_code))
|
|
||||||
self.assertEqual(actual, expected, status_code)
|
|
@ -16,7 +16,7 @@ DISTDIR=dist
|
|||||||
mkdir -p $DISTDIR
|
mkdir -p $DISTDIR
|
||||||
rm -rf $DISTDIR/*
|
rm -rf $DISTDIR/*
|
||||||
|
|
||||||
for d in exporter/*/ instrumentation/*/ opentelemetry-instrumentation/ propagator/*/ sdk-extension/*/ util/*/ ; do
|
for d in exporter/*/ instrumentation/*/ propagator/*/ sdk-extension/*/ util/*/ ; do
|
||||||
(
|
(
|
||||||
echo "building $d"
|
echo "building $d"
|
||||||
cd "$d"
|
cd "$d"
|
||||||
|
@ -53,6 +53,7 @@ default_instrumentations = []
|
|||||||
|
|
||||||
gen_path = os.path.join(
|
gen_path = os.path.join(
|
||||||
root_path,
|
root_path,
|
||||||
|
"opentelemetry-python-core",
|
||||||
"opentelemetry-instrumentation",
|
"opentelemetry-instrumentation",
|
||||||
"src",
|
"src",
|
||||||
"opentelemetry",
|
"opentelemetry",
|
||||||
@ -98,7 +99,7 @@ def main():
|
|||||||
"scripts/eachdist.py",
|
"scripts/eachdist.py",
|
||||||
"format",
|
"format",
|
||||||
"--path",
|
"--path",
|
||||||
"opentelemetry-instrumentation",
|
"opentelemetry-python-core/opentelemetry-instrumentation",
|
||||||
],
|
],
|
||||||
check=True,
|
check=True,
|
||||||
)
|
)
|
||||||
|
16
tox.ini
16
tox.ini
@ -5,10 +5,6 @@ envlist =
|
|||||||
; Environments are organized by individual package, allowing
|
; Environments are organized by individual package, allowing
|
||||||
; for specifying supported Python versions per package.
|
; for specifying supported Python versions per package.
|
||||||
|
|
||||||
; opentelemetry-instrumentation
|
|
||||||
py3{6,7,8,9}-test-instrumentation-base
|
|
||||||
pypy3-test-instrumentation-base
|
|
||||||
|
|
||||||
; opentelemetry-sdk-extension-aws
|
; opentelemetry-sdk-extension-aws
|
||||||
py3{6,7,8,9}-test-sdkextension-aws
|
py3{6,7,8,9}-test-sdkextension-aws
|
||||||
pypy3-test-sdkextension-aws
|
pypy3-test-sdkextension-aws
|
||||||
@ -182,7 +178,6 @@ deps =
|
|||||||
; FIXME: add mypy testing
|
; FIXME: add mypy testing
|
||||||
|
|
||||||
changedir =
|
changedir =
|
||||||
test-instrumentation-base: opentelemetry-instrumentation/tests
|
|
||||||
test-instrumentation-aiohttp-client: instrumentation/opentelemetry-instrumentation-aiohttp-client/tests
|
test-instrumentation-aiohttp-client: instrumentation/opentelemetry-instrumentation-aiohttp-client/tests
|
||||||
test-instrumentation-aiopg: instrumentation/opentelemetry-instrumentation-aiopg/tests
|
test-instrumentation-aiopg: instrumentation/opentelemetry-instrumentation-aiopg/tests
|
||||||
test-instrumentation-asgi: instrumentation/opentelemetry-instrumentation-asgi/tests
|
test-instrumentation-asgi: instrumentation/opentelemetry-instrumentation-asgi/tests
|
||||||
@ -228,7 +223,7 @@ commands_pre =
|
|||||||
; cases but it saves a lot of boilerplate in this file.
|
; cases but it saves a lot of boilerplate in this file.
|
||||||
test: pip install {toxinidir}/opentelemetry-python-core/opentelemetry-api[test]
|
test: pip install {toxinidir}/opentelemetry-python-core/opentelemetry-api[test]
|
||||||
test: pip install {toxinidir}/opentelemetry-python-core/opentelemetry-semantic-conventions[test]
|
test: pip install {toxinidir}/opentelemetry-python-core/opentelemetry-semantic-conventions[test]
|
||||||
test: pip install {toxinidir}/opentelemetry-instrumentation[test]
|
test: pip install {toxinidir}/opentelemetry-python-core/opentelemetry-instrumentation[test]
|
||||||
test: pip install {toxinidir}/opentelemetry-python-core/opentelemetry-sdk[test]
|
test: pip install {toxinidir}/opentelemetry-python-core/opentelemetry-sdk[test]
|
||||||
test: pip install {toxinidir}/opentelemetry-python-core/tests/util[test]
|
test: pip install {toxinidir}/opentelemetry-python-core/tests/util[test]
|
||||||
|
|
||||||
@ -297,7 +292,7 @@ commands_pre =
|
|||||||
|
|
||||||
sqlalchemy: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy[test]
|
sqlalchemy: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy[test]
|
||||||
|
|
||||||
elasticsearch{2,5,6,7}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch[test]
|
elasticsearch{2,5,6,7}: pip install {toxinidir}/opentelemetry-python-core/opentelemetry-instrumentation {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch[test]
|
||||||
|
|
||||||
httpx: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx[test]
|
httpx: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx[test]
|
||||||
|
|
||||||
@ -311,7 +306,6 @@ commands_pre =
|
|||||||
coverage: python {toxinidir}/scripts/eachdist.py install --editable
|
coverage: python {toxinidir}/scripts/eachdist.py install --editable
|
||||||
|
|
||||||
commands =
|
commands =
|
||||||
test: pwd
|
|
||||||
test: pytest {posargs}
|
test: pytest {posargs}
|
||||||
coverage: {toxinidir}/scripts/coverage.sh
|
coverage: {toxinidir}/scripts/coverage.sh
|
||||||
|
|
||||||
@ -324,7 +318,7 @@ deps =
|
|||||||
commands_pre =
|
commands_pre =
|
||||||
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-api
|
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-api
|
||||||
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-semantic-conventions
|
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-semantic-conventions
|
||||||
python -m pip install {toxinidir}/opentelemetry-instrumentation
|
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-instrumentation
|
||||||
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-sdk
|
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-sdk
|
||||||
python -m pip install {toxinidir}/util/opentelemetry-util-http
|
python -m pip install {toxinidir}/util/opentelemetry-util-http
|
||||||
|
|
||||||
@ -350,7 +344,7 @@ commands_pre =
|
|||||||
sudo apt-get install libsnappy-dev
|
sudo apt-get install libsnappy-dev
|
||||||
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-api
|
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-api
|
||||||
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-semantic-conventions
|
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-semantic-conventions
|
||||||
python -m pip install -e {toxinidir}/opentelemetry-instrumentation[test]
|
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-instrumentation[test]
|
||||||
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-sdk
|
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-sdk
|
||||||
python -m pip install {toxinidir}/opentelemetry-python-core/tests/util
|
python -m pip install {toxinidir}/opentelemetry-python-core/tests/util
|
||||||
python -m pip install -e {toxinidir}/util/opentelemetry-util-http[test]
|
python -m pip install -e {toxinidir}/util/opentelemetry-util-http[test]
|
||||||
@ -418,7 +412,7 @@ changedir =
|
|||||||
commands_pre =
|
commands_pre =
|
||||||
pip install -e {toxinidir}/opentelemetry-python-core/opentelemetry-api \
|
pip install -e {toxinidir}/opentelemetry-python-core/opentelemetry-api \
|
||||||
-e {toxinidir}/opentelemetry-python-core/opentelemetry-semantic-conventions \
|
-e {toxinidir}/opentelemetry-python-core/opentelemetry-semantic-conventions \
|
||||||
-e {toxinidir}/opentelemetry-instrumentation \
|
-e {toxinidir}/opentelemetry-python-core/opentelemetry-instrumentation \
|
||||||
-e {toxinidir}/opentelemetry-python-core/opentelemetry-sdk \
|
-e {toxinidir}/opentelemetry-python-core/opentelemetry-sdk \
|
||||||
-e {toxinidir}/opentelemetry-python-core/tests/util \
|
-e {toxinidir}/opentelemetry-python-core/tests/util \
|
||||||
-e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg \
|
-e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg \
|
||||||
|
Reference in New Issue
Block a user