cloud-logging-finops

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Cloud Logging Finops

Cloud Logging Finops

Non-interactive runs. When no user can answer (e.g. a scheduled or automated run), ask nothing: audit the project named in the request, or the active gcloud project; use
--billing-mode=search
; cover all five report topics (Step 2.5); and never enable an API or upgrade a log bucket. Put anything that needed a user (a disabled API, a missing role, the upgrade advisory) in the report instead.
非交互式运行。 当无人能够回答问题时(例如计划任务或自动化运行),不要提出任何问题:审计请求中指定的项目,或当前活动的 gcloud 项目;使用
--billing-mode=search
;涵盖全部五个报告主题(第 2.5 步);并且绝不启用 API 或升级日志桶。将所有需要用户提供信息的事项(API 被禁用、缺少角色、升级提示)写入报告。

Step 0: Locate the Cloud Billing Export

第 0 步:定位 Cloud Billing 导出数据

The audit covers one Google Cloud project,
{project_id}
: the project the user names or, if they don't name one, the active gcloud project (
gcloud config get project
), confirmed with the user.
Discover everything else (log buckets, Observability Analytics, sinks, exclusions, metrics) yourself; never ask the user about those. The billing export is the exception: finding it unaided can mean scanning every project on the billing account, so ask once, before running anything, and don't start a search until the user has chosen answer 3 (single-select, using the host's question tool if it has one):
Do you know where the Cloud Billing export for
{project_id}
is?
  1. Yes — here it is (the BigQuery table ID
    project.dataset.table
    , or just the project and dataset)
  2. There's no billing export for this project
  3. No / not sure — search for it (seconds on a small project; on a large billing account it can take a long time)
AnswerFlagsCost figures
1
--billing-mode=explicit
plus
--billing-table
(or
--billing-project
/
--billing-dataset
)
invoiced
2
--billing-mode=none
list-price estimates
3
--billing-mode=search
(default)
invoiced if found, else estimates
Answer 3's search has no time limit: it checks
{project_id}
first (usually under 10 s, 1–2 min with many tables), then every project on its billing account (can take many minutes; progress prints every 30 s). Tell the user this before launching. If the wait is unacceptable, offer to switch to answer 1 (they look up the table) or answer 2 (skip the export and use list-price estimates). Don't suggest setting up an export to make the search faster.
If the search found an export, tell the user: "Next time, pass
--billing-table=<table>
and discovery drops to about two seconds."
审计涵盖一个 Google Cloud 项目
{project_id}
:即用户指定的项目;如果用户未指定,则使用当前活动的 gcloud 项目(
gcloud config get project
),并向用户确认。
其他所有内容(日志桶、Observability Analytics、sinks、exclusions、metrics)都应自行发现;绝不要就此询问用户。Cloud Billing 导出数据是唯一的例外:自行查找可能需要扫描计费账户中的每个项目,因此在运行任何操作前询问一次,并且在用户选择选项 3 之前不要开始搜索(使用主机的问题工具进行单选,如果该工具可用):
您知道
{project_id}
的 Cloud Billing 导出数据位于哪里吗?
  1. 知道——就在这里 (BigQuery 表 ID
    project.dataset.table
    ,或者只需提供项目和数据集)
  2. 此项目没有 Billing 导出数据
  3. 不知道/不确定——进行搜索 (小型项目通常只需几秒;大型计费账户可能耗时较长)
选项标志成本数据
1
--billing-mode=explicit
加上
--billing-table
(或
--billing-project
/
--billing-dataset
)
已开票金额
2
--billing-mode=none
标价估算
3
--billing-mode=search
(默认)
找到则使用已开票金额,否则使用估算值
选项 3 的搜索没有时间限制:它会先检查
{project_id}
(通常不到 10 秒;存在大量表时需 1–2 分钟),然后检查计费账户中的每个项目(可能需要数分钟;每 30 秒打印一次进度)。启动前告知用户这一点。如果等待时间不可接受,可以建议切换到选项 1(由用户自行查找表)或选项 2(跳过导出数据并使用标价估算)。不要建议为了加快搜索而配置导出数据。
如果搜索找到了导出数据,告诉用户:“下次请传入
--billing-table=<table>
,发现过程大约只需两秒。”

Step 1: Environment Setup

第 1 步:环境设置

