Skip to content

Commit 2c7d5f8

Browse files
committed
Checkout ADK sample from adk-sample-9-29
1 parent 27d8eac commit 2c7d5f8

File tree

15 files changed

+566
-0
lines changed

15 files changed

+566
-0
lines changed

adk-sql-agent/.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Dockerfile

adk-sql-agent/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.db

adk-sql-agent/.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.13

adk-sql-agent/Dockerfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# NOTE: this must be run from the repo root as build context
2+
3+
# Adapted from https://docs.astral.sh/uv/guides/integration/docker/#intermediate-layers
4+
# Install uv
5+
FROM python:3.13-slim
6+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
7+
8+
RUN apt-get update && apt-get install -y git
9+
10+
# Change the working directory to the `app` directory
11+
WORKDIR /app
12+
13+
# Copy the project into the image
14+
COPY . ./
15+
16+
WORKDIR /app/adk-sql-agent
17+
18+
# Sync the project
19+
RUN --mount=type=cache,target=/root/.cache/uv uv sync --locked
20+
21+
ENTRYPOINT [ "uv", "run", "--locked", "--env-file=main.env", "main.py" ]

adk-sql-agent/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# OpenTelemetry ADK instrumentation example
2+
3+
<!-- TODO: link to devsite doc once it is published -->
4+
5+
This demo shows does remote uploading and with `.ref` attributes in the telemetry, following OTel semconv 1.37 for GenAI: https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/gen-ai/gen-ai-events.md
6+
7+
## Configure upload
8+
This demo uses the [fsspec](https://filesystem-spec.readthedocs.io/) library to do the upload
9+
in a vendor agnostic way, which is configured in an environment variable
10+
`OTEL_PYTHON_GENAI_UPLOADER_PATH`. For example, to upload to GCS bucket `my-bucket` with
11+
subdirectory `v1/`:
12+
13+
```console
14+
export OTEL_PYTHON_GENAI_UPLOADER_PATH="gs://my-bucket/v1"
15+
```
16+
17+
This will work with any installed fsspec implementations and also allows using any fsspec
18+
configuration like URL Chaining:
19+
- [Built in implementations](https://filesystem-spec.readthedocs.io/en/latest/api.html#built-in-implementations)
20+
- [Known third party impls](https://filesystem-spec.readthedocs.io/en/latest/api.html#external-implementations)
21+
- [URL Chaining](https://filesystem-spec.readthedocs.io/en/latest/features.html#url-chaining)
22+
23+
## Run the demo
24+
25+
To run the app, set some environment variables (alternatively can be put in `main.env`):
26+
27+
```console
28+
# Port if not default
29+
export PORT=8000
30+
# Project for ADC
31+
export GOOGLE_CLOUD_PROJECT=my-project
32+
33+
# Configure the upload path
34+
export OTEL_PYTHON_GENAI_UPLOADER_PATH="gs://${GOOGLE_CLOUD_PROJECT}/v1"
35+
36+
uv run --env-file main.env main.py
37+
```
38+
39+
## Dockerfile
40+
41+
Build
42+
43+
```console
44+
# from this directory, run with repo root build context
45+
docker build -f ./Dockerfile -t adk-sql-agent-write-aside ..
46+
```
47+
48+
Run:
49+
```console
50+
docker run --rm \
51+
-p 8000:8000 \
52+
-e PORT=8000 \
53+
-e GOOGLE_APPLICATION_CREDENTIALS \
54+
-e GOOGLE_CLOUD_PROJECT \
55+
-e OTEL_PYTHON_GENAI_UPLOADER_PATH="gs://otel-starter-project-genai-refs/v1" \
56+
-v "$GOOGLE_APPLICATION_CREDENTIALS:$GOOGLE_APPLICATION_CREDENTIALS" \
57+
adk-sql-agent-write-aside:latest
58+
```
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
GOOGLE_GENAI_USE_VERTEXAI=1
2+
GOOGLE_CLOUD_PROJECT=otel-starter-project
3+
GOOGLE_CLOUD_LOCATION=us-central1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import agent
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from textwrap import dedent
2+
3+
from google.adk.agents.llm_agent import Agent
4+
5+
root_agent = Agent(
6+
model="gemini-2.5-flash",
7+
name="root_agent",
8+
description="An agent that can describe images",
9+
instruction=dedent("""\
10+
You are an agent that can describe images. You don't have any tools at your disposal.
11+
Some guidelines for you:
12+
13+
- Don't answer any questions that are opinion based or involve emotions.
14+
- Keep it brief and succinct
15+
- But also be descriptive
16+
- Answer in a professional tone
17+
"""),
18+
)

adk-sql-agent/main.env

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
2+
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
3+
4+
GOOGLE_GENAI_USE_VERTEXAI=TRUE
5+
GOOGLE_CLOUD_LOCATION=us-central1
6+
7+
ENABLE_GCS_PYTHON_CLIENT_OTEL_TRACES=true

adk-sql-agent/main.py

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import logging
16+
import logging.handlers
17+
import os
18+
19+
import debugpy
20+
import google.auth
21+
import google.auth.transport.requests
22+
import grpc
23+
import uvicorn
24+
from fastapi import FastAPI
25+
from google.adk.cli.fast_api import get_fast_api_app
26+
from google.auth.transport.grpc import AuthMetadataPlugin
27+
28+
from opentelemetry import _events as events
29+
from opentelemetry import _logs as logs
30+
from opentelemetry import metrics, trace
31+
from opentelemetry.exporter.cloud_logging import CloudLoggingExporter
32+
from opentelemetry.exporter.cloud_monitoring import (
33+
CloudMonitoringMetricsExporter,
34+
)
35+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
36+
OTLPSpanExporter,
37+
)
38+
from opentelemetry.instrumentation.aiohttp_client import (
39+
AioHttpClientInstrumentor,
40+
)
41+
from opentelemetry.instrumentation.google_genai import (
42+
GoogleGenAiSdkInstrumentor,
43+
)
44+
from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor
45+
from opentelemetry.sdk._events import EventLoggerProvider
46+
from opentelemetry.sdk._logs import LoggerProvider
47+
from opentelemetry.sdk._logs.export import (
48+
BatchLogRecordProcessor,
49+
ConsoleLogExporter,
50+
)
51+
from opentelemetry.sdk._logs import LoggingHandler
52+
from opentelemetry.sdk.metrics import MeterProvider
53+
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
54+
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
55+
from opentelemetry.sdk.trace import TracerProvider
56+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
57+
58+
# Get the directory where main.py is located
59+
AGENT_DIR = os.path.dirname(os.path.abspath(__file__))
60+
# Example session DB URL (e.g., SQLite)
61+
SESSION_DB_URL = "sqlite:///./sessions.db"
62+
# Example allowed origins for CORS
63+
ALLOWED_ORIGINS = ["http://localhost", "http://localhost:8080", "*"]
64+
# Set web=True if you intend to serve a web interface, False otherwise
65+
SERVE_WEB_INTERFACE = True
66+
67+
# logging.basicConfig(level=logging.INFO, handlers=[LoggingHandler()])
68+
logging.getLogger().addHandler(LoggingHandler())
69+
logging.getLogger("gcsfs").setLevel(logging.DEBUG)
70+
logging.getLogger("fsspec").setLevel(logging.DEBUG)
71+
logging.getLogger("fsspec.cached").setLevel(logging.DEBUG)
72+
logging.getLogger("opentelemetry").setLevel(logging.DEBUG)
73+
logging.getLogger("opentelemetry").addHandler(logging.StreamHandler())
74+
75+
# debugpy.listen(5678)
76+
77+
78+
# [START opentelemetry_adk_otel_setup]
79+
def setup_opentelemetry() -> None:
80+
credentials, project_id = google.auth.default()
81+
resource = Resource.create(
82+
attributes={
83+
SERVICE_NAME: "adk-sql-agent",
84+
# The project to send spans to
85+
"gcp.project_id": project_id,
86+
}
87+
)
88+
89+
# Set up OTLP auth
90+
request = google.auth.transport.requests.Request()
91+
auth_metadata_plugin = AuthMetadataPlugin(
92+
credentials=credentials, request=request
93+
)
94+
channel_creds = grpc.composite_channel_credentials(
95+
grpc.ssl_channel_credentials(),
96+
grpc.metadata_call_credentials(auth_metadata_plugin),
97+
)
98+
99+
# Set up OpenTelemetry Python SDK
100+
tracer_provider = TracerProvider(resource=resource)
101+
tracer_provider.add_span_processor(
102+
BatchSpanProcessor(
103+
OTLPSpanExporter(
104+
credentials=channel_creds,
105+
endpoint="https://telemetry.googleapis.com:443/v1/traces",
106+
)
107+
)
108+
)
109+
trace.set_tracer_provider(tracer_provider)
110+
111+
logger_provider = LoggerProvider(resource=resource)
112+
logger_provider.add_log_record_processor(
113+
BatchLogRecordProcessor(CloudLoggingExporter())
114+
)
115+
# logger_provider.add_log_record_processor(
116+
# BatchLogRecordProcessor(
117+
# ConsoleLogExporter(out=open("./logs.jsonl", "w+"))
118+
# )
119+
# )
120+
logs.set_logger_provider(logger_provider)
121+
122+
event_logger_provider = EventLoggerProvider(logger_provider)
123+
events.set_event_logger_provider(event_logger_provider)
124+
125+
reader = PeriodicExportingMetricReader(CloudMonitoringMetricsExporter())
126+
meter_provider = MeterProvider(metric_readers=[reader], resource=resource)
127+
metrics.set_meter_provider(meter_provider)
128+
129+
# Set up prompt uploader
130+
# if OTEL_PYTHON_UPLOADER_PATH:
131+
# set_uploader(GcsUploader(bucket_path=OTEL_PYTHON_GCS_UPLOAD_BUCKET))
132+
133+
# Load instrumentors
134+
# SQLite3Instrumentor().instrument()
135+
VertexAIInstrumentor().instrument()
136+
GoogleGenAiSdkInstrumentor().instrument()
137+
AioHttpClientInstrumentor().instrument()
138+
139+
140+
# [END opentelemetry_adk_otel_setup]
141+
142+
143+
def main() -> None:
144+
# Make sure to set:
145+
# OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
146+
# OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
147+
# in order to full prompts and responses and logs messages.
148+
setup_opentelemetry()
149+
150+
# Call the function to get the FastAPI app instance
151+
# Ensure the agent directory name ('capital_agent') matches your agent folder
152+
app: FastAPI = get_fast_api_app(
153+
agents_dir=AGENT_DIR,
154+
session_service_uri=SESSION_DB_URL,
155+
allow_origins=ALLOWED_ORIGINS,
156+
web=SERVE_WEB_INTERFACE,
157+
)
158+
159+
uvicorn.run(
160+
app,
161+
host="0.0.0.0",
162+
port=int(os.environ.get("PORT", 8080)),
163+
)
164+
165+
166+
if __name__ == "__main__":
167+
main()

0 commit comments

Comments
 (0)