Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
73a764c
cherry pick changes from previous PR
keith-decker Sep 17, 2025
0d749a9
move span utils to new file
keith-decker Sep 17, 2025
77d9c3c
remove span state, use otel context for parent/child
keith-decker Sep 17, 2025
054ebe9
flatten LLMInvocation to use attributes instead of dict keys
keith-decker Sep 17, 2025
9d3926f
helper function and docstrings
keith-decker Sep 17, 2025
635b7f8
Merge branch 'main' into util-genai-inference-clean
keith-decker Sep 18, 2025
9837cf4
refactor: store span and context token in LLMInvocation instead of Sp…
keith-decker Sep 18, 2025
1a172d1
refactor: rename prompts/chat_generations to input_messages/output_me…
keith-decker Sep 19, 2025
465ca78
refactor: simplify TelemetryHandler API by moving invocation data man…
keith-decker Sep 19, 2025
cd5aaa6
refactor: update relative imports to absolute imports
keith-decker Sep 19, 2025
8347d17
Update handler to use a context manager instead of start_llm and stop…
keith-decker Sep 22, 2025
742a36f
resolve tox -e doc failure
keith-decker Sep 22, 2025
00e08a8
safeguard against empty request-model
keith-decker Sep 22, 2025
109625c
Merge branch 'main' into util-genai-inference-clean
keith-decker Sep 22, 2025
80c94bf
fix tox typecheck errors for utils
keith-decker Sep 22, 2025
f07c61f
refactor: move tracer to generator, clean up dead code
keith-decker Sep 22, 2025
d6f722f
remove unused linting hint
keith-decker Sep 22, 2025
fdc7f50
back off stricter request-model requirements
keith-decker Sep 22, 2025
da20448
reintroduce manual start/stop for langchain callback flow
keith-decker Sep 22, 2025
18c3365
Fix typecheck in langchain instrumentation (#3773)
wrisa Sep 23, 2025
b232b9a
botocore: Add support for AWS Secrets Manager semantic convention att…
lukeina2z Sep 23, 2025
c1ff846
Merge branch 'main' into util-genai-inference-clean
aabmass Sep 23, 2025
4a08d7f
clean up context handler, clarify unit tests
keith-decker Sep 23, 2025
cf00cf5
Rename UploadHook -> CompletionHook (#3780)
aabmass Sep 24, 2025
b2ed70f
Add opentelemetry-util-genai to the package release workflow (#3781)
aabmass Sep 24, 2025
6ae5e34
Fix package release workflows version.py finding (#3782)
aabmass Sep 24, 2025
7bacbfd
Adjust opentelemetry-instrumentation-vertexai dependency on opentelem…
aabmass Sep 24, 2025
17aba81
Fix exception handling for JSON decoding (#3787)
ChuckJonas Sep 25, 2025
6c57132
Add rstcheck in pre-commit (#3777)
xrmx Sep 25, 2025
243bf8d
remove generator concept
keith-decker Sep 25, 2025
3d6c8da
Merge branch 'main' into util-genai-inference-clean
keith-decker Sep 25, 2025
5f8cd1c
update token types
keith-decker Sep 25, 2025
b0679f1
Update opentelemetry-util-genai version to v0.2b0 (#3783)
otelbot[bot] Sep 25, 2025
e987d66
Merge branch 'main' into util-genai-inference-clean
keith-decker Sep 26, 2025
f4fd656
Merge branch 'genai-utils-e2e-dev' into e2e-inference-merge
keith-decker Sep 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/misc_0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ jobs:
- name: Run tests
run: tox -e shellcheck

ruff:
name: ruff
precommit:
name: precommit
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
Expand All @@ -174,7 +174,7 @@ jobs:
run: pip install tox-uv

- name: Run tests
run: tox -e ruff
run: tox -e precommit

typecheck:
name: typecheck
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/package-prepare-patch-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
- opentelemetry-instrumentation-openai-v2
- opentelemetry-instrumentation-vertexai
- opentelemetry-instrumentation-google-genai
- opentelemetry-util-genai
description: 'Package to be released'
required: true
permissions:
Expand Down Expand Up @@ -48,7 +49,7 @@ jobs:

version=$(./scripts/eachdist.py version --package ${{ inputs.package }})

version_file=$(find $path -type f -path "*version*.py")
version_file=$(find $path -type f -path "**/version.py")
file_count=$(echo "$version_file" | wc -l)

if [ "$file_count" -ne 1 ]; then
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/package-prepare-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
- opentelemetry-instrumentation-openai-v2
- opentelemetry-instrumentation-vertexai
- opentelemetry-instrumentation-google-genai
- opentelemetry-util-genai
description: 'Package to be released'
required: true

Expand Down Expand Up @@ -60,7 +61,7 @@ jobs:

version=${version_dev%.dev}

version_file=$(find $path -type f -path "*version*.py")
version_file=$(find $path -type f -path "**/version.py")
file_count=$(echo "$version_file" | wc -l)

if [ "$file_count" -ne 1 ]; then
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/package-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
- opentelemetry-instrumentation-openai-v2
- opentelemetry-instrumentation-vertexai
- opentelemetry-instrumentation-google-genai
- opentelemetry-util-genai
description: 'Package to be released'
required: true
permissions:
Expand Down
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ repos:
rev: 0.6.0
hooks:
- id: uv-lock
- repo: https://github.com/rstcheck/rstcheck
rev: 77490ffa33bfc0928975ae3cf904219903db755d # frozen: v6.2.5
hooks:
- id: rstcheck
additional_dependencies: ['rstcheck[sphinx]']
args: ["--report-level", "warning"]
2 changes: 2 additions & 0 deletions .rstcheck.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[rstcheck]
ignore_directives = automodule
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- `opentelemetry-instrumentation`: botocore: Add support for AWS Secrets Manager semantic convention attribute
([#3765](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3765))
- Add `rstcheck` to pre-commit to stop introducing invalid RST
([#3777](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3777))


## Version 1.37.0/0.58b0 (2025-09-11)

Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ You can run `tox` with the following arguments:
* `tox -e lint-some-package` to run lint checks on `some-package`
* `tox -e generate-workflows` to run creation of new CI workflows if tox environments have been updated
* `tox -e ruff` to run ruff linter and formatter checks against the entire codebase
* `tox -e precommit` to run all `pre-commit` actions

`ruff check` and `ruff format` are executed when `tox -e ruff` is run. We strongly recommend you to configure [pre-commit](https://pre-commit.com/) locally to run `ruff` automatically before each commit by installing it as git hooks. You just need to [install pre-commit](https://pre-commit.com/#install) in your environment:
`ruff check` and `ruff format` are executed when `tox -e ruff` is run. We strongly recommend you to configure [pre-commit](https://pre-commit.com/) locally to run `ruff` and `rstcheck` automatically before each commit by installing it as git hooks. You just need to [install pre-commit](https://pre-commit.com/#install) in your environment:

```console
pip install pre-commit -c dev-requirements.txt
Expand Down
4 changes: 2 additions & 2 deletions _template/README.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
OpenTelemetry <REPLACE ME> Instrumentation
===========================
==========================================

|pypi|

Expand All @@ -20,5 +20,5 @@ Installation
References
----------

* `OpenTelemetry <REPLACE ME>/ Tracing <https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/<REPLACE ME>/<REPLACE ME>.html>`_
* `OpenTelemetry REPLACE ME/ Tracing <https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/REPLACE ME/REPLACE ME.html>`_
* `OpenTelemetry Project <https://opentelemetry.io/>`_
2 changes: 1 addition & 1 deletion docs/instrumentation-genai/util.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ OpenTelemetry Python - GenAI Util
:undoc-members:
:show-inheritance:

.. automodule:: opentelemetry.util.genai.upload_hook
.. automodule:: opentelemetry.util.genai.completion_hook
:members:
:undoc-members:
:show-inheritance:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
OpenTelemetry Google GenAI SDK Manual Instrumentation Example
============================================
=============================================================

This is an example of how to instrument Google GenAI SDK calls when configuring
OpenTelemetry SDK and Instrumentations manually.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
OpenTelemetry Google GenAI SDK Manual Instrumentation Example
============================================
=============================================================

This is an example of how to instrument Google GenAI SDK calls with zero code changes,
using `opentelemetry-instrument`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
OpenTelemetry Langcahin Instrumentation Example
============================================
===============================================

This is an example of how to instrument Langchain when configuring OpenTelemetry SDK and instrumentations manually.

When :code:`main.py <main.py>`_ is run, it exports traces to an OTLP-compatible endpoint.
When `main.py <main.py>`_ is run, it exports traces to an OTLP-compatible endpoint.
Traces include details such as the span name and other attributes.

Note: :code:`.env <.env>`_ file configures additional environment variables:
Note: `.env <.env>`_ file configures additional environment variables:
- :code:`OTEL_LOGS_EXPORTER=otlp` to specify exporter type.
- :code:`OPENAI_API_KEY` open AI key for accessing the OpenAI API.
- :code:`OTEL_EXPORTER_OTLP_ENDPOINT` to specify the endpoint for exporting traces (default is http://localhost:4317).

Setup
-----

Minimally, update the :code:`.env <.env>`_ file with your :code:`OPENAI_API_KEY`.
Minimally, update the `.env <.env>`_ file with your :code:`OPENAI_API_KEY`.
An OTLP compatible endpoint should be listening for traces http://localhost:4317.
If not, update :code:`OTEL_EXPORTER_OTLP_ENDPOINT` as well.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
OpenTelemetry Langchain Zero-Code Instrumentation Example
======================================================
=========================================================

This is an example of how to instrument Langchain with zero code changes,
using `opentelemetry-instrument`.

When :code:`main.py <main.py>`_ is run, it exports traces to an OTLP-compatible endpoint.
When `main.py <main.py>`_ is run, it exports traces to an OTLP-compatible endpoint.
Traces include details such as the span name and other attributes.

Note: :code:`.env <.env>`_ file configures additional environment variables:
Note: `.env <.env>`_ file configures additional environment variables:
- :code:`OTEL_LOGS_EXPORTER=otlp` to specify exporter type.
- :code:`OPENAI_API_KEY` open AI key for accessing the OpenAI API.
- :code:`OTEL_EXPORTER_OTLP_ENDPOINT` to specify the endpoint for exporting traces (default is http://localhost:4317).

Setup
-----

Minimally, update the :code:`.env <.env>`_ file with your :code:`OPENAI_API_KEY`.
Minimally, update the `.env <.env>`_ file with your :code:`OPENAI_API_KEY`.
An OTLP compatible endpoint should be listening for traces http://localhost:4317.
If not, update :code:`OTEL_EXPORTER_OTLP_ENDPOINT` as well.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
OpenTelemetry VertexAI Instrumentation Example
============================================
==============================================

This is an example of how to instrument VertexAI calls when configuring OpenTelemetry SDK and Instrumentations manually.

Expand All @@ -12,8 +12,8 @@ your VertexAI requests.
Note: `.env <.env>`_ file configures additional environment variables:

- `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true` configures
VertexAI instrumentation to capture prompt and completion contents on
events.
VertexAI instrumentation to capture prompt and completion contents on
events.

Setup
-----
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
OpenTelemetry VertexAI Instrumentation Example
============================================
==============================================

This is an example of how to instrument VertexAI calls with zero code changes,
using `opentelemetry-instrument`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ classifiers = [
dependencies = [
"opentelemetry-api ~= 1.28",
"opentelemetry-instrumentation ~= 0.58b0",
"opentelemetry-util-genai == 0.1b0.dev",
# TODO https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3786: restrict
# version after the first release
"opentelemetry-util-genai",
"opentelemetry-semantic-conventions ~= 0.58b0",
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def _process_event(self, event):
self._content_block["toolUse"]["input"] = json.loads(
self._tool_json_input_buf
)
except json.DecodeError:
except json.JSONDecodeError:
self._content_block["toolUse"]["input"] = (
self._tool_json_input_buf
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ The hooks can be configured as follows:

# `request_obj` is an instance of urllib.request.Request
# `response` is an instance of http.client.HTTPResponse
def response_hook(span, request_obj, response)
def response_hook(span, request_obj, response):
pass

URLLibInstrumentor().instrument(
Expand Down
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ envlist =
generate
generate-workflows
shellcheck
ruff
precommit
typecheck

[testenv]
Expand Down Expand Up @@ -1047,7 +1047,7 @@ commands_pre =
commands =
sh -c "find {toxinidir} -name \*.sh | xargs shellcheck --severity=warning"

[testenv:ruff]
[testenv:{precommit,ruff}]
basepython: python3
deps =
-c {toxinidir}/dev-requirements.txt
Expand Down
13 changes: 9 additions & 4 deletions util/opentelemetry-util-genai/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- Add upload hook to genai utils to implement semconv v1.37.
## Version 0.1b0 (2025-09-24)

The hook uses [`fsspec`](https://filesystem-spec.readthedocs.io/en/latest/) to support
various pluggable backends.
- Add completion hook to genai utils to implement semconv v1.37.

Includes a hook implementation using
[`fsspec`](https://filesystem-spec.readthedocs.io/en/latest/) to support uploading to various
pluggable backends.

([#3780](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3780))
([#3752](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3752))
([#3759](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3752))
([#3759](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3759))
([#3763](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3763))
- Add a utility to parse the `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` environment variable.
Add `gen_ai_latest_experimental` as a new value to the Sem Conv stability flag ([#3716](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3716)).
Expand Down
4 changes: 2 additions & 2 deletions util/opentelemetry-util-genai/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ dependencies = [
"opentelemetry-api>=1.31.0",
]

[project.entry-points.opentelemetry_genai_upload_hook]
fsspec = "opentelemetry.util.genai._fsspec_upload:fsspec_upload_hook"
[project.entry-points.opentelemetry_genai_completion_hook]
fsspec_upload = "opentelemetry.util.genai._fsspec_upload:fsspec_completion_upload_hook"

[project.optional-dependencies]
test = ["pytest>=7.0.0"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,27 @@

from os import environ

from opentelemetry.util.genai.completion_hook import (
CompletionHook,
_NoOpCompletionHook,
)
from opentelemetry.util.genai.environment_variables import (
OTEL_INSTRUMENTATION_GENAI_UPLOAD_BASE_PATH,
)
from opentelemetry.util.genai.upload_hook import UploadHook, _NoOpUploadHook


def fsspec_upload_hook() -> UploadHook:
def fsspec_completion_upload_hook() -> CompletionHook:
# If fsspec is not installed the hook will be a no-op.
try:
# pylint: disable=import-outside-toplevel
from opentelemetry.util.genai._fsspec_upload.fsspec_hook import (
FsspecUploadHook,
from opentelemetry.util.genai._fsspec_upload.completion_hook import (
FsspecUploadCompletionHook,
)
except ImportError:
return _NoOpUploadHook()
return _NoOpCompletionHook()

base_path = environ.get(OTEL_INSTRUMENTATION_GENAI_UPLOAD_BASE_PATH)
if not base_path:
return _NoOpUploadHook()
return _NoOpCompletionHook()

return FsspecUploadHook(base_path=base_path)
return FsspecUploadCompletionHook(base_path=base_path)
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from opentelemetry.semconv._incubating.attributes import gen_ai_attributes
from opentelemetry.trace import Span
from opentelemetry.util.genai import types
from opentelemetry.util.genai.upload_hook import UploadHook
from opentelemetry.util.genai.completion_hook import CompletionHook

GEN_AI_INPUT_MESSAGES_REF: Final = (
gen_ai_attributes.GEN_AI_INPUT_MESSAGES + "_ref"
Expand Down Expand Up @@ -75,12 +75,12 @@ def fsspec_open(urlpath: str, mode: Literal["w"]) -> TextIO:
return cast(TextIO, fsspec.open(urlpath, mode)) # pyright: ignore[reportUnknownMemberType]


class FsspecUploadHook(UploadHook):
"""An upload hook using ``fsspec`` to upload to external storage
class FsspecUploadCompletionHook(CompletionHook):
"""An completion hook using ``fsspec`` to upload to external storage

This function can be used as the
:func:`~opentelemetry.util.genai.upload_hook.load_upload_hook` implementation by
setting :envvar:`OTEL_INSTRUMENTATION_GENAI_UPLOAD_HOOK` to ``fsspec``.
:func:`~opentelemetry.util.genai.completion_hook.load_completion_hook` implementation by
setting :envvar:`OTEL_INSTRUMENTATION_GENAI_COMPLETION_HOOK` to ``fsspec_upload``.
:envvar:`OTEL_INSTRUMENTATION_GENAI_UPLOAD_BASE_PATH` must be configured to specify the
base path for uploads.

Expand Down Expand Up @@ -128,7 +128,7 @@ def done(future: Future[None]) -> None:
fut.add_done_callback(done)
except RuntimeError:
_logger.info(
"attempting to upload file after FsspecUploadHook.shutdown() was already called"
"attempting to upload file after FsspecUploadCompletionHook.shutdown() was already called"
)
self._semaphore.release()

Expand Down Expand Up @@ -161,7 +161,7 @@ def _do_upload(
cls=Base64JsonEncoder,
)

def upload(
def on_completion(
self,
*,
inputs: list[types.InputMessage],
Expand Down
Loading
Loading