Check these prerequisites before Step 2; fix only what is missing:
  • gcloud: if
    gcloud
    is not installed, follow https://docs.cloud.google.com/sdk/docs/install-sdk.md.txt.
  • Project: run
    gcloud config get project
    ; if it isn't
    {project_id}
    (from Step 0), run
    gcloud config set project {project_id}
    .
  • Credentials: the scripts use Application Default Credentials. Run
    gcloud auth application-default login
    , or set
    GOOGLE_APPLICATION_CREDENTIALS
    to a service account key.
  • Billing: the project must have an active billing account attached.
  • APIs: don't enable APIs up front; the Logging, Monitoring, BigQuery and Observability APIs are on by default in new projects. Only if the collector reports an API as disabled (
    SERVICE_DISABLED
    , "has not been used in project"), name it, ask the user, and on approval run
    gcloud services enable {api} --project={project_id}
    (tagged as described below):
    • logging
      ,
      monitoring
      : required; without them there is nothing to audit.
    • bigquery
      : invoiced costs from the billing export.
    • observability
      : resolves the project's default log scope, so log samples match what Logs Explorer shows.
    • cloudasset
      ,
      cloudbilling
      : only answer 3's search across the billing account.
IAM roles for the identity running the audit. The skill never grants roles: the scripts run with the user's own credentials and read only what those credentials can. When a step fails on permissions, its advisory names the step; tell the user which role below it needs:
RoleNeeded for
roles/logging.viewer
,
roles/monitoring.viewer
Every audit: log buckets, sinks, log samples, volume metrics
roles/bigquery.jobUser
,
roles/bigquery.dataViewer
(on the export dataset)
Invoiced costs from the billing export
roles/logging.viewAccessor
on log views in other projects
Reading samples through a default log scope that includes them
roles/cloudasset.viewer
,
roles/billing.viewer
(billing account)
--billing-mode=search
across the billing account
roles/logging.configWriter
Only the optional Observability Analytics upgrade (Step 3B)
bash
[ -f /tmp/finops_venv/bin/python ] || (uv venv /tmp/finops_venv && uv pip install -r scripts/requirements.txt --python /tmp/finops_venv/bin/python)
The bundled scripts tag their Google Cloud API requests. Tag commands you run yourself, inline on each command:
  • gcloud:
    CLOUDSDK_METRICS_ENVIRONMENT="google-skills google-skills/1.0 (skill:cloud-logging-finops)" gcloud ...
  • HTTP:
    curl -H "User-Agent: google-skills/1.0 (skill:cloud-logging-finops)" ...
在第 2 步之前检查以下先决条件;仅修复缺失项:
  • gcloud: 如果未安装 gcloud,请遵循 https://docs.cloud.google.com/sdk/docs/install-sdk.md.txt。
  • 项目: 运行
    gcloud config get project
    ;如果它不是第 0 步中的
    {project_id}
    ,则运行
    gcloud config set project {project_id}
    。
  • 凭据: 脚本使用 Application Default Credentials。运行
    gcloud auth application-default login
    ,或者将
    GOOGLE_APPLICATION_CREDENTIALS
    设置为服务账号密钥。
  • 计费: 项目必须关联有效的计费账户。
  • API: 不要预先启用 API;新项目默认启用 Logging、Monitoring、BigQuery 和 Observability API。仅当收集器报告某个 API 已被禁用(
    SERVICE_DISABLED
    、
    has not been used in project
    )时,列出该 API、询问用户,并在获得批准后运行
    gcloud services enable {api} --project={project_id}
    (按如下方式添加标记):
    • logging
      、
      monitoring
      :必需;没有它们就无法进行审计。
    • bigquery
      :用于从 Billing 导出数据获取已开票成本。
    • observability
      :用于解析项目的默认日志范围,使日志样本与 Logs Explorer 中显示的内容一致。
    • cloudasset
      、
      cloudbilling
      :仅用于选项 3 中跨计费账户的搜索。
运行审计的身份所需的 IAM 角色。该 skill 绝不授予角色:脚本使用用户自己的凭据运行,并且只能读取这些凭据有权访问的内容。当某个步骤因权限不足而失败时,其提示信息会指出相应步骤;告知用户下表中需要使用的角色:
角色用途
roles/logging.viewer
、
roles/monitoring.viewer
每次审计均需要:日志桶、sinks、日志样本、流量指标
roles/bigquery.jobUser
、
roles/bigquery.dataViewer
(授予导出数据集)
从 Billing 导出数据获取已开票成本
roles/logging.viewAccessor
(授予其他项目中的日志视图)
通过包含这些视图的默认日志范围读取样本
roles/cloudasset.viewer
、
roles/billing.viewer
(计费账户)
在
--billing-mode=search
下跨计费账户搜索
roles/logging.configWriter
仅用于可选的 Observability Analytics 升级(第 3B 步)
bash
[ -f /tmp/finops_venv/bin/python ] || (uv venv /tmp/finops_venv && uv pip install -r scripts/requirements.txt --python /tmp/finops_venv/bin/python)
捆绑脚本会为其 Google Cloud API 请求添加标记。自行运行的命令也应内联添加标记:
  • gcloud:
    CLOUDSDK_METRICS_ENVIRONMENT="google-skills google-skills/1.0 (skill:cloud-logging-finops)" gcloud ...
  • HTTP:
    curl -H "User-Agent: google-skills/1.0 (skill:cloud-logging-finops)" ...

