Generated banner for Cloud Monitoring Alert Configuration
Generated logo for Cloud Monitoring Alert Configuration

Cloud Monitoring Alert Configuration

GoogleOfficialPublished by Google

  • Skill
  • Workflow
  • Cloud and DevOps
  • Apache-2.0
  • Low risk
  • Has scripts

From the author

Configures Cloud Monitoring alerting policies using Terraform and PromQL across Cloud Run, Google Kubernetes Engine (GKE), Compute Engine, AI Hypercomputer reservations, Vertex AI Agent Engine, and generic Google Cloud resources. Use when creating, reviewing, migrating, or deduplicating Terraform alerting policies for latency, traffic, error rates, saturation, host or reservation maintenance, GPU XID insights, or AI agent telemetry. Don't use for standalone PromQL query authoring without alerting, log querying, or billing cost audits.
— the description by Google

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured workflow for defining, reviewing, and managing Cloud Monitoring alerting policies. It leverages Terraform for infrastructure-as-code and PromQL for metric conditions, ensuring consistent observability across Google Cloud resources including Cloud Run, GKE, Compute Engine, and AI Agent platforms. The skill enforces best practices like the Four Golden Signals, dynamic grouping, and proper labeling, while providing clear paths for delegating SLO-specific configurations and notification channel management.

What it does

  • Generates parameterized Terraform configurations for Cloud Monitoring alert policies.
  • Implements PromQL-based conditions for high-signal monitoring.
  • Provides resource-specific guidance for GKE, Cloud Run, Compute Engine, and AI agents.
  • Enforces standardized labeling for all generated alerting resources.
  • Integrates with specialized scripts to analyze traffic patterns for AI agent telemetry.
  • Delegates SLO and notification channel configuration to dedicated skills.

When to use it

  • When creating or migrating Terraform-based alerting policies for Google Cloud infrastructure.
  • When setting up monitoring for AI agent reliability, quality, and cost telemetry.
  • When deduplicating existing alert policies to improve signal-to-noise ratios.
  • When configuring alerts for latency, traffic, error rates, or saturation across cloud services.

Advantages

  • Ensures consistent observability standards across diverse cloud environments.
  • Reduces manual configuration errors through structured Terraform templates.
  • Promotes best practices like dynamic grouping and the Four Golden Signals.
  • Maintains clear separation of concerns by delegating SLO and notification tasks.
  • Provides data-driven traffic analysis for accurate AI agent alert thresholds.

Usage examples

“Create a Terraform alerting policy for high latency on my GKE service.”
The agent will guide you through selecting the appropriate GKE PromQL queries, generate the google_monitoring_alert_policy Terraform resource, and prompt you to attach notification channels.
“Configure a cost alert for my Vertex AI Agent based on token usage.”
The agent will run the traffic analysis script to determine your workload pattern and generate a PromQL-based alert policy tailored to your agent's historical token consumption.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/google/cloud-monitoring-alert-configuration/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip cloud-monitoring-alert-configuration.zip -d .agents/skills

Documentation by Google

Configure Cloud Monitoring Alerts

Configure high-signal alerting policies in Cloud Monitoring using Terraform (google_monitoring_alert_policy) and PromQL (condition_prometheus_query_language).

Usage Attribution

For all gcloud CLI, REST API, and MCP attribution requirements when executing commands with this skill, follow the instructions in Usage Attribution.

Enforce Core Alerting Rules

  1. Apply the Four Golden Signals: Cover latency, traffic, errors, and saturation for the target workload.

  2. Use Dynamic Grouping: Aggregate metrics by resource labels and parameterize thresholds with Terraform variables. Never hardcode ephemeral pod or instance identifiers.

  3. Default to PromQL: Use Prometheus Query Language (PromQL) for metric conditions, and use log-based alerts (condition_matched_log or google_logging_metric) for lifecycle and audit events.

  4. Attach Skill Attribution Labels: Always include user_labels with created-with-google-skill = "cloud-monitoring-alert-configuration" on every generated google_monitoring_alert_policy resource.

  5. Require User Confirmation Before Mutating Resources: Never execute commands that modify infrastructure, enable telemetry, create online monitors, or apply Terraform without waiting for explicit user confirmation.

  6. Prompt for Notification Channels: Alerting policies without notification channels incur charges without notifying anyone during an incident. Whenever notification channels are not specified in the user prompt across any workflow, explicitly inform the user that no notification channels are attached to the alerting policies, advise them to configure and attach notification channels before deploying, and ask at the end of your response if they want to configure notification channels.

Route by Target Resource Type

