Google Cloud Logging 工具手册
bucket、view 和 sink 不是三个存储层
Google Cloud Logging 接收的是写到项目、文件夹或组织范围的 LogEntry。资源上的 sinks 根据过滤器把新日志路由到 log bucket 或外部目标;log view 再限制调用者能读取 bucket 中的哪部分内容。应用并不是直接把事件写进某个 bucket。
这一区分会直接影响权限。roles/logging.logWriter 允许创建并路由日志条目,view accessor 或 viewer 负责读取,sink 的 writer identity 则要在目标资源上获得写权限。给应用项目级 Editor 既扩大攻击面,也让排障时无法判断真正缺失的是写、读、路由还是目标权限。可从官方 日志 bucket 说明、log view 与 IAM 角色 校准这些边界。
写入一条带所有权的合成日志
先选择一个明确启用结算的测试项目。人机交互可以 gcloud auth login,工作负载应使用附加服务账号或 Workload Identity Federation;不要为了方便下载长期 JSON key。
gcloud auth login
gcloud config set project PROJECT_ID
gcloud auth list
PROJECT_ID=$(gcloud config get-value project)
test -n "$PROJECT_ID" && test "$PROJECT_ID" != "(unset)"
LAB_ID="$(date -u +%Y%m%d%H%M%S)-$RANDOM"
LOG_ID="checkout-dev-$LAB_ID"
TRACE_ID="TE-GCP-$LAB_ID"
gcloud logging write "$LOG_ID" \
"{\"service\":\"checkout\",\"trace_id\":\"$TRACE_ID\",\"message\":\"payment timeout\"}" \
--payload-type=json --severity=ERROR --labels=log_lab_owner="$LAB_ID"
gcloud logging read \
"logName=\"projects/$PROJECT_ID/logs/$LOG_ID\" AND jsonPayload.trace_id=\"$TRACE_ID\" AND labels.log_lab_owner=\"$LAB_ID\"" \
--freshness=1h --limit=20 --format=jsonPROJECT_ID 要替换为真实测试项目。写入成功通常没有业务输出,读取结果应同时包含 jsonPayload、logName、owner label、resource 与时间戳。空结果先检查活动账号、项目、logName URL 编码、freshness、resource scope 和权限。PERMISSION_DENIED 也要区分缺少 logging.logEntries.create 与缺少私有日志读取权限。
固定 TRACE_ID 证明这条事件可查,owner label 则为清理提供额外保护。它们不能替代平台侧的接收量、错误率和路由指标;一次成功写入也无法证明持续采集链可靠。
Ops Agent 要暴露自己的失败
Compute Engine 主机可以使用 Google Cloud Ops Agent,GKE 和托管服务则有各自接入路径。Agent 配置必须明确 receiver、processor 与 pipeline;结构化解析、排除和 multiline 都在发送前改变摄取字节与事件边界。
附加到 Compute Engine 的服务账号只授予 roles/logging.logWriter 后,可以把下面内容写入 /etc/google-cloud-ops-agent/config.yaml:
logging:
receivers:
checkout_json:
type: files
include_paths:
- /var/log/checkout/app.jsonl
record_log_file_path: true
processors:
parse_checkout_json:
type: parse_json
time_key: "@timestamp"
time_format: "%Y-%m-%dT%H:%M:%SZ"
service:
pipelines:
checkout_pipeline:
receivers: [checkout_json]
processors: [parse_checkout_json]sudo systemctl restart google-cloud-ops-agent
sudo systemctl status google-cloud-ops-agent --no-pager
sudo journalctl -u google-cloud-ops-agent --since "10 minutes ago" --no-pager服务状态应为 active (running),但进程存活不等于事件到达。Agent 用户能否读取文件、时间字段能否解析、multiline 是否吞行、API 是否限流,都要从 Agent 自身日志和平台指标判断。开发者查询通常使用 roles/logging.viewer;读取 Data Access 等私有日志需要额外权限。bucket、view 和 sink 管理角色不应授予业务服务账号。
sink 的 writer identity 是独立主体
Cloud Logging 的 sink 可以把新日志路由到另一个 log bucket、Cloud Storage、BigQuery 或 Pub/Sub。创建 sink 后会得到 writer identity,它必须在目标资源上获得最小写权限。来源项目中的应用身份即使能写日志,也不会自动获得目标 bucket 或 topic 权限。
这条路由是面向生效后的新事件,不会自动搬迁历史数据。迁移时应让新旧目标短时间双路接收固定样本,核对 writer identity、过滤器、数量、延迟和目标读取权限,再切消费者。旧 bucket 按原保留策略留存,不能因为新 sink 已创建就提前删除。
目标不可写、Pub/Sub 配额不足或过滤器错误时,路由失败会以平台日志和指标呈现。平台 owner 需要为 sink 错误与落后建立告警。只在目标系统里查“为什么没数据”,通常看不到来源路由的直接证据。
view 承担的是读取隔离
log view 让团队只访问 bucket 中的一部分日志。集中项目接收多个项目日志时,可以按来源、服务或数据级别创建 view,再把 roles/logging.viewAccessor 授给读者。直接在项目层给宽泛 Viewer,可能绕过原本想用 view 表达的最小访问边界。
读取权限与存储位置也不能混为一谈。日志已进入 bucket,不代表当前 principal 能通过指定 view 看见;view 过滤器错误也会产生“平台没有日志”的假象。排障记录应包含 resource scope、bucket location、bucket ID、view ID、查询过滤器与实际 principal。
日志中的 Authorization、Cookie、连接串、完整请求体和个人信息应该在应用或 Agent 侧删除。IAM 只能限制谁看,不能让已经摄取的敏感字段消失;后续删除还可能受保留、复制和下游 sink 影响。
配额与费用要从目标项目读取
Cloud Logging 对 LogEntry 大小、请求大小、区域写入速率、读取调用、bucket、sink 和过滤器都有配额或固定限制。超出区域摄取配额可能返回 RESOURCE_EXHAUSTED。排除过滤发生在写 API 接收之后时,不一定降低写入配额占用,因此“采集后再排除”不能替代源头降噪。
容量评审应打开目标项目的 Quotas 页面,读取真实额度,为突发流量设置采样、限流、有限缓冲和降级。SDK 无限重试会把云端节流转成节点内存或磁盘故障。
费用也不只来自摄取。超过默认保留的存储、Log Analytics、BigQuery/Storage/Pub/Sub 目标、跨区域网络和 sink 下游都会增加成本。大量离线分析不应反复耗尽在线读取 API;如果数据天然需要批量扫描,就提前路由到合适的分析目标,并让这个出口拥有明确预算与 owner。
删除实验日志前重新确认项目
删除一个日志名是破坏性操作。执行前核对当前项目、唯一前缀和本次 owner label;固定业务日志名不能进入这段命令:
test "$(gcloud config get-value project)" = "$PROJECT_ID"
case "$LOG_ID" in checkout-dev-*) ;; *) echo "refuse unexpected log: $LOG_ID" >&2; exit 1;; esac
test "$(gcloud logging read \
"logName=\"projects/$PROJECT_ID/logs/$LOG_ID\" AND labels.log_lab_owner=\"$LAB_ID\"" \
--freshness=1h --limit=1 --format='value(labels.log_lab_owner)')" = "$LAB_ID"
gcloud logging logs delete "$LOG_ID"生产退出应先停止或切换写入与 sink,验证新目标数量和读取权限,再让旧 bucket 按保留期自然退出。删除项目、bucket 或固定日志名都不是普通回滚动作。Cloud Logging 减少了后端集群运维,却没有替团队承担 IAM、地域、过滤、出口、配额和账单责任;这些对象必须在文章、代码与运行记录里保持同一套名称。
