diff --git a/.github/workflows/gemini-invoke.yml b/.github/workflows/gemini-invoke.yml
index e35fd35b8..1d396ec3b 100644
--- a/.github/workflows/gemini-invoke.yml
+++ b/.github/workflows/gemini-invoke.yml
@@ -61,14 +61,16 @@ jobs:
google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
+ upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
settings: |-
{
"model": {
"maxSessionTurns": 25
},
"telemetry": {
- "enabled": ${{ vars.GOOGLE_CLOUD_PROJECT != '' }},
- "target": "gcp"
+ "enabled": true,
+ "target": "local",
+ "outfile": ".gemini/telemetry.log"
},
"mcpServers": {
"github": {
diff --git a/.github/workflows/gemini-issue-fixer.yml b/.github/workflows/gemini-issue-fixer.yml
index c23d67704..804d9cc20 100644
--- a/.github/workflows/gemini-issue-fixer.yml
+++ b/.github/workflows/gemini-issue-fixer.yml
@@ -62,6 +62,7 @@ jobs:
google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
+ upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
settings: |-
{
"debug": ${{ fromJSON(env.DEBUG || env.ACTIONS_STEP_DEBUG || false) }},
@@ -85,8 +86,9 @@ jobs:
}
},
"telemetry": {
- "enabled": ${{ vars.GOOGLE_CLOUD_PROJECT != '' }},
- "target": "gcp"
+ "enabled": true,
+ "target": "local",
+ "outfile": ".gemini/telemetry.log"
}
}
prompt: '/gemini-issue-fixer'
diff --git a/.github/workflows/gemini-review.yml b/.github/workflows/gemini-review.yml
index 0a8756093..288a12b46 100644
--- a/.github/workflows/gemini-review.yml
+++ b/.github/workflows/gemini-review.yml
@@ -63,14 +63,16 @@ jobs:
google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
+ upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
settings: |-
{
"model": {
"maxSessionTurns": 25
},
"telemetry": {
- "enabled": ${{ vars.GOOGLE_CLOUD_PROJECT != '' }},
- "target": "gcp"
+ "enabled": true,
+ "target": "local",
+ "outfile": ".gemini/telemetry.log"
},
"mcpServers": {
"github": {
diff --git a/.github/workflows/gemini-scheduled-triage.yml b/.github/workflows/gemini-scheduled-triage.yml
index 8cda08a84..912088708 100644
--- a/.github/workflows/gemini-scheduled-triage.yml
+++ b/.github/workflows/gemini-scheduled-triage.yml
@@ -103,14 +103,16 @@ jobs:
google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
+ upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
settings: |-
{
"model": {
"maxSessionTurns": 25
},
"telemetry": {
- "enabled": ${{ vars.GOOGLE_CLOUD_PROJECT != '' }},
- "target": "gcp"
+ "enabled": true,
+ "target": "local",
+ "outfile": ".gemini/telemetry.log"
},
"tools": {
"core": [
diff --git a/.github/workflows/gemini-triage.yml b/.github/workflows/gemini-triage.yml
index 56817510d..6b946c2c9 100644
--- a/.github/workflows/gemini-triage.yml
+++ b/.github/workflows/gemini-triage.yml
@@ -73,14 +73,16 @@ jobs:
google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
+ upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
settings: |-
{
"model": {
"maxSessionTurns": 25
},
"telemetry": {
- "enabled": ${{ vars.GOOGLE_CLOUD_PROJECT != '' }},
- "target": "gcp"
+ "enabled": true,
+ "target": "local",
+ "outfile": ".gemini/telemetry.log"
},
"tools": {
"core": [
diff --git a/README.md b/README.md
index 47663cdde..042b8d195 100644
--- a/README.md
+++ b/README.md
@@ -183,6 +183,8 @@ go to the [Gemini Assistant workflow documentation](./examples/workflows/gemini-
- extensions: _(Optional)_ A list of Gemini CLI extensions to install.
+- upload_artifacts: _(Optional, default: `false`)_ Whether or not to upload artifacts to the github action.
+
diff --git a/action.yml b/action.yml
index 081a8487f..af2e46117 100644
--- a/action.yml
+++ b/action.yml
@@ -71,6 +71,10 @@ inputs:
extensions:
description: 'A list of Gemini CLI extensions to install.'
required: false
+ upload_artifacts:
+ description: 'Whether or not to upload artifacts to the github action.'
+ required: false
+ default: 'false'
outputs:
summary:
@@ -183,26 +187,6 @@ runs:
token_format: 'access_token'
access_token_scopes: 'https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/userinfo.profile'
- - name: 'Run Telemetry Collector for Google Cloud'
- if: |-
- ${{ inputs.gcp_workload_identity_provider != '' }}
- env:
- OTLP_GOOGLE_CLOUD_PROJECT: '${{ inputs.gcp_project_id }}'
- GITHUB_ACTION_PATH: '${{ github.action_path }}'
- shell: 'bash'
- run: |-
- set -euo pipefail
- mkdir -p .gemini/
- sed "s/OTLP_GOOGLE_CLOUD_PROJECT/${OTLP_GOOGLE_CLOUD_PROJECT}/g" "${GITHUB_ACTION_PATH}/scripts/collector-gcp.yaml.template" > ".gemini/collector-gcp.yaml"
-
- chmod 444 "$GOOGLE_APPLICATION_CREDENTIALS"
- docker run -d --name gemini-telemetry-collector --network host \
- -v "${GITHUB_WORKSPACE}:/github/workspace" \
- -e "GOOGLE_APPLICATION_CREDENTIALS=${GOOGLE_APPLICATION_CREDENTIALS/$GITHUB_WORKSPACE//github/workspace}" \
- -w "/github/workspace" \
- otel/opentelemetry-collector-contrib:0.128.0 \
- --config /github/workspace/.gemini/collector-gcp.yaml
-
- name: 'Install Gemini CLI'
id: 'install'
env:
@@ -274,22 +258,29 @@ runs:
fi
fi
- GEMINI_RESPONSE="$(cat "${TEMP_STDOUT}")"
+ # Create the artifacts directory and copy full logs
+ mkdir -p gemini-artifacts
+ cp "${TEMP_STDOUT}" gemini-artifacts/stdout.log
+ cp "${TEMP_STDERR}" gemini-artifacts/stderr.log
+ if [[ -f .gemini/telemetry.log ]]; then
+ cp .gemini/telemetry.log gemini-artifacts/telemetry.log
+ else
+ # Create an empty file so the artifact upload doesn't fail if telemetry is missing
+ touch gemini-artifacts/telemetry.log
+ fi
# Set the captured response as a step output, supporting multiline
echo "gemini_response<> "${GITHUB_OUTPUT}"
- echo "${GEMINI_RESPONSE}" >> "${GITHUB_OUTPUT}"
+ cat "${TEMP_STDOUT}" >> "${GITHUB_OUTPUT}"
echo "EOF" >> "${GITHUB_OUTPUT}"
- GEMINI_ERRORS="$(cat "${TEMP_STDERR}")"
-
# Set the captured errors as a step output, supporting multiline
echo "gemini_errors<> "${GITHUB_OUTPUT}"
- echo "${GEMINI_ERRORS}" >> "${GITHUB_OUTPUT}"
+ cat "${TEMP_STDERR}" >> "${GITHUB_OUTPUT}"
echo "EOF" >> "${GITHUB_OUTPUT}"
if [[ "${FAILED}" = true ]]; then
- LAST_LINE="$(echo "${GEMINI_ERRORS}" | tail -n1)"
+ LAST_LINE="$(tail -n1 "${TEMP_STDERR}")"
echo "::error title=Gemini CLI execution failed::${LAST_LINE}"
echo "See logs for more details"
exit 1
@@ -307,6 +298,82 @@ runs:
PROMPT: '${{ inputs.prompt }}'
GEMINI_MODEL: '${{ inputs.gemini_model }}'
+ - name: 'Upload Gemini CLI outputs'
+ if: |-
+ ${{ inputs.upload_artifacts }}
+ uses: 'actions/upload-artifact@v4' # ratchet:exclude
+ with:
+ name: 'gemini-output'
+ path: 'gemini-artifacts/'
+
+ - name: 'Upload Telemetry to Google Cloud'
+ if: |-
+ ${{ inputs.gcp_workload_identity_provider != '' }}
+ shell: 'bash'
+ run: |-
+ set -euo pipefail
+
+ # If the telemetry log doesn't exist or is empty, do nothing.
+ if [[ ! -s ".gemini/telemetry.log" ]]; then
+ echo "No telemetry log found, skipping upload."
+ exit 0
+ fi
+
+ # Generate the real config file from the template
+ sed -e "s#OTLP_GOOGLE_CLOUD_PROJECT#${OTLP_GOOGLE_CLOUD_PROJECT}#g" \
+ -e "s#GITHUB_REPOSITORY_PLACEHOLDER#${GITHUB_REPOSITORY}#g" \
+ -e "s#GITHUB_RUN_ID_PLACEHOLDER#${GITHUB_RUN_ID}#g" \
+ "${GITHUB_ACTION_PATH}/scripts/collector-gcp.yaml.template" > ".gemini/collector-gcp.yaml"
+
+ # Ensure credentials file has the right permissions
+ chmod 444 "$GOOGLE_APPLICATION_CREDENTIALS"
+
+ # Run the collector in the background with a known name
+ docker run --rm --name gemini-telemetry-collector --network host \
+ -v "${GITHUB_WORKSPACE}:/github/workspace" \
+ -e "GOOGLE_APPLICATION_CREDENTIALS=${GOOGLE_APPLICATION_CREDENTIALS/$GITHUB_WORKSPACE//github/workspace}" \
+ -w "/github/workspace" \
+ otel/opentelemetry-collector-contrib:0.108.0 \
+ --config /github/workspace/.gemini/collector-gcp.yaml &
+
+ # Wait for the collector to start up
+ echo "Waiting for collector to initialize..."
+ sleep 10
+
+ # Monitor the queue until it's empty or we time out
+ echo "Monitoring exporter queue..."
+ ATTEMPTS=0
+ MAX_ATTEMPTS=12 # 12 * 5s = 60s timeout
+ while true; do
+ # Use -f to fail silently if the server isn't ready yet
+ # Filter out the prometheus help/type comments before grabbing the value
+ QUEUE_SIZE=$(curl -sf http://localhost:8888/metrics | grep otelcol_exporter_queue_size | grep -v '^#' | awk '{print $2}' || echo "-1")
+
+ if [ "$QUEUE_SIZE" == "0" ]; then
+ echo "Exporter queue is empty, all data processed."
+ break
+ fi
+
+ if [ "$ATTEMPTS" -ge "$MAX_ATTEMPTS" ]; then
+ echo "::warning::Timed out waiting for exporter queue to empty. Proceeding with shutdown."
+ break
+ fi
+
+ echo "Queue size: $QUEUE_SIZE, waiting..."
+ sleep 5
+ ATTEMPTS=$((ATTEMPTS + 1))
+ done
+
+ # Gracefully shut down the collector
+ echo "Stopping collector..."
+ docker stop gemini-telemetry-collector
+ echo "Collector stopped."
+ env:
+ OTLP_GOOGLE_CLOUD_PROJECT: '${{ inputs.gcp_project_id }}'
+ GITHUB_ACTION_PATH: '${{ github.action_path }}'
+ GITHUB_REPOSITORY: '${{ github.repository }}'
+ GITHUB_RUN_ID: '${{ github.run_id }}'
+
branding:
icon: 'terminal'
color: 'blue'
diff --git a/scripts/collector-gcp.yaml.template b/scripts/collector-gcp.yaml.template
index 06cc80e28..ba3c157d5 100644
--- a/scripts/collector-gcp.yaml.template
+++ b/scripts/collector-gcp.yaml.template
@@ -1,34 +1,33 @@
receivers:
- otlp:
- protocols:
- grpc:
- endpoint: 'localhost:4317'
+ filelog:
+ include: ['.gemini/telemetry.log']
+ start_at: 'beginning'
+
processors:
+ resource:
+ attributes:
+ - key: 'github.repository'
+ value: 'GITHUB_REPOSITORY_PLACEHOLDER'
+ action: 'upsert'
+ - key: 'github.run_id'
+ value: 'GITHUB_RUN_ID_PLACEHOLDER'
+ action: 'upsert'
batch:
- timeout: '1s'
+ send_batch_size: 100
+ timeout: '10s'
+
exporters:
googlecloud:
project: 'OTLP_GOOGLE_CLOUD_PROJECT'
- metric:
- prefix: 'custom.googleapis.com/gemini_cli'
log:
- default_log_name: 'gemini_cli'
+ default_log_name: 'gemini-cli'
+
service:
- telemetry:
- logs:
- level: 'debug'
- metrics:
- level: 'none'
pipelines:
- traces:
- receivers: ['otlp']
- processors: ['batch']
- exporters: ['googlecloud']
- metrics:
- receivers: ['otlp']
- processors: ['batch']
- exporters: ['googlecloud']
logs:
- receivers: ['otlp']
- processors: ['batch']
+ receivers: ['filelog']
+ processors: ['batch', 'resource']
exporters: ['googlecloud']
+ telemetry:
+ metrics:
+ address: '0.0.0.0:8888'