Identify the target resource type and read only the matching reference file directly. Never run directory listings or workspace file searches to look for queries or .tf files unless the prompt explicitly provides a file path. If a user asks to fix or validate a PromQL query without providing the query text or a file path, construct a representative broken-and-corrected query example directly.

Configure Cloud Run Alerts
Configure Google Kubernetes Engine Alerts
Configure AI Agent Alerts
Configure Compute Engine and AI Hypercomputer Alerts
  • Compute Engine VMs, MIGs, GPU XID Insights, Host or Reservation Maintenance (type=scheduled, unscheduled, or multiple), and Machine or Domain Health: compute_engine_alerts.md

Configure Generic Resource Alerts
Delegate Service Level Objective Alerts

Delegate to the google-cloud-slo-alert-configuration skill. That skill owns the SLO setup wizard, the burn-rate PromQL templates (references/promql_templates.md), the SLI metric mapping (references/service_metrics.md), and the App Hub scoping labels (references/app_hub_labels.md). Do NOT duplicate those templates here or claim that this skill owns its own SLO PromQL template library.

Delegate whenever the user asks for an availability or latency SLO, an error budget or burn-rate alert, or a Service Level Objective on any resource. When SLOs are only one part of a broader request (for example, a full production alerting suite for a Cloud Run service), delegate the SLO policies and continue generating the remaining golden-signal policies from the resource-specific reference in the same response.

Every resource reference carries a Context to hand off list naming the SLI metric, its good or bad filter, and the grouping labels — under a ## Delegate Service Level Objective Alerts heading for Cloud Run and generic resources, and inside the SLO section itself for GKE and Agent Platform. Read it and pass that context on, so the SLO skill does not repeat discovery you have already done. When delegating, you MUST also:

  1. State the SLO target and window explicitly if the user gave them, or let the SLO skill apply its SRE defaults (99.9% over a rolling 28 days) if they did not.

  2. Require the returned policies to carry user_labels with created-with-google-skill = "cloud-monitoring-alert-configuration" so attribution stays consistent with the rest of the generated suite. This literal value does NOT change when you delegate: the label records the entry-point skill, not whichever skill supplied the template. Do NOT set created-with-google-skill = "google-cloud-slo-alert-configuration" on policies generated through this delegation.

  3. Preserve the burn-rate duration contract, which google-cloud-slo-alert-configuration does not specify: Fast Burn (1h and 5m windows, factor 14.4) carries duration = "300s", and Slow Burn ([3d] and [6h] lookback, factor 1.0) omits the duration field entirely — do not emit duration = "0s" in its place. Cloud Monitoring rejects a non-zero retest buffer when the lookback window exceeds 25 hours.

  4. When no notification channels are provided, inform the user that no notification channels are attached to the alerting policies, advise them to configure and attach notification channels, and ask if they want to configure notification channels.

[!IMPORTANT] Always tell the user about the referral, even on the fallback path. Some reference files in this skill include standalone burn-rate templates to use when the google-cloud-slo-alert-configuration skill is not installed. If you emit policies from those fallback templates, your response MUST still tell the user that google-cloud-slo-alert-configuration owns SLO configuration, state that the emitted policies use the local fallback templates, and list the handoff context. Never silently present SLO policies as if this skill owned them.

[!NOTE] Exception: Agent Platform (OpenTelemetry-instrumented AI agents on any runtime, including Vertex AI Agent Engine and Cloud Run) is the one resource whose Fast and Slow burn policies live in this skill and remain authoritative. Delegate only for SLO customization — see Reliability.

  • Notification Channels: Delegate to cloud-monitoring-notification-channels-configuration to configure email, PagerDuty, Pub/Sub, or Slack channels. When an alerting policy has no notification channels attached, inform the user that no notification channels are attached and that they should configure notification channels and attach them to the alerting policy.

  • PromQL Authoring: Delegate to cloud-monitoring-promql-query for standalone PromQL query authoring or metric exploration.

Follow the Alert Configuration Workflow

  1. Discover: Identify target resources, metric schemas, and scoping projects using the lookup commands in the matching reference file (such as discover_metric_schema.py for Compute Engine metrics and other Google Cloud resource metrics, or gather_agent_info.py, check_telemetry.py, analyze_traffic.py, create_online_monitor.py, list_trace_scope_table_names.py, and list_log_scope_table_names.py for AI agents).

  2. Route: Load the reference file for the target resource type or delegate SLOs to google-cloud-slo-alert-configuration.

  3. Generate: Produce parameterized Terraform HCL configurations with required user_labels.

  4. Validate: When the loaded reference file requires a validation script (such as lint_promql.py, validate_config.py, lint_syntax.py, or scan_duplicates.py), run or print that exact script command. Do not list or search the scripts/ directory.

  5. Explain and Prompt: Explain each alert policy in plain English. When no notification channels are provided, tell the user that no notification channels are attached to the alerting policy, advise them to configure and attach notification channels, and ask if they want to configure notification channels.

