Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions docs/nitpick-exceptions.ini
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ py-class=
fastapi.applications.FastAPI
starlette.applications.Starlette
_contextvars.Token
opentelemetry.util.genai.types._BaseAgent

any=
; API
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
OpenTelemetry GenAI Utils — invoke_agent Demo
================================================

This example shows how to combine ``VertexAIInstrumentor`` (automatic
instrumentation of Vertex AI SDK calls) with manual
``TelemetryHandler.agent()`` spans from ``opentelemetry-util-genai``
to extend existing instrumentation with agent invocation lifecycle spans.

The ``generate_content`` call is made inside the ``invoke_agent`` context,
so the auto-instrumented LLM span appears as a child of the ``invoke_agent``
parent span — all within the same trace.

Sample Trace
------------

::

Trace ID: 0xe71e16deb2ecd162e3f4fc67c240818b
|
+-- invoke_agent Currency Exchange Agent [4.16s, root span]
| gen_ai.operation.name: invoke_agent
| gen_ai.agent.name: Currency Exchange Agent
| gen_ai.agent.description: Currency exchange agent demo
| gen_ai.provider.name: gcp_vertex_ai
| gen_ai.request.model: gemini-2.5-flash
| gen_ai.response.finish_reasons: ["stop"]
| gen_ai.usage.input_tokens: 12
| gen_ai.usage.output_tokens: 87
| server.address: us-central1-aiplatform.googleapis.com
| scope: opentelemetry.util.genai.handler
|
+-- chat gemini-2.5-flash [4.12s, child span]
gen_ai.operation.name: chat
gen_ai.system: vertex_ai
gen_ai.request.model: gemini-2.5-flash
gen_ai.response.model: gemini-2.5-flash
gen_ai.response.finish_reasons: ["stop"]
gen_ai.usage.input_tokens: 12
gen_ai.usage.output_tokens: 87
server.address: us-central1-aiplatform.googleapis.com
server.port: 443
scope: opentelemetry.instrumentation.vertexai

Prerequisites
-------------

- A GCP project with the **Vertex AI API** enabled.
- **Application Default Credentials** (ADC) configured:
``gcloud auth application-default login``

Setup
-----

An OTLP compatible endpoint should be listening for traces and logs on
http://localhost:4317. If not, update ``OTEL_EXPORTER_OTLP_ENDPOINT``.

Set up a virtual environment:

::

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -e ../../../../util/opentelemetry-util-genai/

Run
---

::

export GCP_PROJECT="your-project-id"
python main.py

You should see an ``invoke_agent`` span wrapping a ``chat`` child span,
both printed to the console and exported to your OTLP endpoint.

Environment Variables
---------------------

- ``GCP_PROJECT`` — GCP project ID (default: ``gcp-o11yinframon-nprd-81065``).
- ``GCP_LOCATION`` — GCP region (default: ``us-central1``).
- ``OTEL_EXPORTER_OTLP_ENDPOINT`` — OTLP endpoint
(default: ``http://localhost:4317``).
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# pylint: skip-file
"""
invoke_agent instrumentation demo.

Combines automatic instrumentation (``VertexAIInstrumentor``) with
manual ``TelemetryHandler.agent()`` spans from ``opentelemetry-util-genai``
to show how genai-utils extends the existing Vertex AI instrumentation
with agent invocation lifecycle spans.

The ``generate_content`` call is made inside the ``invoke_agent`` context,
so the auto-instrumented LLM span appears as a child of the ``invoke_agent``
parent span.

Set environment variables before running:

export GCP_PROJECT="your-project-id"
python main.py
"""

import os

import vertexai
from vertexai.generative_models import GenerativeModel

# NOTE: OpenTelemetry Python Logs and Events APIs are in beta
from opentelemetry import _logs, metrics, trace
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import (
OTLPLogExporter,
)
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
OTLPMetricExporter,
)
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
OTLPSpanExporter,
)
from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor
from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
BatchSpanProcessor,
ConsoleSpanExporter,
)
from opentelemetry.util.genai.handler import TelemetryHandler
from opentelemetry.util.genai.types import AgentInvocation

