mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-08-02 19:47:17 +08:00
Add Initial Support for Instrumenting OpenAI Python Library - Chat Completion Create (#2759)
This commit is contained in:

committed by
GitHub

parent
cef28d6f24
commit
beed0aa395
18
.github/workflows/lint_0.yml
vendored
18
.github/workflows/lint_0.yml
vendored
@ -16,6 +16,24 @@ env:
|
||||
|
||||
jobs:
|
||||
|
||||
lint-instrumentation-openai-v2:
|
||||
name: instrumentation-openai-v2
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e lint-instrumentation-openai-v2
|
||||
|
||||
lint-resource-detector-container:
|
||||
name: resource-detector-container
|
||||
runs-on: ubuntu-latest
|
||||
|
216
.github/workflows/test_0.yml
vendored
216
.github/workflows/test_0.yml
vendored
@ -16,6 +16,114 @@ env:
|
||||
|
||||
jobs:
|
||||
|
||||
py38-test-instrumentation-openai-v2_ubuntu-latest:
|
||||
name: instrumentation-openai-v2 3.8 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.8"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py38-test-instrumentation-openai-v2 -- -ra
|
||||
|
||||
py39-test-instrumentation-openai-v2_ubuntu-latest:
|
||||
name: instrumentation-openai-v2 3.9 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.9"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py39-test-instrumentation-openai-v2 -- -ra
|
||||
|
||||
py310-test-instrumentation-openai-v2_ubuntu-latest:
|
||||
name: instrumentation-openai-v2 3.10 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py310-test-instrumentation-openai-v2 -- -ra
|
||||
|
||||
py311-test-instrumentation-openai-v2_ubuntu-latest:
|
||||
name: instrumentation-openai-v2 3.11 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py311-test-instrumentation-openai-v2 -- -ra
|
||||
|
||||
py312-test-instrumentation-openai-v2_ubuntu-latest:
|
||||
name: instrumentation-openai-v2 3.12 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py312-test-instrumentation-openai-v2 -- -ra
|
||||
|
||||
pypy3-test-instrumentation-openai-v2_ubuntu-latest:
|
||||
name: instrumentation-openai-v2 pypy-3.8 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python pypy-3.8
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "pypy-3.8"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e pypy3-test-instrumentation-openai-v2 -- -ra
|
||||
|
||||
py38-test-resource-detector-container_ubuntu-latest:
|
||||
name: resource-detector-container 3.8 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
@ -4407,111 +4515,3 @@ jobs:
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py311-test-instrumentation-pymemcache-2 -- -ra
|
||||
|
||||
py311-test-instrumentation-pymemcache-3_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-3 3.11 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py311-test-instrumentation-pymemcache-3 -- -ra
|
||||
|
||||
py311-test-instrumentation-pymemcache-4_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-4 3.11 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py311-test-instrumentation-pymemcache-4 -- -ra
|
||||
|
||||
py312-test-instrumentation-pymemcache-0_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-0 3.12 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py312-test-instrumentation-pymemcache-0 -- -ra
|
||||
|
||||
py312-test-instrumentation-pymemcache-1_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-1 3.12 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py312-test-instrumentation-pymemcache-1 -- -ra
|
||||
|
||||
py312-test-instrumentation-pymemcache-2_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-2 3.12 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py312-test-instrumentation-pymemcache-2 -- -ra
|
||||
|
||||
py312-test-instrumentation-pymemcache-3_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-3 3.12 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py312-test-instrumentation-pymemcache-3 -- -ra
|
||||
|
108
.github/workflows/test_1.yml
vendored
108
.github/workflows/test_1.yml
vendored
@ -16,6 +16,114 @@ env:
|
||||
|
||||
jobs:
|
||||
|
||||
py311-test-instrumentation-pymemcache-3_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-3 3.11 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py311-test-instrumentation-pymemcache-3 -- -ra
|
||||
|
||||
py311-test-instrumentation-pymemcache-4_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-4 3.11 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py311-test-instrumentation-pymemcache-4 -- -ra
|
||||
|
||||
py312-test-instrumentation-pymemcache-0_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-0 3.12 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py312-test-instrumentation-pymemcache-0 -- -ra
|
||||
|
||||
py312-test-instrumentation-pymemcache-1_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-1 3.12 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py312-test-instrumentation-pymemcache-1 -- -ra
|
||||
|
||||
py312-test-instrumentation-pymemcache-2_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-2 3.12 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py312-test-instrumentation-pymemcache-2 -- -ra
|
||||
|
||||
py312-test-instrumentation-pymemcache-3_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-3 3.12 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo @ SHA - ${{ github.sha }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
- name: Run tests
|
||||
run: tox -e py312-test-instrumentation-pymemcache-3 -- -ra
|
||||
|
||||
py312-test-instrumentation-pymemcache-4_ubuntu-latest:
|
||||
name: instrumentation-pymemcache-4 3.12 Ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
|
66
CHANGELOG.md
66
CHANGELOG.md
@ -11,6 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
## Version 1.27.0/0.49b0 ()
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-openai-v2` Instrumentation for OpenAI >= 0.27.0
|
||||
([#2759](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2759))
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-fastapi` Add autoinstrumentation mechanism tests.
|
||||
@ -236,7 +243,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#2420](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2420))
|
||||
- `opentelemetry-instrumentation-elasticsearch` Disabling instrumentation with native OTel support enabled
|
||||
([#2524](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2524))
|
||||
- `opentelemetry-instrumentation-asyncio` Check for __name__ attribute in the coroutine
|
||||
- `opentelemetry-instrumentation-asyncio` Check for **name** attribute in the coroutine
|
||||
([#2521](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2521))
|
||||
- `opentelemetry-instrumentation-requests` Fix wrong time unit for duration histogram
|
||||
([#2553](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2553))
|
||||
@ -251,6 +258,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#2146](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2146))
|
||||
|
||||
### Fixed
|
||||
|
||||
- `opentelemetry-instrumentation-celery` Allow Celery instrumentation to be installed multiple times
|
||||
([#2342](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2342))
|
||||
- Align gRPC span status codes to OTEL specification
|
||||
@ -268,8 +276,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- AwsLambdaInstrumentor sets `cloud.account.id` span attribute
|
||||
([#2367](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2367))
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-fastapi` Add support for configuring header extraction via runtime constructor parameters
|
||||
([#2241](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2241))
|
||||
|
||||
@ -280,7 +288,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `opentelemetry-resource-detector-azure` Added 10s timeout to VM Resource Detector
|
||||
([#2119](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2119))
|
||||
- `opentelemetry-instrumentation-asyncpg` Allow AsyncPGInstrumentor to be instantiated multiple times
|
||||
([#1791](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1791))
|
||||
([#1791](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1791))
|
||||
- `opentelemetry-instrumentation-confluent-kafka` Add support for higher versions until 2.3.0 of confluent_kafka
|
||||
([#2132](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2132))
|
||||
- `opentelemetry-resource-detector-azure` Changed timeout to 4 seconds due to [timeout bug](https://github.com/open-telemetry/opentelemetry-python/issues/3644)
|
||||
@ -364,6 +372,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#152](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2013))
|
||||
|
||||
## Version 1.19.0/0.40b0 (2023-07-13)
|
||||
|
||||
- `opentelemetry-instrumentation-asgi` Add `http.server.request.size` metric
|
||||
([#1867](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1867))
|
||||
|
||||
@ -410,6 +419,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#1823](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1823))
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-kafka-python` Add instrumentation to `consume` method
|
||||
([#1786](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1786))
|
||||
|
||||
@ -460,6 +470,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#1692](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1692))
|
||||
|
||||
### Changed
|
||||
|
||||
- Update HTTP server/client instrumentation span names to comply with spec
|
||||
([#1759](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1759))
|
||||
|
||||
@ -497,7 +508,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
|
||||
- Support `aio_pika` 9.x (([#1670](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1670])
|
||||
- `opentelemetry-instrumentation-redis` Add `sanitize_query` config option to allow query sanitization. ([#1572](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1572))
|
||||
- `opentelemetry-instrumentation-redis` Add `sanitize_query` config option to allow query sanitization. ([#1572](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1572))
|
||||
- `opentelemetry-instrumentation-elasticsearch` Add optional db.statement query sanitization.
|
||||
([#1598](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1598))
|
||||
- `opentelemetry-instrumentation-celery` Record exceptions as events on the span.
|
||||
@ -521,7 +532,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#1575](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1575))
|
||||
- Fix SQLAlchemy uninstrumentation
|
||||
([#1581](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1581))
|
||||
- `opentelemetry-instrumentation-grpc` Fix code()/details() of _OpentelemetryServicerContext.
|
||||
- `opentelemetry-instrumentation-grpc` Fix code()/details() of \_OpentelemetryServicerContext.
|
||||
([#1578](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1578))
|
||||
- Fix aiopg instrumentation to work with aiopg < 2.0.0
|
||||
([#1473](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1473))
|
||||
@ -573,7 +584,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#1430](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1430))
|
||||
- `opentelemetry-instrumentation-aiohttp-client` Allow overriding of status in response hook.
|
||||
([#1394](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1394))
|
||||
- `opentelemetry-instrumentation-pymysql` Fix dbapi connection instrument wrapper has no _sock member.
|
||||
- `opentelemetry-instrumentation-pymysql` Fix dbapi connection instrument wrapper has no \_sock member.
|
||||
([#1424](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1424))
|
||||
- `opentelemetry-instrumentation-dbapi` Fix the check for the connection already being instrumented in instrument_connection().
|
||||
([#1424](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1424))
|
||||
@ -658,7 +669,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Add metric instrumentation in starlette
|
||||
([#1327](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1327))
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
- `opentelemetry-instrumentation-kafka-python`: wait for metadata
|
||||
@ -671,7 +681,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#1208](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1208))
|
||||
- `opentelemetry-instrumentation-aiohttp-client` Fix producing additional spans with each newly created ClientSession
|
||||
- ([#1246](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1246))
|
||||
- Add _is_opentelemetry_instrumented check in _InstrumentedFastAPI class
|
||||
- Add \_is_opentelemetry_instrumented check in \_InstrumentedFastAPI class
|
||||
([#1313](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1313))
|
||||
- Fix uninstrumentation of existing app instances in FastAPI
|
||||
([#1258](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1258))
|
||||
@ -690,6 +700,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#1203](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1203))
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-redis` add support to instrument RedisCluster clients
|
||||
([#1177](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1177))
|
||||
- `opentelemetry-instrumentation-sqlalchemy` Added span for the connection phase ([#1133](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1133))
|
||||
@ -702,11 +713,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [1.12.0rc2-0.32b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.12.0rc2-0.32b0) - 2022-07-01
|
||||
|
||||
|
||||
- Pyramid: Only categorize 500s server exceptions as errors
|
||||
([#1037](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1037))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix bug in system metrics by checking their configuration
|
||||
([#1129](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1129))
|
||||
- Adding escape call to fix [auto-instrumentation not producing spans on Windows](https://github.com/open-telemetry/opentelemetry-python/issues/2703).
|
||||
@ -719,8 +730,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- fixed typo in `system.network.io` metric configuration
|
||||
([#1135](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1135))
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-aiohttp-client` Add support for optional custom trace_configs argument.
|
||||
([1079](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1079))
|
||||
- `opentelemetry-instrumentation-sqlalchemy` add support to instrument multiple engines
|
||||
@ -744,10 +755,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Integrated sqlcommenter plugin into opentelemetry-instrumentation-django
|
||||
([#896](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/896))
|
||||
|
||||
|
||||
## Version 1.12.0rc1/0.31b0 (2022-05-17)
|
||||
|
||||
### Fixed
|
||||
|
||||
- `opentelemetry-instrumentation-aiohttp-client` make span attributes available to sampler
|
||||
([#1072](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1072))
|
||||
- `opentelemetry-instrumentation-aws-lambda` Fixed an issue - in some rare cases (API GW proxy integration test)
|
||||
@ -760,6 +771,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `opentelemetry-sdk-extension-aws` change timeout for AWS EC2 and EKS metadata requests from 1000 seconds and 2000 seconds to 1 second
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrument` and `opentelemetry-bootstrap` now include a `--version` flag
|
||||
([#1065](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1065))
|
||||
- `opentelemetry-instrumentation-redis` now instruments asynchronous Redis clients, if the installed redis-py includes async support (>=4.2.0).
|
||||
@ -767,22 +779,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `opentelemetry-instrumentation-boto3sqs` added AWS's SQS instrumentation.
|
||||
([#1081](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1081))
|
||||
|
||||
|
||||
## Version 1.11.1/0.30b1 (2022-04-21)
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-starlette` Capture custom request/response headers in span attributes
|
||||
([#1046](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1046))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Prune autoinstrumentation sitecustomize module directory from PYTHONPATH immediately
|
||||
([#1066](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1066))
|
||||
|
||||
|
||||
## Version 1.11.0/0.30b0 (2022-04-18)
|
||||
|
||||
### Fixed
|
||||
- `opentelemetry-instrumentation-pyramid` Fixed which package is the correct caller in _traced_init.
|
||||
|
||||
- `opentelemetry-instrumentation-pyramid` Fixed which package is the correct caller in \_traced_init.
|
||||
([#830](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/830))
|
||||
- `opentelemetry-instrumentation-tornado` Fix Tornado errors mapping to 500
|
||||
([#1048](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1048))
|
||||
@ -816,7 +829,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `opentelemetry-instrumentation-pyramid` Pyramid: Capture custom request/response headers in span attributes
|
||||
([#1022](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1022))
|
||||
|
||||
|
||||
## Version 1.10.0/0.29b0 (2022-03-10)
|
||||
|
||||
- `opentelemetry-instrumentation-wsgi` Capture custom request/response headers in span attributes
|
||||
@ -830,7 +842,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- `opentelemetry-instrumentation-aws-lambda` `SpanKind.SERVER` by default, add more cases for `SpanKind.CONSUMER` services. ([#926](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/926))
|
||||
- `opentelemetry-instrumentation-sqlalchemy` added experimental sql commenter capability
|
||||
([#924](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/924))
|
||||
([#924](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/924))
|
||||
- `opentelemetry-contrib-instrumentations` added new meta-package that installs all contrib instrumentations.
|
||||
([#681](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/681))
|
||||
- `opentelemetry-instrumentation-dbapi` add experimental sql commenter capability
|
||||
@ -869,12 +881,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Version 1.9.0/0.28b0 (2022-01-26)
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-pyramid` Pyramid: Conditionally create SERVER spans
|
||||
([#869](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/869))
|
||||
- `opentelemetry-instrumentation-grpc` added `trailing_metadata` to _OpenTelemetryServicerContext.
|
||||
- `opentelemetry-instrumentation-grpc` added `trailing_metadata` to \_OpenTelemetryServicerContext.
|
||||
([#871](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/871))
|
||||
- `opentelemetry-instrumentation-asgi` now returns a `traceresponse` response header.
|
||||
([#817](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/817))
|
||||
@ -908,12 +919,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `opentelemetry-instrumentation-aiohttp-client` aiohttp: Remove `span_name` from docs
|
||||
([#857](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/857))
|
||||
|
||||
|
||||
## Version 1.8.0/0.27b0 (2021-12-17)
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-aws-lambda` Adds support for configurable flush timeout via `OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT` property. ([#825](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/825))
|
||||
- `opentelemetry-instrumentation-aws-lambda` Adds support for configurable flush timeout via `OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT` property. ([#825](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/825))
|
||||
- `opentelemetry-instrumentation-pika` Adds support for versions between `0.12.0` to `1.0.0`. ([#837](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/837))
|
||||
|
||||
### Fixed
|
||||
@ -983,13 +993,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#755](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/755))
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-pika` Add `publish_hook` and `consume_hook` callbacks passed as arguments to the instrument method
|
||||
([#763](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/763))
|
||||
|
||||
|
||||
## Version 1.6.1/0.25b1 (2021-10-18)
|
||||
|
||||
### Changed
|
||||
|
||||
- `opentelemetry-util-http` no longer contains an instrumentation entrypoint and will not be loaded
|
||||
automatically by the auto instrumentor.
|
||||
([#745](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/745))
|
||||
@ -1003,7 +1014,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#760](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/760))
|
||||
|
||||
## Version 1.6.0/0.25b0 (2021-10-13)
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-sdk-extension-aws` Release AWS Python SDK Extension as 1.0.0
|
||||
([#667](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/667))
|
||||
- `opentelemetry-instrumentation-urllib3`, `opentelemetry-instrumentation-requests`
|
||||
@ -1030,6 +1043,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#391](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/391))
|
||||
|
||||
### Changed
|
||||
|
||||
- `opentelemetry-instrumentation-flask` Fix `RuntimeError: Working outside of request context`
|
||||
([#734](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/734))
|
||||
- `opentelemetry-propagators-aws-xray` Rename `AwsXRayFormat` to `AwsXRayPropagator`
|
||||
@ -1060,6 +1074,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## Version 1.5.0/0.24b0 (2021-08-26)
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-sdk-extension-aws` Add AWS resource detectors to extension package
|
||||
([#586](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/586))
|
||||
- `opentelemetry-instrumentation-asgi`, `opentelemetry-instrumentation-aiohttp-client`, `openetelemetry-instrumentation-fastapi`,
|
||||
@ -1078,10 +1093,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## Version 1.4.0/0.23b0 (2021-07-21)
|
||||
|
||||
### Removed
|
||||
|
||||
- Move `opentelemetry-instrumentation` to the core repo.
|
||||
([#595](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/595))
|
||||
|
||||
### Changed
|
||||
|
||||
- `opentelemetry-instrumentation-falcon` added support for Falcon 3.
|
||||
([#607](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/607))
|
||||
- `opentelemetry-instrumentation-tornado` properly instrument work done in tornado on_finish method.
|
||||
@ -1129,12 +1146,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#568](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/568))
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-httpx` Add `httpx` instrumentation
|
||||
([#461](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/461))
|
||||
|
||||
## Version 1.3.0/0.22b0 (2021-06-01)
|
||||
|
||||
### 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.
|
||||
@ -1151,6 +1170,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([#488](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/488))
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-botocore` now supports
|
||||
context propagation for lambda invoke via Payload embedded headers.
|
||||
([#458](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/458))
|
||||
@ -1160,6 +1180,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## Version 1.2.0/0.21b0 (2021-05-11)
|
||||
|
||||
### Changed
|
||||
|
||||
- Instrumentation packages don't specify the libraries they instrument as dependencies
|
||||
anymore. Instead, they verify the correct version of libraries are installed at runtime.
|
||||
([#475](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/475))
|
||||
@ -1711,6 +1732,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `opentelemetry-ext-http-requests` Updates for core library changes
|
||||
|
||||
- `Added support for PyPy3` Initial release
|
||||
|
||||
## [#1033](https://github.com/open-telemetryopentelemetry-python-contrib/issues/1033)
|
||||
|
||||
## Version 0.1a0 (2019-09-30)
|
||||
@ -1725,7 +1747,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `opentelemetry-resource-detector-azure` Added 10s timeout to VM Resource Detector
|
||||
([#2119](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2119))
|
||||
- `opentelemetry-instrumentation-asyncpg` Allow AsyncPGInstrumentor to be instantiated multiple times
|
||||
([#1791](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1791))
|
||||
([#1791](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1791))
|
||||
- `opentelemetry-instrumentation-confluent-kafka` Add support for higher versions until 2.3.0 of confluent_kafka
|
||||
([#2132](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2132))
|
||||
- `opentelemetry-resource-detector-azure` Changed timeout to 4 seconds due to [timeout bug](https://github.com/open-telemetry/opentelemetry-python/issues/3644)
|
||||
|
@ -50,6 +50,7 @@ packages=
|
||||
opentelemetry-resource-detector-azure
|
||||
opentelemetry-sdk-extension-aws
|
||||
opentelemetry-propagator-aws-xray
|
||||
opentelemetry-instrumentation-openai-v2
|
||||
opentelemetry-instrumentation-test
|
||||
|
||||
[lintroots]
|
||||
|
@ -29,6 +29,7 @@
|
||||
| [opentelemetry-instrumentation-logging](./opentelemetry-instrumentation-logging) | logging | No | experimental
|
||||
| [opentelemetry-instrumentation-mysql](./opentelemetry-instrumentation-mysql) | mysql-connector-python >= 8.0, < 10.0 | No | experimental
|
||||
| [opentelemetry-instrumentation-mysqlclient](./opentelemetry-instrumentation-mysqlclient) | mysqlclient < 3 | No | experimental
|
||||
| [opentelemetry-instrumentation-openai-v2](./opentelemetry-instrumentation-openai-v2) | openai >= 1.26.0 | No | experimental
|
||||
| [opentelemetry-instrumentation-pika](./opentelemetry-instrumentation-pika) | pika >= 0.12.0 | No | experimental
|
||||
| [opentelemetry-instrumentation-psycopg](./opentelemetry-instrumentation-psycopg) | psycopg >= 3.1.0 | No | experimental
|
||||
| [opentelemetry-instrumentation-psycopg2](./opentelemetry-instrumentation-psycopg2) | psycopg2 >= 2.7.3.1 | No | experimental
|
||||
|
201
instrumentation/opentelemetry-instrumentation-openai-v2/LICENSE
Normal file
201
instrumentation/opentelemetry-instrumentation-openai-v2/LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
@ -0,0 +1,26 @@
|
||||
OpenTelemetry OpenAI Instrumentation
|
||||
====================================
|
||||
|
||||
|pypi|
|
||||
|
||||
.. |pypi| image:: https://badge.fury.io/py/opentelemetry-instrumentation-openai-v2.svg
|
||||
:target: https://pypi.org/project/opentelemetry-instrumentation-openai-v2/
|
||||
|
||||
Instrumentation with OpenAI that supports the openai library and is
|
||||
specified to trace_integration using 'OpenAI'.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
::
|
||||
|
||||
pip install opentelemetry-instrumentation-openai-v2
|
||||
|
||||
|
||||
References
|
||||
----------
|
||||
* `OpenTelemetry OpenAI Instrumentation <https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/openai/openai.html>`_
|
||||
* `OpenTelemetry Project <https://opentelemetry.io/>`_
|
||||
* `OpenTelemetry Python Examples <https://github.com/open-telemetry/opentelemetry-python/tree/main/docs/examples>`_
|
||||
|
@ -0,0 +1,54 @@
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "opentelemetry-instrumentation-openai-v2"
|
||||
dynamic = ["version"]
|
||||
description = "OpenTelemetry Official OpenAI instrumentation"
|
||||
readme = "README.rst"
|
||||
license = "Apache-2.0"
|
||||
requires-python = ">=3.8"
|
||||
authors = [
|
||||
{ name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" },
|
||||
]
|
||||
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.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation ~= 0.48b0",
|
||||
"opentelemetry-semantic-conventions ~= 0.48b0"
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
instruments = [
|
||||
"openai >= 1.0.0",
|
||||
]
|
||||
|
||||
[project.entry-points.opentelemetry_instrumentor]
|
||||
openai = "opentelemetry.instrumentation.openai_v2:OpenAIInstrumentor"
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-openai-v2"
|
||||
|
||||
[tool.hatch.version]
|
||||
path = "src/opentelemetry/instrumentation/openai_v2/version.py"
|
||||
|
||||
[tool.hatch.build.targets.sdist]
|
||||
include = [
|
||||
"/src",
|
||||
"/tests",
|
||||
]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/opentelemetry"]
|
@ -0,0 +1,80 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
OpenAI client instrumentation supporting `openai`, it can be enabled by
|
||||
using ``OpenAIInstrumentor``.
|
||||
|
||||
.. _openai: https://pypi.org/project/openai/
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
.. code:: python
|
||||
|
||||
from openai import OpenAI
|
||||
from opentelemetry.instrumentation.openai import OpenAIInstrumentor
|
||||
|
||||
OpenAIInstrumentor().instrument()
|
||||
|
||||
client = OpenAI()
|
||||
response = client.chat.completions.create(
|
||||
model="gpt-4o-mini",
|
||||
messages=[
|
||||
{"role": "user", "content": "Write a short poem on open telemetry."},
|
||||
],
|
||||
)
|
||||
|
||||
API
|
||||
---
|
||||
"""
|
||||
|
||||
|
||||
from typing import Collection
|
||||
|
||||
from wrapt import wrap_function_wrapper
|
||||
|
||||
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
||||
from opentelemetry.instrumentation.openai_v2.package import _instruments
|
||||
from opentelemetry.instrumentation.utils import unwrap
|
||||
from opentelemetry.semconv.schemas import Schemas
|
||||
from opentelemetry.trace import get_tracer
|
||||
|
||||
from .patch import chat_completions_create
|
||||
|
||||
|
||||
class OpenAIInstrumentor(BaseInstrumentor):
|
||||
|
||||
def instrumentation_dependencies(self) -> Collection[str]:
|
||||
return _instruments
|
||||
|
||||
def _instrument(self, **kwargs):
|
||||
"""Enable OpenAI instrumentation."""
|
||||
tracer_provider = kwargs.get("tracer_provider")
|
||||
tracer = get_tracer(
|
||||
__name__,
|
||||
"",
|
||||
tracer_provider,
|
||||
schema_url=Schemas.V1_27_0.value,
|
||||
)
|
||||
wrap_function_wrapper(
|
||||
module="openai.resources.chat.completions",
|
||||
name="Completions.create",
|
||||
wrapper=chat_completions_create(tracer),
|
||||
)
|
||||
|
||||
def _uninstrument(self, **kwargs):
|
||||
import openai
|
||||
|
||||
unwrap(openai.resources.chat.completions.Completions, "create")
|
@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
|
||||
_instruments = ("openai >= 1.26.0",)
|
@ -0,0 +1,316 @@
|
||||
# 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
|
||||
|
||||
from opentelemetry.semconv._incubating.attributes import (
|
||||
gen_ai_attributes as GenAIAttributes,
|
||||
)
|
||||
from opentelemetry.semconv.attributes import (
|
||||
error_attributes as ErrorAttributes,
|
||||
)
|
||||
from opentelemetry.trace import Span, SpanKind, Tracer
|
||||
from opentelemetry.trace.status import Status, StatusCode
|
||||
|
||||
from .utils import (
|
||||
extract_content,
|
||||
extract_tools_prompt,
|
||||
get_llm_request_attributes,
|
||||
is_streaming,
|
||||
set_event_completion,
|
||||
set_event_prompt,
|
||||
set_span_attribute,
|
||||
silently_fail,
|
||||
)
|
||||
|
||||
|
||||
def chat_completions_create(tracer: Tracer):
|
||||
"""Wrap the `create` method of the `ChatCompletion` class to trace it."""
|
||||
|
||||
def traced_method(wrapped, instance, args, kwargs):
|
||||
|
||||
llm_prompts = []
|
||||
|
||||
for item in kwargs.get("messages", []):
|
||||
tools_prompt = extract_tools_prompt(item)
|
||||
llm_prompts.append(tools_prompt if tools_prompt else item)
|
||||
|
||||
span_attributes = {**get_llm_request_attributes(kwargs)}
|
||||
span_name = f"{span_attributes[GenAIAttributes.GEN_AI_OPERATION_NAME]} {span_attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL]}"
|
||||
|
||||
span = tracer.start_span(
|
||||
name=span_name, kind=SpanKind.CLIENT, attributes=span_attributes
|
||||
)
|
||||
if span.is_recording():
|
||||
_set_input_attributes(span, span_attributes)
|
||||
set_event_prompt(span, json.dumps(llm_prompts))
|
||||
|
||||
try:
|
||||
result = wrapped(*args, **kwargs)
|
||||
if is_streaming(kwargs):
|
||||
return StreamWrapper(
|
||||
result,
|
||||
span,
|
||||
function_call=kwargs.get("functions") is not None,
|
||||
tool_calls=kwargs.get("tools") is not None,
|
||||
)
|
||||
else:
|
||||
if span.is_recording():
|
||||
_set_response_attributes(span, result)
|
||||
span.end()
|
||||
return result
|
||||
|
||||
except Exception as error:
|
||||
span.set_status(Status(StatusCode.ERROR, str(error)))
|
||||
if span.is_recording():
|
||||
span.set_attribute(
|
||||
ErrorAttributes.ERROR_TYPE, type(error).__qualname__
|
||||
)
|
||||
span.end()
|
||||
raise
|
||||
|
||||
return traced_method
|
||||
|
||||
|
||||
@silently_fail
|
||||
def _set_input_attributes(span, attributes):
|
||||
for field, value in attributes.items():
|
||||
set_span_attribute(span, field, value)
|
||||
|
||||
|
||||
@silently_fail
|
||||
def _set_response_attributes(span, result):
|
||||
set_span_attribute(
|
||||
span, GenAIAttributes.GEN_AI_RESPONSE_MODEL, result.model
|
||||
)
|
||||
if getattr(result, "choices", None):
|
||||
choices = result.choices
|
||||
responses = [
|
||||
{
|
||||
"role": (
|
||||
choice.message.role
|
||||
if choice.message and choice.message.role
|
||||
else "assistant"
|
||||
),
|
||||
"content": extract_content(choice),
|
||||
**(
|
||||
{
|
||||
"content_filter_results": choice[
|
||||
"content_filter_results"
|
||||
]
|
||||
}
|
||||
if "content_filter_results" in choice
|
||||
else {}
|
||||
),
|
||||
}
|
||||
for choice in choices
|
||||
]
|
||||
finish_reasons = []
|
||||
for choice in choices:
|
||||
finish_reasons.append(choice.finish_reason or "error")
|
||||
|
||||
set_span_attribute(
|
||||
span,
|
||||
GenAIAttributes.GEN_AI_RESPONSE_FINISH_REASONS,
|
||||
finish_reasons,
|
||||
)
|
||||
set_event_completion(span, responses)
|
||||
|
||||
if getattr(result, "id", None):
|
||||
set_span_attribute(span, GenAIAttributes.GEN_AI_RESPONSE_ID, result.id)
|
||||
|
||||
# Get the usage
|
||||
if getattr(result, "usage", None):
|
||||
set_span_attribute(
|
||||
span,
|
||||
GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS,
|
||||
result.usage.prompt_tokens,
|
||||
)
|
||||
set_span_attribute(
|
||||
span,
|
||||
GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS,
|
||||
result.usage.completion_tokens,
|
||||
)
|
||||
|
||||
|
||||
class StreamWrapper:
|
||||
span: Span
|
||||
response_id: str = ""
|
||||
response_model: str = ""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
stream,
|
||||
span,
|
||||
prompt_tokens=0,
|
||||
function_call=False,
|
||||
tool_calls=False,
|
||||
):
|
||||
self.stream = stream
|
||||
self.span = span
|
||||
self.prompt_tokens = prompt_tokens
|
||||
self.function_call = function_call
|
||||
self.tool_calls = tool_calls
|
||||
self.result_content = []
|
||||
self.completion_tokens = 0
|
||||
self._span_started = False
|
||||
self.setup()
|
||||
|
||||
def setup(self):
|
||||
if not self._span_started:
|
||||
self._span_started = True
|
||||
|
||||
def cleanup(self):
|
||||
if self._span_started:
|
||||
if self.response_model:
|
||||
set_span_attribute(
|
||||
self.span,
|
||||
GenAIAttributes.GEN_AI_RESPONSE_MODEL,
|
||||
self.response_model,
|
||||
)
|
||||
|
||||
if self.response_id:
|
||||
set_span_attribute(
|
||||
self.span,
|
||||
GenAIAttributes.GEN_AI_RESPONSE_ID,
|
||||
self.response_id,
|
||||
)
|
||||
|
||||
set_span_attribute(
|
||||
self.span,
|
||||
GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS,
|
||||
self.prompt_tokens,
|
||||
)
|
||||
set_span_attribute(
|
||||
self.span,
|
||||
GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS,
|
||||
self.completion_tokens,
|
||||
)
|
||||
set_event_completion(
|
||||
self.span,
|
||||
[
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "".join(self.result_content),
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
self.span.end()
|
||||
self._span_started = False
|
||||
|
||||
def __enter__(self):
|
||||
self.setup()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
try:
|
||||
if exc_type is not None:
|
||||
self.span.set_status(Status(StatusCode.ERROR, str(exc_val)))
|
||||
self.span.set_attribute(
|
||||
ErrorAttributes.ERROR_TYPE, exc_type.__qualname__
|
||||
)
|
||||
finally:
|
||||
self.cleanup()
|
||||
return False # Propagate the exception
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
try:
|
||||
chunk = next(self.stream)
|
||||
self.process_chunk(chunk)
|
||||
return chunk
|
||||
except StopIteration:
|
||||
self.cleanup()
|
||||
raise
|
||||
except Exception as error:
|
||||
self.span.set_status(Status(StatusCode.ERROR, str(error)))
|
||||
self.span.set_attribute(
|
||||
ErrorAttributes.ERROR_TYPE, type(error).__qualname__
|
||||
)
|
||||
self.cleanup()
|
||||
raise
|
||||
|
||||
def set_response_model(self, chunk):
|
||||
if self.response_model:
|
||||
return
|
||||
|
||||
if getattr(chunk, "model", None):
|
||||
self.response_model = chunk.model
|
||||
|
||||
def set_response_id(self, chunk):
|
||||
if self.response_id:
|
||||
return
|
||||
|
||||
if getattr(chunk, "id", None):
|
||||
self.response_id = chunk.id
|
||||
|
||||
def build_streaming_response(self, chunk):
|
||||
if getattr(chunk, "choices", None) is None:
|
||||
return
|
||||
|
||||
choices = chunk.choices
|
||||
content = []
|
||||
if not self.function_call and not self.tool_calls:
|
||||
for choice in choices:
|
||||
if choice.delta and choice.delta.content is not None:
|
||||
content = [choice.delta.content]
|
||||
|
||||
elif self.function_call:
|
||||
for choice in choices:
|
||||
if (
|
||||
choice.delta
|
||||
and choice.delta.function_call is not None
|
||||
and choice.delta.function_call.arguments is not None
|
||||
):
|
||||
content = [choice.delta.function_call.arguments]
|
||||
|
||||
elif self.tool_calls:
|
||||
for choice in choices:
|
||||
if choice.delta and choice.delta.tool_calls is not None:
|
||||
toolcalls = choice.delta.tool_calls
|
||||
content = []
|
||||
for tool_call in toolcalls:
|
||||
if (
|
||||
tool_call
|
||||
and tool_call.function is not None
|
||||
and tool_call.function.arguments is not None
|
||||
):
|
||||
content.append(tool_call.function.arguments)
|
||||
|
||||
finish_reasons = []
|
||||
for choice in choices:
|
||||
finish_reasons.append(choice.finish_reason or "error")
|
||||
|
||||
set_span_attribute(
|
||||
self.span,
|
||||
GenAIAttributes.GEN_AI_RESPONSE_FINISH_REASONS,
|
||||
finish_reasons,
|
||||
)
|
||||
if content:
|
||||
self.result_content.append(content[0])
|
||||
|
||||
def set_usage(self, chunk):
|
||||
if getattr(chunk, "usage", None):
|
||||
self.completion_tokens = chunk.usage.completion_tokens
|
||||
self.prompt_tokens = chunk.usage.prompt_tokens
|
||||
|
||||
def process_chunk(self, chunk):
|
||||
self.set_response_id(chunk)
|
||||
self.set_response_model(chunk)
|
||||
self.build_streaming_response(chunk)
|
||||
self.set_usage(chunk)
|
@ -0,0 +1,165 @@
|
||||
# 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 logging
|
||||
from typing import Optional, Union
|
||||
|
||||
from openai import NOT_GIVEN
|
||||
|
||||
from opentelemetry.semconv._incubating.attributes import (
|
||||
gen_ai_attributes as GenAIAttributes,
|
||||
)
|
||||
|
||||
|
||||
def silently_fail(func):
|
||||
"""
|
||||
A decorator that catches exceptions thrown by the decorated function and logs them as warnings.
|
||||
"""
|
||||
|
||||
logger = logging.getLogger(func.__module__)
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception as exception:
|
||||
logger.warning(
|
||||
"Failed to execute %s, error: %s",
|
||||
func.__name__,
|
||||
str(exception),
|
||||
)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def extract_content(choice):
|
||||
if getattr(choice, "message", None) is None:
|
||||
return ""
|
||||
|
||||
# Check if choice.message exists and has a content attribute
|
||||
message = choice.message
|
||||
if getattr(message, "content", None):
|
||||
return choice.message.content
|
||||
|
||||
# Check if choice.message has tool_calls and extract information accordingly
|
||||
elif getattr(message, "tool_calls", None):
|
||||
result = [
|
||||
{
|
||||
"id": tool_call.id,
|
||||
"type": tool_call.type,
|
||||
"function": {
|
||||
"name": tool_call.function.name,
|
||||
"arguments": tool_call.function.arguments,
|
||||
},
|
||||
}
|
||||
for tool_call in choice.message.tool_calls
|
||||
]
|
||||
return result
|
||||
|
||||
# Check if choice.message has a function_call and extract information accordingly
|
||||
elif getattr(message, "function_call", None):
|
||||
return {
|
||||
"name": choice.message.function_call.name,
|
||||
"arguments": choice.message.function_call.arguments,
|
||||
}
|
||||
|
||||
# Return an empty string if none of the above conditions are met
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
def extract_tools_prompt(item):
|
||||
tool_calls = getattr(item, "tool_calls", None)
|
||||
if tool_calls is None:
|
||||
return
|
||||
|
||||
calls = []
|
||||
for tool_call in tool_calls:
|
||||
tool_call_dict = {
|
||||
"id": getattr(tool_call, "id", ""),
|
||||
"type": getattr(tool_call, "type", ""),
|
||||
}
|
||||
|
||||
if hasattr(tool_call, "function"):
|
||||
tool_call_dict["function"] = {
|
||||
"name": getattr(tool_call.function, "name", ""),
|
||||
"arguments": getattr(tool_call.function, "arguments", ""),
|
||||
}
|
||||
calls.append(tool_call_dict)
|
||||
return calls
|
||||
|
||||
|
||||
def set_event_prompt(span, prompt):
|
||||
span.add_event(
|
||||
name="gen_ai.content.prompt",
|
||||
attributes={
|
||||
GenAIAttributes.GEN_AI_PROMPT: prompt,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def set_span_attributes(span, attributes: dict):
|
||||
for field, value in attributes.model_dump(by_alias=True).items():
|
||||
set_span_attribute(span, field, value)
|
||||
|
||||
|
||||
def set_event_completion(span, result_content):
|
||||
span.add_event(
|
||||
name="gen_ai.content.completion",
|
||||
attributes={
|
||||
GenAIAttributes.GEN_AI_COMPLETION: json.dumps(result_content),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def set_span_attribute(span, name, value):
|
||||
if non_numerical_value_is_set(value) is False:
|
||||
return
|
||||
|
||||
span.set_attribute(name, value)
|
||||
|
||||
|
||||
def is_streaming(kwargs):
|
||||
return non_numerical_value_is_set(kwargs.get("stream"))
|
||||
|
||||
|
||||
def non_numerical_value_is_set(value: Optional[Union[bool, str]]):
|
||||
return bool(value) and value != NOT_GIVEN
|
||||
|
||||
|
||||
def get_llm_request_attributes(
|
||||
kwargs,
|
||||
operation_name=GenAIAttributes.GenAiOperationNameValues.CHAT.value,
|
||||
):
|
||||
|
||||
attributes = {
|
||||
GenAIAttributes.GEN_AI_OPERATION_NAME: operation_name,
|
||||
GenAIAttributes.GEN_AI_SYSTEM: GenAIAttributes.GenAiSystemValues.OPENAI.value,
|
||||
GenAIAttributes.GEN_AI_REQUEST_MODEL: kwargs.get(
|
||||
"model", "gpt-3.5-turbo"
|
||||
),
|
||||
GenAIAttributes.GEN_AI_REQUEST_TEMPERATURE: kwargs.get("temperature"),
|
||||
GenAIAttributes.GEN_AI_REQUEST_TOP_P: kwargs.get("p")
|
||||
or kwargs.get("top_p"),
|
||||
GenAIAttributes.GEN_AI_REQUEST_MAX_TOKENS: kwargs.get("max_tokens"),
|
||||
GenAIAttributes.GEN_AI_REQUEST_PRESENCE_PENALTY: kwargs.get(
|
||||
"presence_penalty"
|
||||
),
|
||||
GenAIAttributes.GEN_AI_REQUEST_FREQUENCY_PENALTY: kwargs.get(
|
||||
"frequency_penalty"
|
||||
),
|
||||
}
|
||||
|
||||
# filter out None values
|
||||
return {k: v for k, v in attributes.items() if v is not None}
|
@ -0,0 +1,15 @@
|
||||
# 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__ = "2.0.0.dev"
|
@ -0,0 +1,11 @@
|
||||
openai==1.26.0
|
||||
pydantic==2.8.2
|
||||
Deprecated==1.2.14
|
||||
importlib-metadata==6.11.0
|
||||
packaging==24.0
|
||||
pytest==7.4.4
|
||||
pytest-vcr==1.0.2
|
||||
wrapt==1.16.0
|
||||
|
||||
-e opentelemetry-instrumentation
|
||||
-e instrumentation/opentelemetry-instrumentation-openai-v2
|
@ -0,0 +1,92 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"messages": [{"role": "user", "content": "Say this is a test"}], "model":
|
||||
"gpt-4", "stream": false}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '100'
|
||||
content-type:
|
||||
- application/json
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.47.0
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.47.0
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.11.5
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: "{\n \"id\": \"chatcmpl-AC6ajKKHHpvf6x2Qm35t6m3QE8qli\",\n \"object\":
|
||||
\"chat.completion\",\n \"created\": 1727448637,\n \"model\": \"gpt-4-0613\",\n
|
||||
\ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\":
|
||||
\"assistant\",\n \"content\": \"This is a test.\",\n \"refusal\":
|
||||
null\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n
|
||||
\ }\n ],\n \"usage\": {\n \"prompt_tokens\": 12,\n \"completion_tokens\":
|
||||
5,\n \"total_tokens\": 17,\n \"completion_tokens_details\": {\n \"reasoning_tokens\":
|
||||
0\n }\n },\n \"system_fingerprint\": null\n}\n"
|
||||
headers:
|
||||
CF-Cache-Status:
|
||||
- DYNAMIC
|
||||
CF-RAY:
|
||||
- 8c9c4e9b7fb674d8-PMO
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 27 Sep 2024 14:50:37 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Set-Cookie: test_set_cookie
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
content-length:
|
||||
- '551'
|
||||
openai-organization: test_organization
|
||||
openai-processing-ms:
|
||||
- '434'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '10000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '1000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '9999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '999977'
|
||||
x-ratelimit-reset-requests:
|
||||
- 6ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 1ms
|
||||
x-request-id:
|
||||
- req_5f2690abaf909a9f047488694d44495e
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
@ -0,0 +1,113 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"messages": [{"role": "user", "content": "Say this is a test"}], "model":
|
||||
"gpt-4", "stream": true, "stream_options": {"include_usage": true}}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '142'
|
||||
content-type:
|
||||
- application/json
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.47.0
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.47.0
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.11.5
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: 'data: {"id":"chatcmpl-AC6akONKCxc8HS63qZ08HyjeTSq6p","object":"chat.completion.chunk","created":1727448638,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-AC6akONKCxc8HS63qZ08HyjeTSq6p","object":"chat.completion.chunk","created":1727448638,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"This"},"logprobs":null,"finish_reason":null}],"usage":null}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-AC6akONKCxc8HS63qZ08HyjeTSq6p","object":"chat.completion.chunk","created":1727448638,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
is"},"logprobs":null,"finish_reason":null}],"usage":null}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-AC6akONKCxc8HS63qZ08HyjeTSq6p","object":"chat.completion.chunk","created":1727448638,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
a"},"logprobs":null,"finish_reason":null}],"usage":null}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-AC6akONKCxc8HS63qZ08HyjeTSq6p","object":"chat.completion.chunk","created":1727448638,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
|
||||
test"},"logprobs":null,"finish_reason":null}],"usage":null}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-AC6akONKCxc8HS63qZ08HyjeTSq6p","object":"chat.completion.chunk","created":1727448638,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-AC6akONKCxc8HS63qZ08HyjeTSq6p","object":"chat.completion.chunk","created":1727448638,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null}
|
||||
|
||||
|
||||
data: {"id":"chatcmpl-AC6akONKCxc8HS63qZ08HyjeTSq6p","object":"chat.completion.chunk","created":1727448638,"model":"gpt-4-0613","system_fingerprint":null,"choices":[],"usage":{"prompt_tokens":12,"completion_tokens":5,"total_tokens":17,"completion_tokens_details":{"reasoning_tokens":0}}}
|
||||
|
||||
|
||||
data: [DONE]
|
||||
|
||||
|
||||
'
|
||||
headers:
|
||||
CF-Cache-Status:
|
||||
- DYNAMIC
|
||||
CF-RAY:
|
||||
- 8c9c4ea489d57948-PMO
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- text/event-stream; charset=utf-8
|
||||
Date:
|
||||
- Fri, 27 Sep 2024 14:50:38 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Set-Cookie: test_set_cookie
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
openai-organization: test_organization
|
||||
openai-processing-ms:
|
||||
- '161'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '10000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '1000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '9999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '999977'
|
||||
x-ratelimit-reset-requests:
|
||||
- 6ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 1ms
|
||||
x-request-id:
|
||||
- req_3fa9ac9f3693c712e4c377e26d203e58
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
@ -0,0 +1,70 @@
|
||||
"""Unit tests configuration module."""
|
||||
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from openai import OpenAI
|
||||
|
||||
from opentelemetry import trace
|
||||
from opentelemetry.instrumentation.openai_v2 import OpenAIInstrumentor
|
||||
from opentelemetry.sdk.trace import TracerProvider
|
||||
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
|
||||
from opentelemetry.sdk.trace.export.in_memory_span_exporter import (
|
||||
InMemorySpanExporter,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def exporter():
|
||||
exporter = InMemorySpanExporter()
|
||||
processor = SimpleSpanProcessor(exporter)
|
||||
|
||||
provider = TracerProvider()
|
||||
provider.add_span_processor(processor)
|
||||
trace.set_tracer_provider(provider)
|
||||
|
||||
return exporter
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clear_exporter(exporter):
|
||||
exporter.clear()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def environment():
|
||||
if not os.getenv("OPENAI_API_KEY"):
|
||||
os.environ["OPENAI_API_KEY"] = "test-api-key"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def openai_client():
|
||||
return OpenAI()
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vcr_config():
|
||||
return {
|
||||
"filter_headers": ["authorization", "api-key"],
|
||||
"decode_compressed_response": True,
|
||||
"before_record_response": scrub_response_headers,
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def instrument():
|
||||
OpenAIInstrumentor().instrument()
|
||||
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def uninstrument():
|
||||
OpenAIInstrumentor().uninstrument()
|
||||
|
||||
|
||||
def scrub_response_headers(response):
|
||||
"""
|
||||
This scrubs sensitive response headers. Note they are case-sensitive!
|
||||
"""
|
||||
response["headers"]["openai-organization"] = "test_organization"
|
||||
response["headers"]["Set-Cookie"] = "test_set_cookie"
|
||||
return response
|
@ -0,0 +1,157 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from opentelemetry.semconv._incubating.attributes import (
|
||||
gen_ai_attributes as GenAIAttributes,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_chat_completion(exporter, openai_client):
|
||||
llm_model_value = "gpt-4"
|
||||
messages_value = [{"role": "user", "content": "Say this is a test"}]
|
||||
|
||||
kwargs = {
|
||||
"model": llm_model_value,
|
||||
"messages": messages_value,
|
||||
"stream": False,
|
||||
}
|
||||
|
||||
response = openai_client.chat.completions.create(**kwargs)
|
||||
spans = exporter.get_finished_spans()
|
||||
chat_completion_span = spans[0]
|
||||
# assert that the span name is correct
|
||||
assert chat_completion_span.name == f"chat {llm_model_value}"
|
||||
|
||||
attributes = chat_completion_span.attributes
|
||||
operation_name = attributes[GenAIAttributes.GEN_AI_OPERATION_NAME]
|
||||
system = attributes[GenAIAttributes.GEN_AI_SYSTEM]
|
||||
request_model = attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL]
|
||||
response_model = attributes[GenAIAttributes.GEN_AI_RESPONSE_MODEL]
|
||||
response_id = attributes[GenAIAttributes.GEN_AI_RESPONSE_ID]
|
||||
input_tokens = attributes[GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS]
|
||||
output_tokens = attributes[GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS]
|
||||
# assert that the attributes are correct
|
||||
assert (
|
||||
operation_name == GenAIAttributes.GenAiOperationNameValues.CHAT.value
|
||||
)
|
||||
assert system == GenAIAttributes.GenAiSystemValues.OPENAI.value
|
||||
assert request_model == llm_model_value
|
||||
assert response_model == response.model
|
||||
assert response_id == response.id
|
||||
assert input_tokens == response.usage.prompt_tokens
|
||||
assert output_tokens == response.usage.completion_tokens
|
||||
|
||||
events = chat_completion_span.events
|
||||
|
||||
# assert that the prompt and completion events are present
|
||||
prompt_event = list(
|
||||
filter(
|
||||
lambda event: event.name == "gen_ai.content.prompt",
|
||||
events,
|
||||
)
|
||||
)
|
||||
completion_event = list(
|
||||
filter(
|
||||
lambda event: event.name == "gen_ai.content.completion",
|
||||
events,
|
||||
)
|
||||
)
|
||||
|
||||
assert prompt_event
|
||||
assert completion_event
|
||||
|
||||
# assert that the prompt and completion events have the correct attributes
|
||||
assert prompt_event[0].attributes[
|
||||
GenAIAttributes.GEN_AI_PROMPT
|
||||
] == json.dumps(messages_value)
|
||||
|
||||
assert (
|
||||
json.loads(
|
||||
completion_event[0].attributes[GenAIAttributes.GEN_AI_COMPLETION]
|
||||
)[0]["content"]
|
||||
== response.choices[0].message.content
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_chat_completion_streaming(exporter, openai_client):
|
||||
llm_model_value = "gpt-4"
|
||||
messages_value = [{"role": "user", "content": "Say this is a test"}]
|
||||
|
||||
kwargs = {
|
||||
"model": llm_model_value,
|
||||
"messages": messages_value,
|
||||
"stream": True,
|
||||
"stream_options": {"include_usage": True},
|
||||
}
|
||||
|
||||
response_stream_usage = None
|
||||
response_stream_model = None
|
||||
response_stream_id = None
|
||||
response_stream_result = ""
|
||||
response = openai_client.chat.completions.create(**kwargs)
|
||||
for chunk in response:
|
||||
if chunk.choices:
|
||||
response_stream_result += chunk.choices[0].delta.content or ""
|
||||
|
||||
# get the last chunk
|
||||
if getattr(chunk, "usage", None):
|
||||
response_stream_usage = chunk.usage
|
||||
response_stream_model = chunk.model
|
||||
response_stream_id = chunk.id
|
||||
|
||||
spans = exporter.get_finished_spans()
|
||||
streaming_span = spans[0]
|
||||
|
||||
assert streaming_span.name == f"chat {llm_model_value}"
|
||||
attributes = streaming_span.attributes
|
||||
|
||||
operation_name = attributes[GenAIAttributes.GEN_AI_OPERATION_NAME]
|
||||
system = attributes[GenAIAttributes.GEN_AI_SYSTEM]
|
||||
request_model = attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL]
|
||||
response_model = attributes[GenAIAttributes.GEN_AI_RESPONSE_MODEL]
|
||||
response_id = attributes[GenAIAttributes.GEN_AI_RESPONSE_ID]
|
||||
input_tokens = attributes[GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS]
|
||||
output_tokens = attributes[GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS]
|
||||
assert (
|
||||
operation_name == GenAIAttributes.GenAiOperationNameValues.CHAT.value
|
||||
)
|
||||
assert system == GenAIAttributes.GenAiSystemValues.OPENAI.value
|
||||
assert request_model == llm_model_value
|
||||
assert response_model == response_stream_model
|
||||
assert response_id == response_stream_id
|
||||
assert input_tokens == response_stream_usage.prompt_tokens
|
||||
assert output_tokens == response_stream_usage.completion_tokens
|
||||
|
||||
events = streaming_span.events
|
||||
|
||||
# assert that the prompt and completion events are present
|
||||
prompt_event = list(
|
||||
filter(
|
||||
lambda event: event.name == "gen_ai.content.prompt",
|
||||
events,
|
||||
)
|
||||
)
|
||||
completion_event = list(
|
||||
filter(
|
||||
lambda event: event.name == "gen_ai.content.completion",
|
||||
events,
|
||||
)
|
||||
)
|
||||
|
||||
assert prompt_event
|
||||
assert completion_event
|
||||
|
||||
# assert that the prompt and completion events have the correct attributes
|
||||
assert prompt_event[0].attributes[
|
||||
GenAIAttributes.GEN_AI_PROMPT
|
||||
] == json.dumps(messages_value)
|
||||
|
||||
assert (
|
||||
json.loads(
|
||||
completion_event[0].attributes[GenAIAttributes.GEN_AI_COMPLETION]
|
||||
)[0]["content"]
|
||||
== response_stream_result
|
||||
)
|
@ -57,6 +57,7 @@ dependencies = [
|
||||
"opentelemetry-instrumentation-logging==0.49b0.dev",
|
||||
"opentelemetry-instrumentation-mysql==0.49b0.dev",
|
||||
"opentelemetry-instrumentation-mysqlclient==0.49b0.dev",
|
||||
"opentelemetry-instrumentation-openai-v2==2.0.0.dev",
|
||||
"opentelemetry-instrumentation-pika==0.49b0.dev",
|
||||
"opentelemetry-instrumentation-psycopg==0.49b0.dev",
|
||||
"opentelemetry-instrumentation-psycopg2==0.49b0.dev",
|
||||
|
@ -120,6 +120,10 @@ libraries = [
|
||||
"library": "mysqlclient < 3",
|
||||
"instrumentation": "opentelemetry-instrumentation-mysqlclient==0.49b0.dev",
|
||||
},
|
||||
{
|
||||
"library": "openai >= 1.0.0",
|
||||
"instrumentation": "opentelemetry-instrumentation-openai-v2==2.0.0.dev",
|
||||
},
|
||||
{
|
||||
"library": "pika >= 0.12.0",
|
||||
"instrumentation": "opentelemetry-instrumentation-pika==0.49b0.dev",
|
||||
|
16
tox.ini
16
tox.ini
@ -6,6 +6,11 @@ envlist =
|
||||
; Environments are organized by individual package, allowing
|
||||
; for specifying supported Python versions per package.
|
||||
|
||||
; instrumentation-openai
|
||||
py3{8,9,10,11,12}-test-instrumentation-openai-v2
|
||||
pypy3-test-instrumentation-openai-v2
|
||||
lint-instrumentation-openai-v2
|
||||
|
||||
; opentelemetry-resource-detector-container
|
||||
py3{8,9,10,11,12}-test-resource-detector-container
|
||||
pypy3-test-resource-detector-container
|
||||
@ -404,6 +409,12 @@ commands_pre =
|
||||
opentelemetry-instrumentation: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils
|
||||
opentelemetry-instrumentation: pip install -r {toxinidir}/opentelemetry-instrumentation/test-requirements.txt
|
||||
|
||||
openai: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api
|
||||
openai: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions
|
||||
openai: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk
|
||||
openai: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils
|
||||
openai: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-openai-v2/test-requirements.txt
|
||||
|
||||
distro: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api
|
||||
distro: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions
|
||||
distro: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk
|
||||
@ -456,6 +467,11 @@ commands_pre =
|
||||
kafka-pythonng: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk
|
||||
kafka-pythonng: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/test-requirements-ng.txt
|
||||
|
||||
openai: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api
|
||||
openai: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk
|
||||
openai: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions
|
||||
openai: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-openai-v2/test-requirements.txt
|
||||
|
||||
confluent-kafka: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api
|
||||
confluent-kafka: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions
|
||||
confluent-kafka: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk
|
||||
|
Reference in New Issue
Block a user