Files

scripts/agent_platform/analyze_traffic.py

#!/usr/bin/env python3
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Traffic metrics analyzer for Agent Platform agents (using OpenTelemetry).

Computes zero-ratio, variance ratio, and 1-week autocorrelation on a 14-day
metrics time series (at 5-minute intervals) and classifies the traffic pattern
to recommend the optimal dynamic PromQL alerting threshold strategy.
"""

import argparse
import json
import math
import statistics
import sys
import time

try:
  from google.auth import exceptions as auth_exceptions  # pytype: disable=import-error  # pyrefly: ignore[missing-import]
  from google.cloud import monitoring_v3  # pytype: disable=import-error  # pyrefly: ignore[missing-import]
except ImportError:
  auth_exceptions = None
  monitoring_v3 = None

# Number of 5-minute data points in a 7-day weekly window
# (12 points/hour * 24 hours/day * 7 days/week)
_POINTS_PER_WEEK = 2016

# Supported metric types and their corresponding resource labels.
_SUPPORTED_METRIC_TYPE_LABEL = {
    "workload.googleapis.com/gen_ai.invoke_agent.duration": (
        "metric.labels.gen_ai_agent_name"
    ),
    "workload.googleapis.com/gen_ai.client.token.usage": (
        "resource.labels.namespace"
    ),
}

_ALIGN_DELTA = (
    monitoring_v3.Aggregation.Aligner.ALIGN_DELTA
    if monitoring_v3 is not None
    else 1
)

# Supported metric types and their corresponding aligners.
_SUPPORTED_METRIC_TYPE_ALIGNER = {
    "workload.googleapis.com/gen_ai.invoke_agent.duration": _ALIGN_DELTA,
    "workload.googleapis.com/gen_ai.client.token.usage": _ALIGN_DELTA,
}

# Supported metric types and their filters for live queries.
_SUPPORTED_METRIC_TYPE_FILTERS = {
    "workload.googleapis.com/gen_ai.invoke_agent.duration": [],
    "workload.googleapis.com/gen_ai.client.token.usage": [],
}


class CredentialsMissingError(Exception):
  """Raised when Google Cloud credentials are not found."""

  pass


def compute_metrics_and_classify(values: list[float]) -> dict[str, float | str]:
  """Computes statistical metrics and classifies the traffic profile.

  Args:
      values: A list of floats representing the 5-minute rate telemetry. Should
        be at least 4032 points (14 days).

  Returns:
      A dictionary with statistical metrics and the classification profile.

  Raises:
      ValueError: If values contains fewer than 4032 points (14 days).
  """
  required_points = 2 * _POINTS_PER_WEEK
  if len(values) < required_points:
    raise ValueError(
        f"Insufficient data points: expected at least {required_points} (14"
        f" days at 5m interval), got {len(values)}"
    )

  # We focus on the last 7 days (latest weekly points) and previous 7 days
  # (weekly points before that)
  last_7_days = values[-_POINTS_PER_WEEK:]
  prev_7_days = values[-required_points:-_POINTS_PER_WEEK]

  # 1. Zero Ratio: proportion of 5m intervals with rate <= 0.01 in the last
  # 7 days
  zero_ratio = sum(x <= 0.01 for x in last_7_days) / _POINTS_PER_WEEK

  # 2. Mean and Standard Deviation of the last 7 days
  mean_last = statistics.mean(last_7_days)
  stddev_last = statistics.pstdev(last_7_days)

  variance_ratio = stddev_last / mean_last if mean_last > 0.0001 else 0.0

  # 3. Autocorrelation at 1-week lag
  mean_prev = statistics.mean(prev_7_days)
  stddev_prev = statistics.pstdev(prev_7_days)

  if stddev_last > 0.0001 and stddev_prev > 0.0001:
    covariance = (
        sum(
            (x - mean_last) * (y - mean_prev)
            for x, y in zip(last_7_days, prev_7_days)
        )
        / _POINTS_PER_WEEK
    )
    autocorr_1w = covariance / (stddev_last * stddev_prev)
  else:
    autocorr_1w = 0.0

  # Decision tree classification
  if mean_last == 0.0 and zero_ratio == 1.0:
    profile = "New Agent / No Traffic"
    algorithm = "Short-Window Z-Score (1h baseline)"
    rationale = (
        "No historical traffic observed. Defaulting to Short-Window Z-Score"
        " (1h baseline) dynamic thresholding to ensure quick activation"
        " (requires 1 hour of traffic history)."
    )
  elif variance_ratio > 2.0:
    profile = "Bursty / Inconsistent"
    algorithm = "Moving Averages"
    rationale = (
        f"Variance ratio is high ({variance_ratio:.2f}), indicating volatile"
        " bursty peaks. Moving averages dynamic baseline thresholds are"
        " recommended to smooth out short-term fluctuations and prevent false"
        " pages."
    )
  elif autocorr_1w > 0.75 and variance_ratio <= 2.0:
    profile = "Seasonal / Cyclical"
    algorithm = "Seasonal Decomposition (average 1w and 1d)"
    rationale = (
        f"Auto-correlation at 1w lag is high ({autocorr_1w:.2f}) with stable"
        f" variance ratio ({variance_ratio:.2f}). Comparing against the average"
        " of 1w and 1d offsets mitigates holiday false positives and prevents"
        " diurnal false alerts during off-peak periods."
    )
  else:
    profile = "Steady / Consistent"
    algorithm = "1w Z-Score Baseline"
    rationale = (
        "Stable regular traffic pattern with low variance ratio"
        f" ({variance_ratio:.2f}) and moderate/low autocorrelation"
        f" ({autocorr_1w:.2f}). 1w Z-Score baseline is ideal."
    )

  return {
      "zero_ratio": round(zero_ratio, 4),
      "variance_ratio": round(variance_ratio, 4),
      "autocorr_1w": round(autocorr_1w, 4),
      "mean": round(mean_last, 4),
      "stddev": round(stddev_last, 4),
      "profile": profile,
      "recommended_algorithm": algorithm,
      "rationale": rationale,
  }


def align_to_grid(
    points: list[tuple[float, float]],
    end_time: float,
    num_points: int = 4032,
    interval_sec: int = 300,
) -> list[float]:
  """Aligns sparse telemetry points to a uniform time grid of fixed size.

  We anchor the grid at end_time aligned to interval_sec and look backward.

  Args:
      points: A list of tuples (timestamp, value).
      end_time: The end timestamp of the grid window.
      num_points: The exact number of points in the target grid.
      interval_sec: The grid interval in seconds.

  Returns:
      A list of floats representing the aligned values in order of time.
  """
  aligned_end = math.floor(end_time / interval_sec) * interval_sec
  aligned_start = aligned_end - num_points * interval_sec

  grid = [0.0] * num_points

  for ts, val in points:
    rounded_ts = round(ts / interval_sec) * interval_sec
    idx = int((rounded_ts - aligned_start) / interval_sec) - 1
    if 0 <= idx < num_points:
      grid[idx] += val

  return grid


def query_live_metrics(
    project_id: str,
    metric_type: str,
    engine_id: str,
) -> list[float]:
  """Queries live metrics (e.g., OTel latency or token usage) for 14 days.

  Args:
      project_id: The GCP project ID.
      metric_type: The metric type to query.
      engine_id: The agent identifier value.

  Returns:
      A list of 4032 floats representing the 5m rate telemetry aligned to grid.

  Raises:
      CredentialsMissingError: If GCP credentials are not found.
  """
  if monitoring_v3 is None or auth_exceptions is None:
    raise CredentialsMissingError(
        "No valid Google Cloud credentials or monitoring client found. Please"
        " run 'gcloud auth application-default login' to authenticate your"
        " local environment."
    )
  try:
    client = monitoring_v3.MetricServiceClient()
    name = f"projects/{project_id}"

    now = time.time()
    seconds_per_day = 24 * 3600
    start_time = now - 14 * seconds_per_day

    interval = monitoring_v3.TimeInterval({
        "end_time": {"seconds": int(now)},
        "start_time": {"seconds": int(start_time)},
    })

    filter_str = (
        f'metric.type = "{metric_type}" AND'
        f" {_SUPPORTED_METRIC_TYPE_LABEL[metric_type]} ="
        f' "{engine_id}"'
    )
    for metric_filter in _SUPPORTED_METRIC_TYPE_FILTERS[metric_type]:
      filter_str += f" AND {metric_filter}"

    results = client.list_time_series(
        request={
            "name": name,
            "filter": filter_str,
            "interval": interval,
            "view": monitoring_v3.ListTimeSeriesRequest.TimeSeriesView.FULL,
            "aggregation": {
                "alignment_period": {"seconds": 300},
                "per_series_aligner": _SUPPORTED_METRIC_TYPE_ALIGNER[
                    metric_type
                ],
                "cross_series_reducer": (
                    monitoring_v3.Aggregation.Reducer.REDUCE_SUM
                ),
                "group_by_fields": [
                    _SUPPORTED_METRIC_TYPE_LABEL[metric_type]
                ],
            },
        }
    )
  except auth_exceptions.DefaultCredentialsError as e:
    raise CredentialsMissingError(
        "No valid Google Cloud credentials found. Please run 'gcloud auth"
        " application-default login' to authenticate your local environment."
    ) from e

  points = []
  for series in results:
    for point in series.points:
      st = point.interval.start_time
      ts = (
          st.timestamp()
          if hasattr(st, "timestamp")
          else st.ToDatetime().timestamp()
      )
      pb = getattr(point.value, "_pb", point.value)
      val_type = pb.WhichOneof("value")
      if val_type == "distribution_value":
        # Calculate total tokens consumed across all buckets in the interval
        val = float(
            point.value.distribution_value.mean
            * point.value.distribution_value.count
        )
      elif val_type == "int64_value":
        val = float(point.value.int64_value)
      else:
        val = float(point.value.double_value)
      points.append((
          ts,
          val,
      ))

  if not points:
    # No traffic detected at all. Return a 14-day grid filled with 0.0.
    return [0.0] * (2 * _POINTS_PER_WEEK)

  # Align sparse points to the 14-day 5-minute grid
  return align_to_grid(points, now, num_points=2 * _POINTS_PER_WEEK)


def main():
  parser = argparse.ArgumentParser(
      description=(
          "Analyze 14-day traffic metrics to select dynamic thresholding"
          " algorithm."
      )
  )
  parser.add_argument(
      "--metric-type",
      required=True,
      type=str,
      help="The metric type to query.",
  )
  parser.add_argument(
      "--metrics-file",
      type=str,
      help="Path to JSON file containing list of numbers. Use '-' for stdin.",
  )
  parser.add_argument(
      "--live",
      action="store_true",
      help="Force live GCP metrics query validation check.",
  )
  parser.add_argument(
      "--project-id",
      type=str,
      help="GCP project ID (required for live queries).",
  )
  parser.add_argument(
      "--reasoning-engine-id",
      type=str,
      help=(
          "Agent Identifier (e.g., gen_ai_agent_name or namespace) "
          "required for live queries."
      ),
  )
  args = parser.parse_args()

  data = None

  if args.metric_type not in _SUPPORTED_METRIC_TYPE_LABEL:
    print(
        f"Error: Metric type {args.metric_type} is not supported.",
        file=sys.stderr,
    )
    sys.exit(1)

  if args.live:
    if not args.project_id or not args.reasoning_engine_id:
      print(
          "Error: Live GCP queries require --project-id and"
          " --reasoning-engine-id to be specified.",
          file=sys.stderr,
      )
      sys.exit(1)

    try:
      data = query_live_metrics(
          args.project_id, args.metric_type, args.reasoning_engine_id
      )
    except CredentialsMissingError as e:
      print(f"Error: {e}", file=sys.stderr)
      sys.exit(1)
    except Exception as e:
      print(f"Error executing live query: {e}", file=sys.stderr)
      sys.exit(1)

  else:
    # File/Stdin input mode
    if not args.metrics_file and sys.stdin.isatty():
      print(
          "Error: Must specify --metrics-file or pipe metrics data to stdin"
          " when not using --live.",
          file=sys.stderr,
      )
      sys.exit(1)

    try:
      if args.metrics_file == "-" or not args.metrics_file:
        data = json.load(sys.stdin)
      else:
        with open(args.metrics_file, "r") as f:
          data = json.load(f)
    except Exception as e:
      print(f"Error reading metrics data: {e}", file=sys.stderr)
      sys.exit(1)

  if not data or not isinstance(data, list):
    print(
        "Error: Metrics data must be a JSON list of numbers or parsed"
        " successfully from a source",
        file=sys.stderr,
    )
    sys.exit(1)

  try:
    results = compute_metrics_and_classify(data)
    print(json.dumps(results, indent=2))
  except ValueError as e:
    print(f"Error: {e}", file=sys.stderr)
    sys.exit(1)


if __name__ == "__main__":
  main()

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Python

Security

What our scanner noticed· Low risk

  • Scripts that your agent may run

This skill includes scripts that your agent may run. Read them before you use it.

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
Google
Publisher
Google (Official)
Source
google/skills · skills/cloud/cloud-monitoring-alert-configuration · commit 2194d3b
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Google or Google.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download cloud-monitoring-alert-configuration.zip