Step 2: Data Collection

第 2 步:数据收集

Start the collector below as a background process (it takes from seconds to many minutes), then go to Step 2.5 while it runs:
bash
/tmp/finops_venv/bin/python scripts/collect_logging_data.py \
  --project-id {project_id} --billing-mode={none|explicit|search}
Optional:
--billing-project
,
--billing-dataset
,
--billing-table
(e.g.
billing-proj.ds.gcp_billing_export_v1_XXXX
or a curated FinOps view).
Outputs:
logging_usage_summary.json
,
monthly_details/
,
service_details/
, and
[FINOPS ADVISORY]
lines (see Step 3). The collector's output ends with a
[COLLECTION PROFILE]
table of per-stage timings; if the run took longer than the times in Step 0, or the user asks why the audit took so long, read that table before guessing.
将下面的收集器作为后台进程启动(耗时从数秒到数分钟不等),然后在它运行时进入第 2.5 步:
bash
/tmp/finops_venv/bin/python scripts/collect_logging_data.py \
  --project-id {project_id} --billing-mode={none|explicit|search}
可选参数:
--billing-project
、
--billing-dataset
、
--billing-table
(例如
billing-proj.ds.gcp_billing_export_v1_XXXX
或经过整理的 FinOps 视图)。
输出:
logging_usage_summary.json
、
monthly_details/
、
service_details/
,以及
[FINOPS ADVISORY]
行(参见第 3 步)。收集器的输出末尾包含一个
[COLLECTION PROFILE]
表,其中记录各阶段的耗时;如果运行时间超过第 0 步所述时间,或用户询问审计为何耗时如此之长,应先读取该表,而不要猜测。

Step 2.5: Ask What the Report Is For

第 2.5 步:询问报告用途

Always ask this while the collector runs (multi-select). If the user skips it, cover all five topics:
What should this report answer?
  • Where is the money going — attribution by service and stream
  • Is spend growing — trends and projection
  • What can I safely turn off — concrete savings actions
  • What are these logs actually saying — noisiest patterns and samples
  • Severity and audit-log posture
