Simplify bootstrap and generate code (#514)

- We now automatically generate bootstrap_gen.py file from the list of instrumentations present in the source tree.
- Bootstrap command now uses consumes this auto-generated list instead of keeping it's own local copy.
- We no longer uninstall packages before installing them as instrumentation package no longer specify libraries as dependencies so the edge cases are no longer there.
- We no longer try to install an incompatible version or force upgrade/downgrade an installed version. This used to leave systems in broken states which should happen no more.
This commit is contained in:
Owais Lone
2021-06-01 21:49:09 +05:30
committed by GitHub
parent af7ab072cc
commit 5d1f3201af
47 changed files with 1330 additions and 215 deletions

View File

@ -45,7 +45,7 @@ jobs:
uses: actions/cache@v2
with:
path: .tox
key: v2-build-tox-cache-${{ env.RUN_MATRIX_COMBINATION }}-${{ hashFiles('tox.ini', 'dev-requirements.txt') }}
key: v2-build-tox-cache-${{ env.RUN_MATRIX_COMBINATION }}-${{ hashFiles('tox.ini', 'gen-requirements.txt', 'dev-requirements.txt') }}
- name: run tox
run: tox -f ${{ matrix.python-version }}-${{ matrix.package }} -- --benchmark-json=${{ env.RUN_MATRIX_COMBINATION }}-benchmark.json
- name: Find and merge benchmarks
@ -76,7 +76,7 @@ jobs:
strategy:
fail-fast: false
matrix:
tox-environment: [ "docker-tests", "lint", "docs" ]
tox-environment: [ "docker-tests", "lint", "docs", "generate" ]
name: ${{ matrix.tox-environment }}
runs-on: ubuntu-latest
steps:
@ -99,6 +99,9 @@ jobs:
uses: actions/cache@v2
with:
path: .tox
key: v2-misc-tox-cache-${{ matrix.tox-environment }}-${{ hashFiles('tox.ini', 'dev-requirements.txt', 'docs-requirements.txt') }}
key: v2-misc-tox-cache-${{ matrix.tox-environment }}-${{ hashFiles('tox.ini', 'dev-requirements.txt', 'gen-requirements.txt', 'docs-requirements.txt') }}
- name: run tox
run: tox -e ${{ matrix.tox-environment }}
- name: Ensure generated code is up to date
if: matrix.tox-environment == 'generate'
run: git diff --exit-code || (echo 'Generated code is out of date, please run "tox -e generate" and commit the changes in this PR.' && exit 1)

1
.gitignore vendored
View File

@ -8,6 +8,7 @@
*.egg
*.egg-info
dist
dist-info
build
eggs
parts

View File

@ -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.2.0-0.21b0...HEAD)
### Changed
- `opentelemetry-bootstrap` not longer forcibly removes and re-installs libraries and their instrumentations.
This means running bootstrap will not auto-upgrade existing dependencies and as a result not cause dependency
conflicts.
([#514](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/514))
- `opentelemetry-instrumentation-asgi` Set the response status code on the server span
([#478](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/478))
- `opentelemetry-instrumentation-tornado` Fixed cases where description was used with non-

View File

@ -170,7 +170,7 @@ Below is a checklist of things to be mindful of when implementing a new instrume
- Extends from [BaseInstrumentor](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/opentelemetry-instrumentation/src/opentelemetry/instrumentation/instrumentor.py#L26)
- Supports auto-instrumentation
- Add an entry point (ex. https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/instrumentation/opentelemetry-instrumentation-requests/setup.cfg#L56)
- Add instrumentation package to `bootstrap.py` (https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py#L37)
- Run `python scripts/setup.py` followed by `python scripts/generate_instrumentation_bootstrap.py` after adding a new instrumentation package.
- Functionality that is common amongst other instrumentation and can be abstracted [here](https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/opentelemetry-instrumentation/src/opentelemetry/instrumentation)
- Request/response [hooks](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/408) for http instrumentations
- `suppress_instrumentation` functionality

6
gen-requirements.txt Normal file
View File

@ -0,0 +1,6 @@
-c dev-requirements.txt
astor==0.8.1
jinja2~=2.7
isort
black

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -66,6 +68,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -17,6 +17,8 @@
# RUN `python scripts/generate_setup.py` TO REGENERATE.
import distutils.cmd
import json
import os
from configparser import ConfigParser
@ -56,6 +58,32 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
setuptools.setup(
version=PACKAGE_INFO["__version__"], extras_require=extras_require
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places",
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
"name": config["metadata"]["name"],
"version": PACKAGE_INFO["__version__"],
"instruments": PACKAGE_INFO["_instruments"],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={"meta": JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require,
)

View File

@ -15,118 +15,19 @@
# limitations under the License.
import argparse
import pkgutil
import logging
import subprocess
import sys
from logging import getLogger
import pkg_resources
from opentelemetry.instrumentation.bootstrap_gen import (
default_instrumentations,
libraries,
)
from opentelemetry.instrumentation.version import __version__ as version
logger = getLogger(__file__)
# A mapping of "target library" to "desired instrumentor path/versioned package
# name". Used as part of the `opentelemetry-bootstrap` command which looks at
# libraries used by the application that is to be instrumented, and handles
# automatically installing the appropriate instrumentations for that app.
# This helps for those who prefer to turn on as much instrumentation as
# possible, and don't want to go through the manual process of combing through
# the libraries their application uses to figure which one can be
# instrumented.
# NOTE: system-metrics is not to be included.
def all_instrumentations():
pkg_instrumentation_map = {
"aiohttp-client": "opentelemetry-instrumentation-aiohttp-client",
"aiopg": "opentelemetry-instrumentation-aiopg",
"asyncpg": "opentelemetry-instrumentation-asyncpg",
"boto": "opentelemetry-instrumentation-boto",
"botocore": "opentelemetry-instrumentation-botocore",
"celery": "opentelemetry-instrumentation-celery",
"dbapi": "opentelemetry-instrumentation-dbapi",
"django": "opentelemetry-instrumentation-django",
"elasticsearch": "opentelemetry-instrumentation-elasticsearch",
"falcon": "opentelemetry-instrumentation-falcon",
"fastapi": "opentelemetry-instrumentation-fastapi",
"flask": "opentelemetry-instrumentation-flask",
"grpc": "opentelemetry-instrumentation-grpc",
"jinja2": "opentelemetry-instrumentation-jinja2",
"mysql": "opentelemetry-instrumentation-mysql",
"psycopg2": "opentelemetry-instrumentation-psycopg2",
"pymemcache": "opentelemetry-instrumentation-pymemcache",
"pymongo": "opentelemetry-instrumentation-pymongo",
"pymysql": "opentelemetry-instrumentation-pymysql",
"pyramid": "opentelemetry-instrumentation-pyramid",
"redis": "opentelemetry-instrumentation-redis",
"requests": "opentelemetry-instrumentation-requests",
"sklearn": "opentelemetry-instrumentation-sklearn",
"sqlalchemy": "opentelemetry-instrumentation-sqlalchemy",
"sqlite3": "opentelemetry-instrumentation-sqlite3",
"starlette": "opentelemetry-instrumentation-starlette",
"tornado": "opentelemetry-instrumentation-tornado",
"urllib": "opentelemetry-instrumentation-urllib",
}
for pkg, instrumentation in pkg_instrumentation_map.items():
pkg_instrumentation_map[pkg] = "{0}=={1}".format(
instrumentation, version
)
return pkg_instrumentation_map
instrumentations = all_instrumentations()
# relevant instrumentors and tracers to uninstall and check for conflicts for target libraries
libraries = {
"aiohttp-client": ("opentelemetry-instrumentation-aiohttp-client",),
"aiopg": ("opentelemetry-instrumentation-aiopg",),
"asyncpg": ("opentelemetry-instrumentation-asyncpg",),
"boto": ("opentelemetry-instrumentation-boto",),
"botocore": ("opentelemetry-instrumentation-botocore",),
"celery": ("opentelemetry-instrumentation-celery",),
"dbapi": ("opentelemetry-instrumentation-dbapi",),
"django": ("opentelemetry-instrumentation-django",),
"elasticsearch": ("opentelemetry-instrumentation-elasticsearch",),
"falcon": ("opentelemetry-instrumentation-falcon",),
"fastapi": ("opentelemetry-instrumentation-fastapi",),
"flask": ("opentelemetry-instrumentation-flask",),
"grpc": ("opentelemetry-instrumentation-grpc",),
"jinja2": ("opentelemetry-instrumentation-jinja2",),
"mysql": ("opentelemetry-instrumentation-mysql",),
"psycopg2": ("opentelemetry-instrumentation-psycopg2",),
"pymemcache": ("opentelemetry-instrumentation-pymemcache",),
"pymongo": ("opentelemetry-instrumentation-pymongo",),
"pymysql": ("opentelemetry-instrumentation-pymysql",),
"pyramid": ("opentelemetry-instrumentation-pyramid",),
"redis": ("opentelemetry-instrumentation-redis",),
"requests": ("opentelemetry-instrumentation-requests",),
"sklearn": ("opentelemetry-instrumentation-sklearn",),
"sqlalchemy": ("opentelemetry-instrumentation-sqlalchemy",),
"sqlite3": ("opentelemetry-instrumentation-sqlite3",),
"starlette": ("opentelemetry-instrumentation-starlette",),
"tornado": ("opentelemetry-instrumentation-tornado",),
"urllib": ("opentelemetry-instrumentation-urllib",),
}
def _install_package(library, instrumentation):
"""
Ensures that desired version is installed w/o upgrading its dependencies
by uninstalling where necessary (if `target` is not provided).
OpenTelemetry auto-instrumentation packages often have traced libraries
as instrumentation dependency (e.g. flask for
opentelemetry-instrumentation-flask), so using -I on library could cause
likely undesired Flask upgrade.Using --no-dependencies alone would leave
potential for nonfunctional installations.
"""
pip_list = _sys_pip_freeze()
for package in libraries[library]:
if "{}==".format(package).lower() in pip_list:
logger.info(
"Existing %s installation detected. Uninstalling.", package
)
_sys_pip_uninstall(package)
_sys_pip_install(instrumentation)
logger = logging.getLogger(__file__)
def _syscall(func):
@ -148,15 +49,6 @@ def _syscall(func):
return wrapper
@_syscall
def _sys_pip_freeze():
return (
subprocess.check_output([sys.executable, "-m", "pip", "freeze"])
.decode()
.lower()
)
@_syscall
def _sys_pip_install(package):
# explicit upgrade strategy to override potential pip config
@ -174,13 +66,6 @@ def _sys_pip_install(package):
)
@_syscall
def _sys_pip_uninstall(package):
subprocess.check_call(
[sys.executable, "-m", "pip", "uninstall", "-y", package]
)
def _pip_check():
"""Ensures none of the instrumentations have dependency conflicts.
Clean check reported as:
@ -203,22 +88,44 @@ def _pip_check():
)
def _is_installed(library):
return library in sys.modules or pkgutil.find_loader(library) is not None
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():
return {k: v for k, v in instrumentations.items() if _is_installed(k)}
libs = default_instrumentations[:]
libs.extend(
[
v["instrumentation"]
for _, v in libraries.items()
if _is_installed(v["library"])
]
)
return libs
def _run_requirements(packages):
print("\n".join(packages.values()), end="")
def _run_requirements():
logger.setLevel(logging.ERROR)
print("\n".join(_find_installed_libraries()), end="")
def _run_install(packages):
for pkg, inst in packages.items():
_install_package(pkg, inst)
def _run_install():
for lib in _find_installed_libraries():
_sys_pip_install(lib)
_pip_check()
@ -250,4 +157,4 @@ def run() -> None:
action_install: _run_install,
action_requirements: _run_requirements,
}[args.action]
cmd(_find_installed_libraries())
cmd()

View File

@ -0,0 +1,134 @@
# 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.22.dev0",
},
"aiopg": {
"library": "aiopg >= 0.13.0",
"instrumentation": "opentelemetry-instrumentation-aiopg==0.22.dev0",
},
"asgiref": {
"library": "asgiref ~= 3.0",
"instrumentation": "opentelemetry-instrumentation-asgi==0.22.dev0",
},
"asyncpg": {
"library": "asyncpg >= 0.12.0",
"instrumentation": "opentelemetry-instrumentation-asyncpg==0.22.dev0",
},
"boto": {
"library": "boto~=2.0",
"instrumentation": "opentelemetry-instrumentation-boto==0.22.dev0",
},
"botocore": {
"library": "botocore ~= 1.0",
"instrumentation": "opentelemetry-instrumentation-botocore==0.22.dev0",
},
"celery": {
"library": "celery >= 4.0, < 6.0",
"instrumentation": "opentelemetry-instrumentation-celery==0.22.dev0",
},
"django": {
"library": "django >= 1.10",
"instrumentation": "opentelemetry-instrumentation-django==0.22.dev0",
},
"elasticsearch": {
"library": "elasticsearch >= 2.0",
"instrumentation": "opentelemetry-instrumentation-elasticsearch==0.22.dev0",
},
"falcon": {
"library": "falcon ~= 2.0",
"instrumentation": "opentelemetry-instrumentation-falcon==0.22.dev0",
},
"fastapi": {
"library": "fastapi ~= 0.58.1",
"instrumentation": "opentelemetry-instrumentation-fastapi==0.22.dev0",
},
"flask": {
"library": "flask ~= 1.0",
"instrumentation": "opentelemetry-instrumentation-flask==0.22.dev0",
},
"grpcio": {
"library": "grpcio ~= 1.27",
"instrumentation": "opentelemetry-instrumentation-grpc==0.22.dev0",
},
"jinja2": {
"library": "jinja2~=2.7",
"instrumentation": "opentelemetry-instrumentation-jinja2==0.22.dev0",
},
"mysql-connector-python": {
"library": "mysql-connector-python ~= 8.0",
"instrumentation": "opentelemetry-instrumentation-mysql==0.22.dev0",
},
"psycopg2-binary": {
"library": "psycopg2-binary >= 2.7.3.1",
"instrumentation": "opentelemetry-instrumentation-psycopg2==0.22.dev0",
},
"pymemcache": {
"library": "pymemcache ~= 1.3",
"instrumentation": "opentelemetry-instrumentation-pymemcache==0.22.dev0",
},
"pymongo": {
"library": "pymongo ~= 3.1",
"instrumentation": "opentelemetry-instrumentation-pymongo==0.22.dev0",
},
"PyMySQL": {
"library": "PyMySQL ~= 0.10.1",
"instrumentation": "opentelemetry-instrumentation-pymysql==0.22.dev0",
},
"pyramid": {
"library": "pyramid >= 1.7",
"instrumentation": "opentelemetry-instrumentation-pyramid==0.22.dev0",
},
"redis": {
"library": "redis >= 2.6",
"instrumentation": "opentelemetry-instrumentation-redis==0.22.dev0",
},
"requests": {
"library": "requests ~= 2.0",
"instrumentation": "opentelemetry-instrumentation-requests==0.22.dev0",
},
"scikit-learn": {
"library": "scikit-learn ~= 0.24.0",
"instrumentation": "opentelemetry-instrumentation-sklearn==0.22.dev0",
},
"sqlalchemy": {
"library": "sqlalchemy",
"instrumentation": "opentelemetry-instrumentation-sqlalchemy==0.22.dev0",
},
"starlette": {
"library": "starlette ~= 0.13.0",
"instrumentation": "opentelemetry-instrumentation-starlette==0.22.dev0",
},
"tornado": {
"library": "tornado >= 6.0",
"instrumentation": "opentelemetry-instrumentation-tornado==0.22.dev0",
},
"urllib3": {
"library": "urllib3 >= 1.0.0, < 2.0.0",
"instrumentation": "opentelemetry-instrumentation-urllib3==0.22.dev0",
},
}
default_instrumentations = [
"opentelemetry-instrumentation-dbapi==0.22.dev0",
"opentelemetry-instrumentation-logging==0.22.dev0",
"opentelemetry-instrumentation-sqlite3==0.22.dev0",
"opentelemetry-instrumentation-urllib==0.22.dev0",
"opentelemetry-instrumentation-wsgi==0.22.dev0",
]

View File

@ -13,18 +13,17 @@
# limitations under the License.
# type: ignore
from functools import reduce
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):
sampled = sample(list(packages), int(len(packages) * rate),)
return {k: v for k, v in packages.items() if k in sampled}
return sample(list(packages), int(len(packages) * rate),)
class TestBootstrap(TestCase):
@ -34,9 +33,8 @@ class TestBootstrap(TestCase):
@classmethod
def setUpClass(cls):
# select random 60% of instrumentations
cls.installed_libraries = sample_packages(
bootstrap.instrumentations, 0.6
[lib["instrumentation"] for lib in libraries.values()], 0.6
)
# treat 50% of sampled packages as pre-installed
@ -49,39 +47,21 @@ class TestBootstrap(TestCase):
return_value=cls.installed_libraries,
)
pip_freeze_output = []
for inst in cls.installed_instrumentations.values():
inst = inst.replace(">=", "==")
if "==" not in inst:
inst = "{}==x.y".format(inst)
pip_freeze_output.append(inst)
cls.pip_freeze_patcher = patch(
"opentelemetry.instrumentation.bootstrap._sys_pip_freeze",
return_value="\n".join(pip_freeze_output),
)
cls.pip_install_patcher = patch(
"opentelemetry.instrumentation.bootstrap._sys_pip_install",
)
cls.pip_uninstall_patcher = patch(
"opentelemetry.instrumentation.bootstrap._sys_pip_uninstall",
)
cls.pip_check_patcher = patch(
"opentelemetry.instrumentation.bootstrap._pip_check",
)
cls.pkg_patcher.start()
cls.mock_pip_freeze = cls.pip_freeze_patcher.start()
cls.mock_pip_install = cls.pip_install_patcher.start()
cls.mock_pip_uninstall = cls.pip_uninstall_patcher.start()
cls.mock_pip_check = cls.pip_check_patcher.start()
@classmethod
def tearDownClass(cls):
cls.pip_check_patcher.start()
cls.pip_uninstall_patcher.start()
cls.pip_install_patcher.start()
cls.pip_freeze_patcher.start()
cls.pkg_patcher.stop()
@patch("sys.argv", ["bootstrap", "-a", "pipenv"])
@ -94,32 +74,13 @@ class TestBootstrap(TestCase):
with patch("sys.stdout", new=StringIO()) as fake_out:
bootstrap.run()
self.assertEqual(
fake_out.getvalue(),
"\n".join(self.installed_libraries.values()),
fake_out.getvalue(), "\n".join(self.installed_libraries),
)
@patch("sys.argv", ["bootstrap", "-a", "install"])
def test_run_cmd_install(self):
bootstrap.run()
self.assertEqual(
self.mock_pip_freeze.call_count, len(self.installed_libraries)
)
to_uninstall = reduce(
lambda x, y: x + y,
[
pkgs
for lib, pkgs in bootstrap.libraries.items()
if lib in self.installed_instrumentations
],
)
self.mock_pip_uninstall.assert_has_calls(
[call(i) for i in to_uninstall], any_order=True
)
self.mock_pip_install.assert_has_calls(
[call(i) for i in self.installed_libraries.values()],
any_order=True,
[call(i) for i in self.installed_libraries], any_order=True,
)
self.assertEqual(self.mock_pip_check.call_count, 1)

View File

@ -0,0 +1,98 @@
#!/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 ast
import logging
import os
import subprocess
import astor
import pkg_resources
from otel_packaging import (
get_instrumentation_packages,
root_path,
scripts_path,
)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("instrumentation_list_generator")
_auto_generation_msg = """
# DO NOT EDIT. THIS FILE WAS AUTOGENERATED FROM templates/{source}.
# RUN `python scripts/generate_setup.py` TO REGENERATE.
"""
_template = """
{header}
# DO NOT EDIT. THIS FILE WAS AUTOGENERATED FROM INSTRUMENTATION PACKAGES.
# RUN `python scripts/generate_instrumentation_bootstrap.py` TO REGENERATE.
{source}
"""
_source_tmpl = """
libraries = {}
default_instrumentations = []
"""
gen_path = os.path.join(
root_path,
"opentelemetry-instrumentation",
"src",
"opentelemetry",
"instrumentation",
"bootstrap_gen.py",
)
def main():
# pylint: disable=no-member
default_instrumentations = ast.List(elts=[])
libraries = ast.Dict(keys=[], values=[])
for pkg in get_instrumentation_packages():
if not pkg["instruments"]:
default_instrumentations.elts.append(ast.Str(pkg["requirement"]))
for target_pkg in pkg["instruments"]:
parsed = pkg_resources.Requirement.parse(target_pkg)
libraries.keys.append(ast.Str(parsed.name))
libraries.values.append(
ast.Dict(
keys=[ast.Str("library"), ast.Str("instrumentation")],
values=[ast.Str(target_pkg), ast.Str(pkg["requirement"])],
)
)
tree = ast.parse(_source_tmpl)
tree.body[0].value = libraries
tree.body[1].value = default_instrumentations
source = astor.to_source(tree)
with open(
os.path.join(scripts_path, "license_header.txt"), "r"
) as header_file:
header = header_file.read()
source = _template.format(header=header, source=source)
with open(gen_path, "w") as gen_file:
gen_file.write(source)
subprocess.run(["black", "-q", gen_path], check=True)
if __name__ == "__main__":
main()

View File

@ -17,6 +17,7 @@
import logging
import os
import subprocess
import sys
from jinja2 import Template
@ -72,7 +73,17 @@ def main():
with open(generated_file, "w") as fh:
fh.write(generated)
fh.flush()
subprocess.run(["black", "-q", generated_file], check=True)
subprocess.run(
[
sys.executable,
"scripts/eachdist.py",
"format",
"--path",
"instrumentation",
],
check=True,
)
if __name__ == "__main__":

View File

@ -0,0 +1,13 @@
# 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.

43
scripts/otel_packaging.py Normal file
View File

@ -0,0 +1,43 @@
# 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 json
import os
import subprocess
scripts_path = os.path.dirname(os.path.abspath(__file__))
root_path = os.path.dirname(scripts_path)
instrumentations_path = os.path.join(root_path, "instrumentation")
def get_instrumentation_packages():
for pkg in sorted(os.listdir(instrumentations_path)):
pkg_path = os.path.join(instrumentations_path, pkg)
if not os.path.isdir(pkg_path):
continue
out = str(
subprocess.check_output(
"python setup.py meta", shell=True, cwd=pkg_path
)
)
instrumentation = json.loads(out.split("\\n")[1])
instrumentation["requirement"] = "==".join(
(instrumentation["name"], instrumentation["version"],)
)
yield instrumentation
if __name__ == "__main__":
print(list(get_instrumentation_packages()))

View File

@ -20,6 +20,8 @@ git checkout -b release/${VERSION}
git push origin release/${VERSION}
./scripts/eachdist.py update_versions --versions stable,prerelease
./scripts/generate_setup.py
./scripts/generate_instrumentation_bootstrap.py
rc=$?
if [ $rc != 0 ]; then
echo "::set-output name=version_updated::0"

View File

@ -17,6 +17,8 @@
{{ auto_generation_msg }}
import os
import distutils.cmd
import json
from configparser import ConfigParser
import setuptools
@ -55,7 +57,31 @@ for dep in extras_require["instruments"]:
extras_require["test"] = test_deps
class JSONMetadataCommand(distutils.cmd.Command):
description = (
"print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ",
"auto-generate code in other places"
)
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
metadata = {
'name': config['metadata']['name'],
'version': PACKAGE_INFO['__version__'],
'instruments': PACKAGE_INFO['_instruments'],
}
print(json.dumps(metadata))
setuptools.setup(
cmdclass={'meta': JSONMetadataCommand},
version=PACKAGE_INFO["__version__"],
extras_require=extras_require
)

12
tox.ini
View File

@ -156,6 +156,8 @@ envlist =
docker-tests
docs
generate
[testenv]
deps =
-c dev-requirements.txt
@ -212,7 +214,6 @@ changedir =
test-util-http: util/opentelemetry-util-http/tests
test-sdkextension-aws: sdk-extension/opentelemetry-sdk-extension-aws/tests
test-propagator-ot-trace: propagator/opentelemetry-propagator-ot-trace/tests
test-exporter-datadog: exporter/opentelemetry-exporter-datadog/tests
commands_pre =
@ -430,3 +431,12 @@ commands =
commands_post =
docker-compose down -v
[testenv:generate]
deps =
-r {toxinidir}/gen-requirements.txt
commands =
{toxinidir}/scripts/generate_setup.py
{toxinidir}/scripts/generate_instrumentation_bootstrap.py