OTLP_ENDPOINT = os.environ.get(
"OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"
)
GCP_PROJECT = os.environ.get("GCP_PROJECT", "gcp-o11yinframon-nprd-81065")
GCP_LOCATION = os.environ.get("GCP_LOCATION", "us-central1")
MODEL = "gemini-2.5-flash"
AGENT_NAME = "Currency Exchange Agent"

resource = Resource.create({"service.name": "invoke-agent-demo"})

# configure tracing
tracer_provider = TracerProvider(resource=resource)
tracer_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
tracer_provider.add_span_processor(
BatchSpanProcessor(OTLPSpanExporter(endpoint=OTLP_ENDPOINT, insecure=True))
)
trace.set_tracer_provider(tracer_provider)

# configure metrics
metric_reader = PeriodicExportingMetricReader(
OTLPMetricExporter(endpoint=OTLP_ENDPOINT, insecure=True)
)
meter_provider = MeterProvider(
resource=resource, metric_readers=[metric_reader]
)
metrics.set_meter_provider(meter_provider)

# configure logging and events
logger_provider = LoggerProvider(resource=resource)
logger_provider.add_log_record_processor(
BatchLogRecordProcessor(
OTLPLogExporter(endpoint=OTLP_ENDPOINT, insecure=True)
)
)
_logs.set_logger_provider(logger_provider)

# Auto-instrument Vertex AI SDK calls (generate_content, etc.)
VertexAIInstrumentor().instrument()


def main():
vertexai.init(project=GCP_PROJECT, location=GCP_LOCATION)
model = GenerativeModel(MODEL)
handler = TelemetryHandler()

# ----- invoke_agent span wrapping an LLM call -----
# The generate_content call is auto-instrumented by VertexAIInstrumentor
# and appears as a child span under the invoke_agent parent span.
print("[invoke_agent] Starting agent invocation...")
with handler.agent(
AgentInvocation(
agent_name=AGENT_NAME,
provider="gcp_vertex_ai",
request_model=MODEL,
agent_description="Currency exchange agent demo",
server_address=f"{GCP_LOCATION}-aiplatform.googleapis.com",
)
) as invocation:
response = model.generate_content(
"What is the exchange rate from US dollars to SEK today?"
)
# Populate response attributes on the invocation
usage = response.usage_metadata
invocation.input_tokens = usage.prompt_token_count
invocation.output_tokens = usage.candidates_token_count
invocation.finish_reasons = ["stop"]

print(f"[invoke_agent] Response:\n{response.text}\n")


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
google-cloud-aiplatform[agent_engines,langchain]>=1.64
google-genai>=1.0
langchain-google-vertexai
requests

opentelemetry-sdk>=1.40
opentelemetry-exporter-otlp-proto-grpc>=1.40
opentelemetry-instrumentation-vertexai>=2.0b0
opentelemetry-util-genai>=0.4b0.dev0
2 changes: 2 additions & 0 deletions util/opentelemetry-util-genai/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- Add `AgentInvocation` type and agent invocation lifecycle support
([#4274](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4274))
- Populate schema_url on metrics
([#4320](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4320))
- Add workflow invocation type to genAI utils
Expand Down
6 changes: 3 additions & 3 deletions util/opentelemetry-util-genai/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ classifiers = [
"Programming Language :: Python :: 3.14",
]
dependencies = [
"opentelemetry-instrumentation ~= 0.58b0",
"opentelemetry-semantic-conventions ~= 0.58b0",
"opentelemetry-api>=1.31.0",
"opentelemetry-instrumentation ~= 0.61b0",
"opentelemetry-semantic-conventions ~= 0.61b0",
"opentelemetry-api>=1.40.0",
]

[project.entry-points.opentelemetry_genai_completion_hook]
Expand Down
Loading