Cloudflare GraphQL Analytics for zone traffic, firewall events, Workers metrics, and schema exploration. Use when querying Cloudflare analytics data or exploring the GraphQL API.
日本語の概要は準備中です。原文の説明を表示しています。
Use when working with Gcp — cost anti-hallucination rules, MANDATORY parallel execution patterns (30x speedup), monitoring aligners, reusable billing/pricing scripts, VAT/tax handling, and filtering/pagination.
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
Execute GCP CLI commands with proper credential injection.
These rules are MANDATORY when analyzing GCP billing data. Violating them produces wildly incorrect cost reports.
The cost column in billing exports is NOT your actual bill. It shows usage priced at contract/on-demand rates before credits are applied. Credits (promotional, SUDs, CUDs, free tier) are stored separately in the credits array with negative amounts.
-- Pre-tax net cost (filter cost_type = 'regular'):
NET COST = SUM(cost WHERE cost_type='regular') + SUM(credits.amount)
-- Tax-inclusive net cost (include all cost_types):
NET COST WITH TAX = SUM(cost) + SUM(credits.amount)
NEVER report SUM(cost) alone as the cost. Always compute net cost. In actual SQL, always use CAST(... AS NUMERIC) — see Rule 8.
The billing export table is at the billing account level and contains costs for ALL projects under that billing account. If you query without filtering by project.id, you aggregate costs across 10+ unrelated projects.
-- WRONG: Aggregates ALL projects in the billing account
SELECT service.description, SUM(cost) FROM `{BILLING_TABLE}` GROUP BY 1
-- CORRECT: Scoped to the target project with net cost
SELECT service.description,
SUM(CAST(cost AS NUMERIC))
+ SUM(IFNULL((SELECT SUM(CAST(c.amount AS NUMERIC)) FROM UNNEST(credits) c), 0)) AS net_cost
FROM `{BILLING_TABLE}`
WHERE project.id = '{PROJECT_ID}'
GROUP BY 1
If a row has 3 credit entries, LEFT JOIN UNNEST(credits) duplicates that row 3 times, tripling the SUM(cost). This is the most common cause of inflated cost reports.
-- WRONG: Inflates cost by N times (N = number of credits per row)
SELECT SUM(cost), SUM(credits.amount)
FROM `{BILLING_TABLE}` LEFT JOIN UNNEST(credits) AS credits
-- CORRECT: Subquery aggregates credits without duplicating cost rows
SELECT
SUM(CAST(cost AS NUMERIC)) AS gross_cost,
SUM(IFNULL((SELECT SUM(CAST(c.amount AS NUMERIC)) FROM UNNEST(credits) c), 0)) AS total_credits
FROM `{BILLING_TABLE}`
WHERE project.id = '{PROJECT_ID}'
Note: LEFT JOIN UNNEST(credits) is safe when you are ONLY aggregating credits.amount and NOT also aggregating cost — e.g., when filtering by credit type. The danger is combining it with SUM(cost) in the same query.
Before reporting any cost figure, verify it's physically possible.
Step 1: Check the currency. GCP billing accounts can use ANY currency (USD, VND, EUR, BRL, JPY, etc.). Run gcp_billing_currency or check the currency column BEFORE interpreting any numbers. A value of 5,000,000 in VND (~$200 USD) is very different from 5,000,000 in USD.
Step 2: Verify magnitude against known pricing (in the account's currency):
| Machine Type | Region | Monthly On-Demand Price (USD) |
|---|---|---|
| e2-micro | asia-southeast1 | ~$8/mo |
| e2-small | asia-southeast1 | ~$15/mo |
| e2-medium | asia-southeast1 | ~$30/mo |
| e2-standard-2 | asia-southeast1 | ~$60/mo |
| n1-standard-2 | asia-southeast1 | ~$60/mo (before SUD) |
| n2-standard-2 | asia-southeast1 | ~$70/mo |
Red flags that indicate a query error or currency mismatch:
If numbers seem unreasonably high, STOP and verify the currency before reporting. Do NOT present cost numbers to users without confirming the currency unit.
If net_cost is consistently $0 (or near-zero) while gross_cost is large, the account is on a promotional credit program (free trial, startup credits, enterprise credits). This is normal — not an anomaly.
MANDATORY first query before any billing analysis:
-- Step 0: Detect credit program status
SELECT
c.type AS credit_type,
c.full_name AS credit_name,
COUNT(*) AS line_items,
SUM(CAST(c.amount AS NUMERIC)) AS total_credit_amount
FROM `{BILLING_TABLE}`, UNNEST(credits) AS c
WHERE DATE(usage_start_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
AND project.id = '{PROJECT_ID}'
GROUP BY 1, 2
ORDER BY total_credit_amount ASC
Interpretation:
PROMOTION credits with large amounts → account is on promotional/trial programSUSTAINED_USAGE_DISCOUNT → automatic discounts on N1/N2/N2D/C2/M1/M2 instancesCOMMITTED_USAGE_DISCOUNT → organization has CUD commitmentsFREE_TIER → usage within free tier limitsIf PROMOTION credits fully offset costs: Report that the account is on a credit program. Do NOT generate alarmist alerts about "projected costs when credits expire" unless the user specifically asks for that analysis.
Gross cost fluctuates when credits are added/removed/adjusted. Only net cost reflects actual spending changes.
-- Pseudocode (not valid SQL — see Anomaly Detection query in BigQuery section for working version)
-- WRONG: Anomaly on gross cost → false positive from credit changes
HAVING SUM(cost) > threshold
-- CORRECT: Anomaly on net cost → real spending change
HAVING (SUM(cost) + SUM(credits_subquery)) > threshold
If billing data shows charges for a service (e.g., App Engine, Load Balancer) but gcloud commands show that service doesn't exist in the project, the charges are likely from another project in the same billing account that leaked into your unfiltered query. Go back to Rule 2 and add WHERE project.id = ....
The cost and credits.amount fields are Float type. Summing millions of rows accumulates floating-point errors. Always cast:
SUM(CAST(cost AS NUMERIC)) -- not SUM(cost)
invoice.month (YYYYMM): The invoice this line item belongs to. Use for invoice reconciliation.usage_start_time: When usage actually occurred. Use for trend analysis.Billing export data takes up to 24-48 hours to fully propagate. Do NOT alert on "missing data" for the current day or yesterday.
GCP billing accounts can be configured in any currency (USD, EUR, VND, BRL, JPY, GBP, etc.). The currency column in the billing export table identifies the billing currency. NEVER assume USD.
MANDATORY: Run gcp_billing_currency (or check SELECT DISTINCT currency FROM TABLE) as part of the first billing query. Include the currency in every cost report.
-- Check billing currency
SELECT DISTINCT currency FROM `{BILLING_TABLE}` WHERE project.id = '{PROJECT_ID}'
Reporting rules:
$ symbol without confirming the currency is USDCommon non-USD currencies and approximate rates (for sanity-checking only):
Before writing ANY billing query, verify ALL of the following:
gcp_billing_currency or equivalent queryWHERE project.id = '{PROJECT_ID}' filterSUM(CAST(cost AS NUMERIC)) + SUM(IFNULL((SELECT SUM(CAST(c.amount AS NUMERIC)) FROM UNNEST(credits) c), 0))LEFT JOIN UNNEST(credits) used alongside SUM(cost)CAST(... AS NUMERIC) for precisioncost_type is considered (regular vs tax vs adjustment vs rounding_error)ALL independent operations MUST run in parallel using background jobs (&) and wait
ENFORCEMENT RULES:
for item in $items; do cmd $item; done (causes O(n) runtime){ cmd1 } & { cmd2 } & { cmd3 } & waitPARALLEL PATTERN (CORRECT):
for instance in $instances; do
operation "$instance" & # ← Spawn as background job
done
wait # ← Wait for all to complete
SEQUENTIAL PATTERN (FORBIDDEN - ONLY if operations have data dependencies):
result=$(operation1)
operation2 "$result" # ← Only valid if operation2 requires operation1's output
&) and wait for independent operations
{ ... } & with wait at the endwait before processing--quiet (-q) flag or export CLOUDSDK_CORE_DISABLE_PROMPTS=1 to disable prompts in scriptsFILTERING ORDER MATTERS - Understand server-side vs client-side
--filter (VARIES BY COMMAND) - Can be server-side OR client-side
--log-http to verify: if filter appears in API request, it's server-side--format (ALWAYS CLIENT-SIDE) - Formatting after data retrieval
--format="value(...)" for clean, parseable outputPERFORMANCE IMPACT:
--log-http to check which mode your command usesEXAMPLES:
# Efficient: --filter with --format for minimal output
gcloud compute instances list --filter="status=RUNNING" \
--format="value(name,zone.scope(zones),machineType.scope(machineTypes))"
# Verify if filter is server-side (look for filter in HTTP request)
gcloud compute instances list --filter="status=RUNNING" --log-http 2>&1 | grep -i filter
# Multiple filter conditions
gcloud compute instances list \
--filter="status=RUNNING AND machineType~n1-standard" \
--format="value(name,zone)"
COMMON FILTER OPERATORS:
= exact match, != not equal, ~ regex match, !~ regex not match: substring match (HAS operator)>, >=, <, <= for comparisonsAND, OR, NOT for boolean logicPAGINATION FOR LARGE DATASETS - Prevent timeouts and memory issues
KEY PARAMETERS:
--limit=N: Maximum total items to return (stops early)--page-size=N: Items per API call (internal pagination, still returns all unless --limit set)--sort-by=FIELD: Sort results (prefix with ~ for descending)ORDER OF OPERATIONS (gcloud applies in this order):
--flatten → 2. --sort-by → 3. --filter → 4. --limitEXAMPLES:
# Get first 10 instances only
gcloud compute instances list --limit=10 --format="value(name,zone)"
# Paginate with smaller chunks (memory efficiency)
gcloud compute instances list --page-size=50 --limit=200 \
--format="value(name,zone)"
# Sort by creation time, newest first
gcloud compute instances list --sort-by=~creationTimestamp --limit=5 \
--format="value(name,creationTimestamp)"
BEST PRACTICE: Combine --filter + --limit to minimize data transfer:
# Filter server-side, limit client-side
gcloud compute instances list --filter="status=RUNNING" --limit=100 \
--format="value(name,zone)"
USEFUL PROJECTION FUNCTIONS - Reduce post-processing with built-in transforms
EXTRACTION FUNCTIONS:
.scope(segment) - Extract last URL segment (e.g., zone name from full URL).basename() - Get filename from path.segment(n) - Get nth segment from URLDATE/TIME FUNCTIONS:
.date(format) - Format timestamp (e.g., .date('%Y-%m-%d')).date(tz=LOCAL) - Convert to local timezoneSTRING FUNCTIONS:
.yesno(yes, no) - Convert boolean to custom strings.list() - Format as comma-separated listEXAMPLES:
# Extract zone name from full URL
gcloud compute instances list \
--format="value(name,zone.scope(zones),machineType.scope(machineTypes))"
# Output: my-vm us-central1-a n1-standard-1
# Format creation date
gcloud compute instances list \
--format="table(name,creationTimestamp.date('%Y-%m-%d'),status)"
# Boolean formatting
gcloud compute instances list \
--format="value(name,scheduling.preemptible.yesno('preemptible','on-demand'))"
# Get single value (no headers)
gcloud config get-value project --format="value(.)"
REFERENCE: Run gcloud topic projections for full documentation
ANTI-PATTERN EXAMPLE (SEQUENTIAL - SLOW - UNACCEPTABLE)
#!/bin/bash
# RUNTIME: ~60 seconds for 30 instances (2 sec per call x 30)
END_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
START_TIME=$(date -u -d "30 days ago" +"%Y-%m-%dT%H:%M:%SZ")
echo "GCP VM Metrics Summary ($START_TIME to $END_TIME)"
PROJECT_ID=$(gcloud config get-value project)
echo "Project: $PROJECT_ID"
# Get zones and instances
gcloud compute zones list --format="value(name)" | while read zone; do
instances=$(gcloud compute instances list --zones="$zone" --format="value(name)" --project="$PROJECT_ID")
if [ -n "$instances" ]; then
echo "Zone: $zone"
# This SEQUENTIAL loop is FORBIDDEN
echo "$instances" | while read instance_name; do
echo " Instance: $instance_name"
# Sequential metric fetches - UNACCEPTABLE
gcloud monitoring time-series list \
--filter="resource.labels.project_id='$PROJECT_ID' AND resource.labels.zone='$zone' AND resource.labels.instance_id='$instance_name' AND metric.type='compute.googleapis.com/instance/cpu/utilization'" \
--interval.start-time="$START_TIME" \
--interval.end-time="$END_TIME" \
--aggregation.alignment-period=3600s \
--aggregation.per-series-aligner="ALIGN_MEAN" \
--format="value(points[].value.doubleValue)" \
--project="$PROJECT_ID"
gcloud monitoring time-series list \
--filter="resource.labels.project_id='$PROJECT_ID' AND resource.labels.zone='$zone' AND resource.labels.instance_id='$instance_name' AND metric.type='compute.googleapis.com/instance/network/received_bytes_count'" \
--interval.start-time="$START_TIME" \
--interval.end-time="$END_TIME" \
--aggregation.alignment-period=3600s \
--aggregation.per-series-aligner="ALIGN_RATE" \
--format="value(points[].value.doubleValue)" \
--project="$PROJECT_ID"
done
fi
done
# TOTAL TIME: ~60 seconds (UNACCEPTABLE for 30+ instances)
CORRECT EXAMPLE (PARALLEL - FAST - REQUIRED)
#!/bin/bash
# RUNTIME: ~2 seconds for 30 instances (all run simultaneously)
END_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
START_TIME=$(date -u -d "30 days ago" +"%Y-%m-%dT%H:%M:%SZ")
PROJECT_ID=$(gcloud config get-value project 2>/dev/null)
# Fetch a single metric (called in parallel)
get_metric() {
local instance=$1 zone=$2 metric=$3 aligner=$4
gcloud monitoring time-series list \
--filter="resource.labels.instance_id='$instance' AND metric.type='$metric'" \
--interval.start-time="$START_TIME" --interval.end-time="$END_TIME" \
--aggregation.alignment-period=3600s \
--aggregation.per-series-aligner="$aligner" \
--format="value(points[].value.doubleValue)" \
--project="$PROJECT_ID" \
| awk -v i="$instance" -v m="$metric" '{sum+=$1; count++} END {if(count>0) printf "%s\t%s\t%.2f\n", i, m, sum/count}'
}
# Process one instance: fetch multiple metrics in parallel
process_instance() {
local instance=$1 zone=$2
get_metric "$instance" "$zone" "compute.googleapis.com/instance/cpu/utilization" "ALIGN_MEAN" &
get_metric "$instance" "$zone" "compute.googleapis.com/instance/network/received_bytes_count" "ALIGN_RATE" &
wait # Wait for all metrics of this instance
}
# Process ALL instances in parallel
instances=$(gcloud compute instances list --format="value(name,zone.scope(zones))" --project="$PROJECT_ID")
echo "$instances" | while read instance zone; do
process_instance "$instance" "$zone" &
done
wait # Wait for all instances to complete
PERFORMANCE COMPARISON TABLE
| Pattern | Instances | Time/Call | Total Time | Speed |
|---|---|---|---|---|
| Sequential (❌) | 30 | 2 sec | ~60 sec | Baseline |
| Parallel (✅) | 30 | 2 sec | ~2 sec | 30x faster |
| Sequential (❌) | 100 | 2 sec | ~200 sec | Baseline |
| Parallel (✅) | 100 | 2 sec | ~2 sec | 100x faster |
KEY DIFFERENCES IN THIS SCRIPT (What Makes It Parallel)
process_instance "$instance" "$zone" & - spawns each instance as background jobwait - waits for all instances to completeprocess_instance: metrics are fetched in parallel (with & and inner wait)--format="value(name,zone.scope(zones))" for efficient extractionVALIDATION CHECKLIST FOR AGENT Before outputting ANY script, check every item:
& background job spawns in script: ___wait statementgcloud projects list --format="value(projectId,name,lifecycleState)"gcloud compute instances list --format="value(name,zone,machineType.scope(machineTypes),status)"gcloud compute instances describe myInstance --zone=us-central1-a --format="value(name,machineType,status,scheduling.preemptible)"gcloud storage buckets list --format="value(name,location,storageClass)"gcloud sql instances list --format="value(name,databaseVersion,region,tier,state)"gcloud config get-value project --format="value(.)"gcloud app services list --format="value(id,split.allocations.keys())"gcloud functions list --format="value(name,status,trigger.eventTrigger.eventType)"gcloud billing accounts list --format="value(name,displayName,open)"gcloud container clusters list --format="value(name,location,status,currentMasterVersion)"BILLING ACCOUNT & BUDGET MANAGEMENT - gcloud billing commands
LIST BILLING ACCOUNTS (accounts you have access to):
# List all billing accounts with key fields
gcloud billing accounts list --format="value(name,displayName,open)"
# Get billing account ID only (for scripting)
gcloud billing accounts list --format="value(name)" --filter="open=true"
DESCRIBE BILLING ACCOUNT:
# Get account details (check if sub-account)
gcloud billing accounts describe BILLING_ACCOUNT_ID \
--format="value(displayName,masterBillingAccount,open)"
# If masterBillingAccount is set, this is a reseller sub-account
LIST PROJECTS UNDER BILLING ACCOUNT:
# List all projects linked to a billing account
gcloud billing projects list --billing-account=BILLING_ACCOUNT_ID \
--format="value(projectId,billingEnabled)"
# Filter to only enabled projects
gcloud billing projects list --billing-account=BILLING_ACCOUNT_ID \
--filter="billingEnabled=true" --format="value(projectId)"
CHECK PROJECT BILLING STATUS:
# Check if specific project has billing enabled
gcloud billing projects describe PROJECT_ID --format="value(billingEnabled)"
# Returns: True or False
# Get billing account linked to project
gcloud billing projects describe PROJECT_ID \
--format="value(billingAccountName)"
BUDGET MANAGEMENT:
# List all budgets for a billing account
gcloud billing budgets list --billing-account=BILLING_ACCOUNT_ID \
--format="value(displayName,amount.specifiedAmount.units,amount.specifiedAmount.currencyCode)"
# Describe specific budget details
gcloud billing budgets describe BUDGET_ID --billing-account=BILLING_ACCOUNT_ID \
--format="value(displayName,amount,budgetFilter,thresholdRules)"
PARALLEL PATTERN FOR MULTI-ACCOUNT ANALYSIS:
# Fetch billing info for multiple accounts in parallel
accounts=$(gcloud billing accounts list --format="value(name)" --filter="open=true")
for account in $accounts; do
{
projects=$(gcloud billing projects list --billing-account="$account" \
--format="value(projectId)" --filter="billingEnabled=true")
echo "$account: $(echo "$projects" | wc -l) projects"
} &
done
wait
CRITICAL: VAT/TAX AWARENESS - Why your costs may differ from Console
IMPORTANT: GCP Pricing API and BigQuery billing exports return TAX-EXCLUSIVE (pre-tax) prices. The GCP Console dashboard shows TOTAL costs INCLUDING taxes (VAT, GST, sales tax, etc.).
THIS CAUSES DISCREPANCIES between API results and what customers see in their Console!
HOW GCP HANDLES TAXES:
cost column is PRE-TAX; taxes are separate rows with cost_type = "tax"TAX RATES BY REGION (examples - varies by location and changes over time):
TO GET TAX-INCLUSIVE TOTALS FROM BIGQUERY:
-- Get total cost INCLUDING taxes (matches Console dashboard)
-- Note: project.id filter required per Rule 2
SELECT
invoice.month AS invoice_month,
SUM(CASE WHEN cost_type != 'tax' THEN CAST(cost AS NUMERIC) ELSE 0 END) AS pre_tax_cost,
SUM(CASE WHEN cost_type = 'tax' THEN CAST(cost AS NUMERIC) ELSE 0 END) AS tax_amount,
SUM(CAST(cost AS NUMERIC))
+ SUM(IFNULL((SELECT SUM(CAST(c.amount AS NUMERIC)) FROM UNNEST(credits) c), 0)) AS net_cost_with_tax
FROM `{BILLING_TABLE}`
WHERE project.id = '{PROJECT_ID}'
AND invoice.month = FORMAT_DATE('%Y%m', CURRENT_DATE())
GROUP BY 1
-- Get tax breakdown by project (intentionally no project.id filter: multi-project breakdown)
SELECT
project.id AS project_id,
SUM(CASE WHEN cost_type != 'tax' THEN CAST(cost AS NUMERIC) ELSE 0 END) AS usage_cost,
SUM(CASE WHEN cost_type = 'tax' THEN CAST(cost AS NUMERIC) ELSE 0 END) AS tax_cost,
SUM(CAST(cost AS NUMERIC))
+ SUM(IFNULL((SELECT SUM(CAST(c.amount AS NUMERIC)) FROM UNNEST(credits) c), 0)) AS net_total_with_tax
FROM `{BILLING_TABLE}`
WHERE DATE(usage_start_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY 1
ORDER BY net_total_with_tax DESC
-- Get tax types (VAT, GST, sales tax, etc.)
SELECT
sku.description AS tax_type,
SUM(CAST(cost AS NUMERIC)) AS tax_amount
FROM `{BILLING_TABLE}`
WHERE project.id = '{PROJECT_ID}'
AND cost_type = 'tax'
AND DATE(usage_start_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY 1
ORDER BY 2 DESC
WHEN REPORTING COSTS TO USERS:
COST COMPARISON FORMULA (pseudocode — use CAST/UNNEST subquery pattern in actual SQL):
Console Total = Usage Cost + Credits + Taxes
= SUM(cost WHERE cost_type='regular')
+ SUM(credits.amount) -- credits are negative
+ SUM(cost WHERE cost_type='tax')
= SUM(cost) + SUM(credits.amount) -- simplified: all cost_types
get_pricing_gcp.sh)DO NOT read or modify the script file. Only source and call the function.
SETUP (at the start of your script):
source ./_skills/connections/gcp/gcp/scripts/get_pricing_gcp.sh
FUNCTION: get_gcp_cost RESOURCE REGION
Auto-detects the GCP service from the resource name prefix and returns on-demand pricing in TOON format.
NOTE: All prices are TAX-EXCLUSIVE. See VAT/Tax Handling for tax-inclusive calculations.
Supported resource prefixes:
| Prefix | Service | Example |
|---|---|---|
e2-, n1-, n2-, c2-, c3- | Compute Engine | e2-standard-2 |
cloudsql-, db- | Cloud SQL | cloudsql-db-n1-standard-2 |
gcs- | Cloud Storage | gcs-standard |
functions- | Cloud Functions | functions-256mb |
cloudrun- | Cloud Run | cloudrun-1cpu-512mb |
redis- | Memorystore | redis-basic-1gb |
bq- | BigQuery | bq-ondemand |
pd- | Persistent Disk | pd-ssd-100gb |
lb- | Load Balancer | lb-forwarding-rule |
cloudnat- | Cloud NAT | cloudnat-standard |
gke- | GKE | gke-standard |
Compute Engine detail: GCP bills vCPU and RAM separately. The script has a built-in machine spec table and queries both Core and Ram SKUs, combining them into a total hourly/monthly estimate.
Examples:
source ./_skills/connections/gcp/gcp/scripts/get_pricing_gcp.sh
get_gcp_cost e2-standard-2 asia-southeast1
get_gcp_cost n2-standard-4 us-central1
get_gcp_cost gcs-standard us-central1
get_gcp_cost cloudsql-db-n1-standard-2 asia-southeast1
COMMON METRICS:
ALIGNERS (per-series-aligner):
CRITICAL: alignment-period MUST be >= 60 seconds If you specify a per-series-aligner other than ALIGN_NONE, alignment-period is REQUIRED and must be at least 60 seconds.
CROSS-SERIES REDUCERS (aggregate across multiple resources):
CROSS-SERIES EXAMPLE (aggregate CPU across all instances in a zone):
gcloud monitoring time-series list \
--filter="metric.type='compute.googleapis.com/instance/cpu/utilization'" \
--aggregation.alignment-period=3600s \
--aggregation.per-series-aligner=ALIGN_MEAN \
--aggregation.cross-series-reducer=REDUCE_MEAN \
--aggregation.group-by-fields="resource.labels.zone" \
--format="value(points[].value.doubleValue)"
get_billing_gcp.sh)DO NOT read or modify the script file. Only source and call the functions.
SETUP (at the start of your script):
source ./_skills/connections/gcp/gcp/scripts/get_billing_gcp.sh
All functions enforce anti-hallucination rules: WHERE project.id filter, CAST(... AS NUMERIC) on financial fields, net cost via UNNEST subquery (never LEFT JOIN UNNEST + SUM(cost)), cost_type = 'regular' where appropriate. Output is TOON format (tab-separated).
TABLE NAMING CONVENTION:
dataset.gcp_billing_export_v1_<BILLING_ACCOUNT_ID_NO_DASHES>dataset.gcp_billing_export_resource_v1_<BILLING_ACCOUNT_ID_NO_DASHES>012ABC-456DEF-789GHI becomes table suffix 012ABC456DEF789GHI (dashes removed)FUNCTION REFERENCE:
| Function | Purpose | Signature |
|---|---|---|
gcp_billing_currency | Detect billing currency (MANDATORY first) | TABLE PROJECT_ID |
gcp_billing_credits | Credit program detection (MANDATORY second) | TABLE PROJECT_ID |
gcp_billing_summary | Top services by net cost | TABLE PROJECT_ID [--days N] |
gcp_billing_trend | Daily net cost trend | TABLE PROJECT_ID [--days N] |
gcp_billing_anomalies | Z-score anomaly on net cost | TABLE PROJECT_ID |
gcp_billing_by_resource | Resource-level breakdown (detailed export) | TABLE PROJECT_ID [--days N] |
gcp_billing_by_sku | SKU-level breakdown | TABLE PROJECT_ID [--days N] |
gcp_billing_invoice | Invoice reconciliation (uses invoice.month) | TABLE PROJECT_ID [--month YYYYMM] |
gcp_billing_compare | Multi-project comparison (no project filter) | TABLE [--days N] |
MANDATORY WORKFLOW (every billing analysis):
gcp_billing_currency first to detect the billing currency (see Rule 11)gcp_billing_credits second to detect credit programscredit_coverage_ratio: close to -1.0 = fully covered by credits (do NOT alarm); -0.3 to -0.01 = partial discounts (normal); ~0 = minimal creditsgcp_billing_summary or other functions as neededExamples:
source ./_skills/connections/gcp/gcp/scripts/get_billing_gcp.sh
TABLE="dataset.gcp_billing_export_v1_012ABC456DEF789GHI"
PROJECT="my-project-id"
# Step 0a: Detect billing currency (MANDATORY - see Rule 11)
gcp_billing_currency "$TABLE" "$PROJECT"
# Step 0b: Detect credit programs (MANDATORY)
gcp_billing_credits "$TABLE" "$PROJECT"
# Top services by net cost (last 30 days)
gcp_billing_summary "$TABLE" "$PROJECT" --days 30
# Daily trend
gcp_billing_trend "$TABLE" "$PROJECT" --days 14
# Anomaly detection
gcp_billing_anomalies "$TABLE" "$PROJECT"
# Resource-level breakdown (requires detailed export table)
gcp_billing_by_resource "$TABLE" "$PROJECT" --days 7
# SKU-level breakdown
gcp_billing_by_sku "$TABLE" "$PROJECT" --days 7
# Invoice reconciliation (current month)
gcp_billing_invoice "$TABLE" "$PROJECT"
# Invoice reconciliation (specific month)
gcp_billing_invoice "$TABLE" "$PROJECT" --month 202601
# Multi-project comparison (no project filter)
gcp_billing_compare "$TABLE" --days 7
BILLING EXPORT SCHEMA REFERENCE (key columns):
| Column | Description |
|---|---|
currency | ISO 4217 currency code (USD, VND, EUR, etc.). Check this FIRST — never assume USD. |
cost | Usage cost at contract/on-demand rate, BEFORE credits. NOT your actual bill. |
cost_at_list | Cost at public list price (before negotiated discounts). |
credits | Array of credit entries. Each has type, amount (always negative), full_name. |
credits.type | PROMOTION, SUSTAINED_USAGE_DISCOUNT, COMMITTED_USAGE_DISCOUNT, FREE_TIER, DISCOUNT, etc. |
cost_type | "regular", "tax", "adjustment", or "rounding_error". |
project.id | GCP project ID. ALWAYS filter by this. |
invoice.month | YYYYMM string. Use for invoice reconciliation. |
usage_start_time | When usage occurred. Use for trend analysis. |
resource.name | Resource identifier (detailed export only). |
CREDIT TYPES:
| Credit Type | Meaning | Typical Coverage |
|---|---|---|
PROMOTION | Trial credits, startup credits, enterprise promotional | Can be 100% (full offset) |
SUSTAINED_USAGE_DISCOUNT | Auto-discount for N1/N2/N2D/C2/M1/M2 running >25% of month | Up to 30% for N1 |
COMMITTED_USAGE_DISCOUNT | Resource-based CUD commitment | 37-55% depending on term |
COMMITTED_USAGE_DISCOUNT_DOLLAR_BASE | Spend-based CUD commitment | Varies by commitment |
FREE_TIER | Always-free tier usage | Small amounts |
DISCOUNT | Other negotiated discounts | Varies |
RESELLER_MARGIN | Reseller margin credits | Varies |
NOTE on SUDs: E2 machine types are NOT eligible for Sustained Use Discounts. Only N1, N2, N2D, C2, M1, M2 families receive SUDs.
BUILT-IN HELP - Learn filter/format/projection syntax
gcloud topic filters # Filter expression syntax and operators
gcloud topic formats # Output format options and projections
gcloud topic projections # Projection functions (.scope(), .date(), etc.)
PARALLEL vs SEQUENTIAL - Quick Reference
for item in $items; do operation "$item" & done; waitFORBIDDEN ANTI-PATTERNS (see detailed examples above):
for x in $list; do cmd; done → use & done; waitresult1=$(cmd1); result2=$(cmd2) → use cmd1 & cmd2 & waitPresent results as a structured report:
Gcp Report
══════════
Resources discovered: [count]
Resource Status Key Metric Issues
──────────────────────────────────────────────
[name] [ok/warn] [value] [findings]
Summary: [total] resources | [ok] healthy | [warn] warnings | [crit] critical
Action Items: [list of prioritized findings]
Target ≤50 lines of output. Use tables for multi-resource comparisons.
| Shortcut | Counter | Why |
|---|---|---|
| "I'll skip discovery and check known resources" | Always run Phase 1 discovery first | Resource names change, new resources appear — assumed names cause errors |
| "The user only asked for a quick check" | Follow the full discovery → analysis flow | Quick checks miss critical issues; structured analysis catches silent failures |
| "Default configuration is probably fine" | Audit configuration explicitly | Defaults often leave logging, security, and optimization features disabled |
| "Metrics aren't needed for this" | Always check relevant metrics when available | API/CLI responses show current state; metrics reveal trends and intermittent issues |
| "I don't have access to that" | Try the command and report the actual error | Assumed permission failures prevent useful investigation; actual errors are informative |
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Cloudflare GraphQL Analytics for zone traffic, firewall events, Workers metrics, and schema exploration. Use when querying Cloudflare analytics data or exploring the GraphQL API.
日本語の概要は準備中です。原文の説明を表示しています。
Use when working with Alloydb — google AlloyDB instance analysis, query insights, columnar engine optimization, maintenance windows, and cluster health.
日本語の概要は準備中です。原文の説明を表示しています。
Use when working with Aqua — aqua Security platform analysis. Covers container runtime protection, image assurance policies, compliance frameworks, vulnerability management, workload protection, and registry scanning. Use when analyzing container security posture, reviewing image compliance, investigating runtime alerts, or auditing security policies.
日本語の概要は準備中です。原文の説明を表示しています。
Use when working with Bigquery — google BigQuery job analysis, slot utilization, cost analysis, dataset management, and query optimization.
日本語の概要は準備中です。原文の説明を表示しています。
Use when working with Cassandra — apache Cassandra keyspace analysis, compaction strategies, repair status, nodetool operations, and cluster health monitoring.
日本語の概要は準備中です。原文の説明を表示しています。
Use when working with Checkov — checkov infrastructure-as-code security scanning. Covers Terraform, CloudFormation, Kubernetes, and Dockerfile scanning, policy management, custom checks, compliance frameworks, and suppression management. Use when scanning IaC for security misconfigurations, evaluating compliance, managing custom policies, or reviewing scan results.
日本語の概要は準備中です。原文の説明を表示しています。