The user's choices decide which outputs you read in depth and what your summary leads with; they never change what the collector gathers:
InterestRead deeply
Attribution
service_details/*.json
,
daily_services
Growth
monthly_details/*.json
,
mom_patterns
,
cost_projection
Savings actions
reduction_actions
,
extraneous_spend
What logs say
severity_summary.samples_by_service
,
granular_analytics.top_signatures
(Observability Analytics only)
Severity / audit
severity_summary
, withheld-rule reasons
Your narrative goes in
insights/executive_summary.html
(see Executive Summary Authoring). You don't write the savings actions: the generated report's Cost Optimizer tab lists them from
reduction_actions
.
[!CAUTION] Never edit
assets/report_template.html
.
收集器运行期间始终询问此问题(多选)。如果用户跳过,则涵盖全部五个主题:
这份报告需要回答哪些问题?
  • 钱花在哪里——按服务和日志流归因
  • 支出是否在增长——趋势与预测
  • 可以安全关闭什么——具体的节省措施
  • 这些日志实际在说什么——最嘈杂的模式与样本
  • 严重性级别与审计日志态势
用户的选择决定深入读取哪些输出,以及摘要重点介绍什么;但不会改变收集器收集的数据:
关注点深入读取
归因
service_details/*.json
、
daily_services
增长
monthly_details/*.json
、
mom_patterns
、
cost_projection
节省措施
reduction_actions
、
extraneous_spend
日志内容
severity_summary.samples_by_service
、
granular_analytics.top_signatures
(仅 Observability Analytics)
严重性级别/审计
severity_summary
、withheld 规则原因
叙述内容写入
insights/executive_summary.html
(参见 Executive Summary Authoring)。不要自行编写节省措施:生成报告的 Cost Optimizer 标签页会列出
reduction_actions
中的节省措施。
[!CAUTION] 绝不编辑
assets/report_template.html
。

Step 3: Follow the Advisories

第 3 步:处理提示信息

A. Tell the User What the Cost Figures Are Based On

A. 告知用户成本数据依据

[!IMPORTANT] Unless figures are invoiced (
billing_metadata.invoiced
), tell the user in plain language where you looked, what you found, and what the numbers are based on. Keep internals (stage numbers, mode names, HTTP codes, "quota project", "Cloud Asset Inventory") in the log and
billing_metadata.fallback_chain
.
  • Answer 1, the location gave no costs (
    explicit_table
    or
    explicit_scope
    step not
    found
    ): the collector never searches beyond what the user named. Tell them what was wrong, from the step's
    detail
    (no rows for this project, no export table there, or the query failed), that costs are list-price estimates, and offer to rerun with a corrected location or with answer 3.
  • Answer 2 (
    user_declared_no_export
    ): "I didn't search — you told me there's no billing export — so costs are list-price estimates, not invoiced amounts." Never call a skipped search exhausted.
  • Answer 3, found nothing (
    billing_account
    status
    not_found
    ): "I searched this project and your billing account and found no billing export. Costs are list-price estimates (quote each SKU's price and free tier from
    pricing.skus
    ) over a trailing 30 days." Only this case supports recommending export setup. Cite the official pricing page (https://cloud.google.com/products/observability/pricing) as the source of list prices.
  • Answer 3, search failed on permissions (any step status
    inconclusive
    ): tell the user the lookup couldn't complete, so costs are estimates. Never tell them no billing export exists; the search didn't finish.
  • Answer 3, this project's table rejected (
    local_project
    status
    no_project_records
    ): "This project has a billing export, but it holds no records for this project, so I searched the rest of the billing account." Then report the outcome of that wider search as above.
  • Partial history: months are labelled
    actual_bq_billing
    or
    usage_estimated
    ; state the exact date boundary in the executive summary.
When on list pricing, recommend export for accuracy: future audits would use the actual invoice, including discounts, over multiple months.
[!IMPORTANT] 除非数据为已开票金额(
billing_metadata.invoiced
),否则应以通俗语言告知用户数据从哪里查到了什么,以及这些数字的依据是什么。内部信息(阶段编号、模式名称、HTTP 状态码、
quota project
、
Cloud Asset Inventory
)应仅保留在日志和
billing_metadata.fallback_chain
中。
  • 选项 1,所提供的位置没有成本数据(
    explicit_table
    或
    explicit_scope
    步骤的状态不是
    found
    ):收集器不会搜索用户指定范围之外的内容。根据该步骤的
    detail
    告知用户出了什么问题(此项目没有数据行、指定位置没有导出表,或者查询失败),说明成本采用标价估算,并建议使用修正后的位置或选项 3 重新运行。
  • 选项 2(
    user_declared_no_export
    ):“我没有进行搜索——您告诉我此项目没有 Billing 导出数据——因此成本采用标价估算,而不是已开票金额。”绝不把跳过的搜索描述为已经穷尽搜索。
  • 选项 3,未找到任何内容(
    billing_account
    状态为
    not_found
    ):“我搜索了这个项目和您的计费账户,没有找到 Billing 导出数据。成本采用标价估算(来自
    pricing.skus
    中每个 SKU 的价格和免费额度),统计范围为过去 30 天。”只有这种情况才建议配置导出数据。引用官方定价页面(https://cloud.google.com/products/observability/pricing)作为标价价格的来源。
  • 选项 3,因权限不足导致搜索失败(任一步骤状态为
    inconclusive
    ):告知用户查找无法完成,因此成本数据属于估算值。绝不能断言不存在 Billing 导出数据;搜索并未完成。
  • 选项 3,此项目的表被拒绝(
    local_project
    状态为
    no_project_records
    ):“此项目存在 Billing 导出数据,但其中没有此项目的记录,因此我搜索了计费账户中的其他项目。”然后按照上述方式报告更大范围搜索的结果。
  • 历史数据不完整: 月份会标记为
    actual_bq_billing
    或
    usage_estimated
    ;在执行摘要中明确说明准确的日期边界。
使用标价时,建议配置导出数据以提高准确性:未来的审计将使用包含折扣且涵盖多个月的实际账单金额。

B. Observability Analytics

B. Observability Analytics

Observability Analytics was formerly called Log Analytics; the scripts' advisories and field names still use the old name.
  • Disabled: present the advisory, including that upgrading the log bucket is irreversible, then end your reply with a direct question, e.g. "Do you want me to upgrade the
    _Default
    log bucket to Observability Analytics? This can't be undone."
    Telling the user how to run it themselves is not asking. Only after they approve upgrading that log bucket, run
    /tmp/finops_venv/bin/python scripts/enable_log_analytics.py --project-id {project_id}
    . The audit proceeds on Cloud Monitoring either way.
[!CAUTION] Never run
enable_log_analytics.py
or
gcloud logging buckets update --enable-analytics
in the same turn you raise the advisory, or on general permission like "do whatever you need".
  • < 24 hours old: the 14-day Cloud Monitoring baseline is used until samples accumulate (~1–2 hours).
  • 1–13 days: cite the sample window in the report.
  • ≥ 14 days: full SQL analytics.
  • Representative logs unavailable
    advisory:
    samples are missing because your environment can't read log entries (needs
    roles/logging.viewer
    ), not because streams are empty. Relay the error and role; per-stream detail is in
    severity_summary.sample_errors
    .
  • Samples empty but the stream has volume: samples are read through the project's default log scope, like Logs Explorer (
    analytics_metadata.log_read_scope
    ). If its
    source
    is
    project
    and it has a
    note
    , the scope couldn't be resolved, so logs held outside this project's log buckets weren't read. Say that and relay the
    note
    ; never say the stream has no logs.
Observability Analytics 以前称为 Log Analytics;脚本的提示信息和字段名称仍使用旧名称。
  • 已禁用: 展示提示信息,包括升级日志桶不可撤销这一事实,然后在回复末尾提出一个直接问题,例如:“您要将
    _Default
    日志桶升级为 Observability Analytics 吗?此操作无法撤销。”
    仅告诉用户如何自行运行并不等同于询问。只有在用户明确批准升级该日志桶后,才运行
    /tmp/finops_venv/bin/python scripts/enable_log_analytics.py --project-id {project_id}
    。无论是否升级,审计都会继续使用 Cloud Monitoring。
[!CAUTION] 在提出提示信息的同一轮中,绝不要运行
enable_log_analytics.py
或
gcloud logging buckets update --enable-analytics
;也不要依据“做任何必要操作”之类的笼统授权执行这些操作。
  • 启用时间不足 24 小时: 在样本累积之前(约 1–2 小时),使用 14 天的 Cloud Monitoring 基线。
  • 启用时间为 1–13 天: 在报告中注明样本窗口。
  • 启用时间至少为 14 天: 使用完整的 SQL 分析。
  • Representative logs unavailable
    提示:
    样本缺失是因为当前环境无法读取日志条目(需要
    roles/logging.viewer
    ),而不是因为日志流为空。转述错误和所需角色;每个日志流的详细信息位于
    severity_summary.sample_errors
    。
  • 样本为空但日志流存在流量: 样本是通过项目的默认日志范围读取的,与 Logs Explorer 相同(
    analytics_metadata.log_read_scope
    )。如果其
    source
    为
    project
    且包含
    note
    ,说明无法解析日志范围,因此没有读取此项目日志桶之外保存的日志。告知用户这一点并转述
    note
    ;绝不要说该日志流没有日志。

C. Measurement Integrity

C. 计量完整性

[!CAUTION] Never quote cost or volume derived from Observability Analytics payload byte sums; they overstate billed volume about 2x.
QuestionSource
Cost, GiB ingestedBilling export (
billing.query_logging_billing_costs
,
daily_gib
,
monthly_costs
)
Service mix
logging.googleapis.com/billing/bytes_ingested
(
resource_type
)
Log stream / severity volume
logging.googleapis.com/byte_count
(
log
,
severity
)
Severity mix, entry contentObservability Analytics SQL (
constants.PAYLOAD_BYTES_SQL
)
  • Totals come from the invoice when it exists; metrics only supply shares. Never put a metric-derived total next to an invoiced one.
  • byte_count
    (received) and
    billing/bytes_ingested
    (billed) differ by ~1.5x or more; never divide one by the other.
  • If
    telemetry_integrity.status
    is
    degraded
    , say dips on the listed days look like a metric defect that won't self-correct, and repeat the limits in
    telemetry_integrity.note
    . Never claim with certainty that nothing changed.
  • A month with
    is_partial: true
    is month-to-date. Label it so, and never call it a complete month or "last month".
[!CAUTION] 绝不引用由 Observability Analytics 有效载荷字节总和计算出的成本或流量;这些数值会将计费流量高估约 2 倍。
项目数据来源
成本、已摄入 GiBBilling 导出数据(
billing.query_logging_billing_costs
、
daily_gib
、
monthly_costs
)
服务构成
logging.googleapis.com/billing/bytes_ingested
(
resource_type
)
日志流/严重性级别流量
logging.googleapis.com/byte_count
(
log
、
severity
)
严重性级别构成、条目内容Observability Analytics SQL(
constants.PAYLOAD_BYTES_SQL
)
  • 存在账单时,总量来自账单;指标只用于提供占比。绝不把基于指标计算出的总量与已开票总量并列展示。
  • byte_count
    (接收量)与
    billing/bytes_ingested
    (计费量)相差约 1.5 倍或更多;绝不要用其中一个除以另一个。
  • 如果
    telemetry_integrity.status
    为
    degraded
    ,说明所列日期上的下降看起来像是不会自行恢复的指标缺陷,并重复说明
    telemetry_integrity.note
    中的限制。绝不能确定地声称什么都没有发生变化。
  • 标记为
    is_partial: true
    的月份是本月截至当前的数据。必须明确标注,绝不能称其为完整月份或“上月”。

D. Extraneous Spend

D. 非必要支出

extraneous_spend.headline
is a conservative floor: the sum of the
reduction_actions.actions
with
counted: true
(duplicate bucket routing, flow-log sampling, DEBUG logs, stale exclusions), each priced on exactly what its remedy removes. Everything else is surfaced, never counted: over-retention (not quantified), sampled exclusion rules (estimates), and Data Access audit logs (in
withheld
).
  1. Report it as a floor (
    ≥ X%
    ), never a point estimate or "up to".
  2. If
    status
    is
    insufficient_data
    , give no figure — not a guess, a benchmark, or $0.
  3. Quote any action's
    flag
    verbatim; it is written for the reader.
  4. Uncounted actions and
    uncounted_total_pct
    may be mentioned as upside, never added to the headline.
  5. If
    headline.exceeds_sanity_ceiling
    , say the headline isn't reliable, name the largest counted action, and flag it for manual review. Offer no number.
  6. If
    inventory_unavailable
    is non-empty, say log sink, exclusion and flow-log actions weren't checked; never say none exist.
  7. Whenever Data Access audit logs come up (a
    withheld
    entry, or the user names them), say they are left out of the number because they need a compliance decision: disabling or excluding them is frequently prohibited by compliance or security policy, so the owner must confirm before acting.
extraneous_spend.headline
是一个保守下限:它将
reduction_actions.actions
中所有
counted: true
的措施相加(重复的日志桶路由、flow-log 采样、DEBUG 日志、失效的排除规则),并且每项都严格按其修复措施所移除的量计价。其他内容只会被披露,绝不计入:超期保留(未量化)、采样的排除规则(估算值),以及 Data Access 审计日志(位于
withheld
中)。
  1. 将其报告为下限(
    ≥ X%
    ),绝不能报告为点估计或“最高可达”。
  2. 如果
    status
    为
    insufficient_data
    ,不要给出任何数值——不要猜测、使用基准值或报告为 $0。
  3. 原样引用任何措施的
    flag
    ;这些内容是专门写给读者看的。
  4. 可以将未计入的措施和
    uncounted_total_pct
    作为额外收益提及,但绝不能将其加入 headline。
  5. 如果
    headline.exceeds_sanity_ceiling
    ,说明 headline 不可靠,指出计入金额最大的措施,并将其标记为需要人工审查。不要提供任何数值。
  6. 如果
    inventory_unavailable
    非空,说明未检查 log sink、exclusion 和 flow-log 措施;绝不能声称不存在这些措施。
  7. 每当涉及 Data Access 审计日志(出现
    withheld
    条目,或用户提及这些日志)时,说明它们未计入该数值,因为是否禁用或排除它们需要作出合规决定;合规或安全策略通常会禁止此类操作,因此必须由负责人确认后才能执行。

E. Exclusion Filters and Actions

E. 排除过滤器与措施

  • Only Cost Optimizer actions carry filters and savings; Service Details volumes are not savings. Report
    sample_coverage.shown_pct
    .
  • Quote an action's monthly figures (
    monthly_gib
    ,
    monthly_usd
    ), never a rule's sample-window GiB (
    granular_analytics.exclusion_candidates
    ).
  • rule_scope: stream
    drops every log entry of that severity in the stream; say so.
  • If
    refused_claims
    is non-empty, name the streams the safety gate removed.
Never offered as actions:
CRITICAL
/
ALERT
/
EMERGENCY
(incident signal), free
_Required
streams ($0, audit retention), Data Access audit logs (often compliance-mandated; report, never count), and streams with no measured volume.
[!CAUTION] Hand-written exclusion filters must: include a severity predicate (
severity = "DEFAULT"
for DEFAULT — omitting it matches everything); use the URL-encoded log ID (
compute.googleapis.com%2Ffirewall
); never embed unescaped log text or rotating tokens (UUIDs, IPs, long integers, times) in a regex; and respect the list above.
  • 只有 Cost Optimizer 中的措施会附带过滤器和节省金额;Service Details 中的流量不是节省金额。报告
    sample_coverage.shown_pct
    。
  • 引用措施的月度数据(
    monthly_gib
    、
    monthly_usd
    ),绝不能引用规则的样本窗口 GiB(
    granular_analytics.exclusion_candidates
    )。
  • rule_scope: stream
    会丢弃该日志流中具有指定严重性级别的所有日志条目;必须明确说明这一点。
  • 如果
    refused_claims
    非空,指出安全门禁移除了哪些日志流。
绝不作为措施提供:
CRITICAL
/
ALERT
/
EMERGENCY
(事件信号)、免费的
_Required
日志流($0,审计保留)、Data Access 审计日志(通常由合规要求强制保留;只报告,绝不计入),以及没有测得流量的日志流。
[!CAUTION] 手写排除过滤器必须:包含严重性级别谓词(DEFAULT 使用
severity = "DEFAULT"
——省略它会匹配全部内容);使用 URL 编码的日志 ID(
compute.googleapis.com%2Ffirewall
);绝不要在正则表达式中嵌入未转义的日志文本或轮换令牌(UUID、IP、长整数、时间);并遵守上述列表。

Step 4: Build and Deliver the Report

第 4 步:构建并交付报告

bash
/tmp/finops_venv/bin/python scripts/build_report.py --summary logging_usage_summary.json --insights-dir insights/ --output log_usage_report.html
build_report.py
writes an executive summary unless you provide
insights/executive_summary.html
.
Give the user one link that, when clicked, opens the fully rendered report — not raw HTML, not a missing file — from wherever the user actually is. Confirm that will happen before you post it.
Then list what they can explore (charts, service drilldowns, ranked actions with copyable filters, ✓ Prove It drawers) and suggest 3–4 follow-up questions drawn from this project's data, phrased to ask as-is.
If the user asked something specific, answer it directly with both GiB and USD, from
monthly_aggregations
(
latest_complete_month
names the newest whole month; each month's
top_service
is its Top Cost Driver),
mom_patterns
,
cost_projection
,
trailing_30d_summary
(its
top_driver
is the report's Top Cost Driver without an invoice),
granular_analytics
(present only when Observability Analytics ran), or the per-service/month detail files.
bash
/tmp/finops_venv/bin/python scripts/build_report.py --summary logging_usage_summary.json --insights-dir insights/ --output log_usage_report.html
除非提供
insights/executive_summary.html
,否则
build_report.py
会写入执行摘要。
向用户提供一个链接;点击后应从用户当前所在的位置打开完整渲染的报告——而不是原始 HTML,也不是缺失文件。发布链接前先确认它能够正常打开。
然后列出用户可以探索的内容(图表、服务明细、带有可复制过滤器的排名措施、✓ Prove It 抽屉),并根据此项目的数据提出 3–4 个可直接询问的后续问题。
如果用户询问了具体问题,请直接使用
monthly_aggregations
(
latest_complete_month
表示最新的完整月份;每个月的
top_service
是其 Top Cost Driver)、
mom_patterns
、
cost_projection
、
trailing_30d_summary
(在没有账单时,其
top_driver
是报告的 Top Cost Driver)、
granular_analytics
(仅在运行 Observability Analytics 时存在)或各服务/月度明细文件,直接回答问题,并同时提供 GiB 和 USD。

Step 5: Follow-Up Questions

第 5 步:后续问题

Phase 1 (default): answer from the JSON on disk in a few sentences or a small table, name what the data can't settle, then stop and offer 3–4 ways to go deeper. Don't re-run collection or re-query sources.
Question aboutRead
A severity
severity_summary
,
granular_analytics.top_signatures
for that severity
A service
service_details/{service}.json
,
top_signatures
and
top_log_names
for it
An optimization actionits entry in
reduction_actions.actions
(
claims
,
refused_claims
,
flag
,
counted
)
Phase 2 (only after the user picks a direction): go as deep as it needs. Run Observability Analytics SQL against
analytics_metadata.table_name
, the
_AllLogs
view the collector measured. Step 3 still applies.
第 1 阶段(默认): 根据磁盘上的 JSON,用几句话或一个小表格回答;指出数据无法确定的事项,然后停止并提供 3–4 个进一步探索的方向。不要重新运行收集器或重新查询数据源。
问题类型读取内容
特定严重性级别该严重性级别对应的
severity_summary
、
granular_analytics.top_signatures
特定服务该服务对应的
service_details/{service}.json
、
top_signatures
和
top_log_names
特定优化措施
reduction_actions.actions
中的对应条目(
claims
、
refused_claims
、
flag
、
counted
)
第 2 阶段(仅在用户选择方向后): 根据需要深入分析。针对
analytics_metadata.table_name
(收集器测量过的
_AllLogs
视图)运行 Observability Analytics SQL。第 3 步仍然适用。

Step 6: Prove It

第 6 步:Prove It

provenance.claims[<id>]
records each headline figure's
formula
,
sources
(exact query, Google Cloud console link, steps; only the 10 largest streams per action), known
differences
from the console, and runnable
checks
(covering every stream). Ids include
latest_complete_spend
,
mtd_run_rate
,
trailing_30d_volume
,
estimated_run_rate
,
top_cost_driver
,
extraneous_spend
,
severity_costs
,
service_mix
,
action::<action id>
. A claim built from others lists them in
see_also
(
extraneous_spend
→ its counted actions); prove those too, and
verify_claim.py
re-checks them with it.
When asked to prove a figure:
  1. Now, from disk: walk the formula with its inputs; list each source with its Google Cloud console link, its query exactly as recorded, and steps; then the
    differences
    .
  2. Same turn, in the background: run
    /tmp/finops_venv/bin/python scripts/verify_claim.py --summary <summary> --claim "<id>"
    ; don't wait.
  3. When it finishes: a table (check | report | live | Δ | ✓/△/✗) and a one-line verdict. Explain △ with the recorded
    differences
    ; give ✗ causes in one line each.
[!CAUTION] Prove It is the only request that may re-query sources, and only via
verify_claim.py
. Don't re-run collection or alter the recorded queries.
Disclose when relevant: whether the claim was priced (
pricing.mode
)
per_sku
(each SKU's price and free tier in
pricing.skus
) or
blended
(reason in
pricing.notes
); that service and severity figures exclude credits; and, if
cross_project_billing
, that reproducing it needs
roles/bigquery.dataViewer
on the billing export dataset and
roles/bigquery.jobUser
.
provenance.claims[<id>]
记录每个 headline 数字的
formula
、
sources
(精确查询、Google Cloud Console 链接、执行步骤;每项措施仅包含最大的 10 个日志流)、与 Console 之间的已知
differences
,以及可运行的
checks
(覆盖每个日志流)。ID 包括
latest_complete_spend
、
mtd_run_rate
、
trailing_30d_volume
、
estimated_run_rate
、
top_cost_driver
、
extraneous_spend
、
severity_costs
、
service_mix
、
action::<action id>
。由其他数字构建的 claim 会在
see_also
中列出它们(
extraneous_spend
→ 其计入的措施);也要对这些 claim 进行验证,并由
verify_claim.py
一并重新检查。
当用户要求证明某个数字时:
  1. 立即从磁盘核对: 按公式逐步检查其输入;列出每个来源及其 Google Cloud Console 链接、原样记录的查询和执行步骤;然后列出
    differences
    。
  2. 在同一轮中后台运行: 运行
    /tmp/finops_venv/bin/python scripts/verify_claim.py --summary <summary> --claim "<id>"
    ;不要等待。
  3. 完成后: 输出一个表格(检查 | 报告 | 实时 | Δ | ✓/△/✗)和一行结论。使用记录的
    differences
    解释 △;✗ 的每项原因用一行说明。
[!CAUTION] Prove It 是唯一可以重新查询数据源的请求,并且只能通过
verify_claim.py
进行。不要重新运行收集器,也不要修改已记录的查询。
在相关情况下披露:claim 的计价方式(
pricing.mode
)是
per_sku
(
pricing.skus
中每个 SKU 的价格和免费额度)还是
blended
(原因见
pricing.notes
);服务与严重性级别数字不包含 credits;以及如果存在
cross_project_billing
,复现该结果需要在 Billing 导出数据集上授予
roles/bigquery.dataViewer
,并授予
roles/bigquery.jobUser
。