|
|
排查 gstack 问题靠什么?日志。说白了,日志就是你在 GCP 上跑 AI Agent 时的“黑匣子”。
gstack 这东西跟本地 CLI 工具不太一样,日志链路要经过三层:gstack CLI 本地运行产生的日志、Google Cloud Vertex AI 的调用记录、还有 Cloud Logging 上的聚合日志。今天这篇主要聊官方工具链的日志配置和查看方法,pip 安装版、gcloud CLI 集成版、Python SDK 调用三种场景全覆盖,命令直接复制就能用。
---
## 一、gstack CLI 日志基础
gstack 在 PyPI 分发的 CLI 工具基于 Python `logging` 标准库构建,源码结构挺干净的。装完之后,日志默认往 `~/.gstack/logs/` 目录里写,文件名格式是 `gstack-{timestamp}.log`。
日志级别由环境变量 `GSTACK_LOG_LEVEL` 控制,支持 `DEBUG`、`INFO`、`WARNING`、`ERROR` 四档,默认是 `INFO`。
### 安装与快速验证
```bash
pip install gstack
gstack --version
```
跑一遍,日志目录会自动创建。验证一下日志文件有没有生成:
```bash
ls -la ~/.gstack/logs/
```
### 配置方式一:环境变量
```bash
export GSTACK_LOG_LEVEL=DEBUG
export GSTACK_LOG_FILE=~/.gstack/logs/debug.log
gstack --version
```
环境变量优先级高于配置文件,临时调试开这个最方便。
### 配置方式二:配置文件
在 `~/.gstack/config.yaml` 里写:
```yaml
logging:
level: DEBUG
file: ~/.gstack/logs/gstack.log
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
max_bytes: 10485760 # 10MB 轮转
backup_count: 5
```
`max_bytes` 和 `backup_count` 控制日志轮转,长期跑脚本的话这两个参数一定要配,不然磁盘早晚会爆。
### 日志格式拆解
一条典型的 gstack 日志长这样:
```
2024-03-15 10:23:45,123 - gstack.cli - INFO - Request to gemini-1.5-pro completed in 1.234s
```
字段含义:
| 字段 | 含义 |
|------|------|
| `asctime` | 时间戳,精确到毫秒 |
| `name` | Logger 名称,`gstack.cli` 或 `gstack.sdk` |
| `levelname` | 日志级别 |
| `message` | 具体内容 |
想输出 JSON 格式方便后续解析?自己写个 formatter 就成:
```python
import logging
import json
class JSONFormatter(logging.Formatter):
def format(self, record):
return json.dumps({
"time": self.formatTime(record),
"level": record.levelname,
"logger": record.name,
"message": record.getMessage()
})
```
---
## 二、gcloud 集成层日志
gstack 通过 `gcloud auth` 调用 Vertex AI 时,认证层和 HTTP 请求层会额外输出 gcloud SDK 的日志。这部分由 Google Cloud Python SDK 的 `google-cloud-core` 库管理,和 gstack 自家的日志分开记录。
先看一下当前认证状态:
```bash
gcloud auth list
```
输出的 Active account 如果过期了,Vertex AI 调用直接返回 `401 Unauthorized`。
开启 gcloud 详细日志:
```bash
export GCLOUD_PYTHON_LOG_LEVEL=DEBUG
gstack generate "hello world"
```
DEBUG 级别下能看到完整的 HTTP 请求头、响应状态码、OAuth token 刷新全过程。
认证问题排查用这个:
```bash
gcloud auth debug --log-file=/tmp/gcloud_auth.log
```
Service Account 密钥认证出问题时,这命令生成的报告非常详细。
三类常见错误一览:
| 错误类型 | 特征 | 排查优先级 |
|---------|------|-----------|
| `PERMISSION_DENIED` | IAM 角色缺少 Vertex AI User | 第一优先级 |
| `API_NOT_ENABLED` | Vertex AI API 未启用 | 第一优先级 |
| `INVALID_ARGUMENT` | 请求参数格式错误 | 第二优先级 |
gstack 报 Vertex AI 调用失败?先看 gcloud 认证有没有过期,再查 Project IAM 权限,最后才看 gstack 本身。
---
## 三、Vertex AI 调用日志
gstack 和 Vertex AI 的交互本质是 REST API 调用 Gemini 模型。每次请求,Vertex AI 会在 GCP Cloud Logging 里自动生成一条 `generativelanguage.googleapis.com` 类型的日志,包含请求 ID、模型名称、token 消耗量、延迟和响应状态。
通过 gcloud CLI 查看 Vertex AI 日志:
```bash
gcloud logging read \
'resource.type="ai_platform" AND resource.labels.endpoint_id="*"' \
--project=YOUR_PROJECT_ID \
--latest 20 \
--format="table(timestamp,severity,jsonPayload.model_display_name,jsonPayload.request_id,jsonPayload.latencyMs)"
```
按时间范围过滤特定模型:
```bash
gcloud logging read \
'resource.type="ai_platform" AND jsonPayload.model_display_name="gemini-1.5-pro"' \
--project=YOUR_PROJECT_ID \
--freshness=24h \
--format="json"
```
想精确定位单次调用?用 `request_id` 查:
```bash
gcloud logging read \
'jsonPayload.request_id="abc123xyz"' \
--project=YOUR_PROJECT_ID \
--format="json"
```
`request_id` 是把 gstack 本地日志和 Vertex AI 云端日志串起来的关键字段,必须记住。
Cloud Logging 默认保留 30 天,企业版可以自定义。想长期存档?配置日志路由:
```bash
gcloud logging sinks create gstack-archive \
storage.googleapis.com/your-bucket \
--log-filter='resource.type="ai_platform"'
gcloud logging sinks update gstack-archive \
--add-exclusion='name=exclude-debug,pfilter='severity="DEBUG"'
```
日志字段说明:
| 字段 | 含义 |
|------|------|
| `request_id` | 单次 API 调用唯一标识,关联 gstack 本地日志用这个 |
| `latencyMs` | 请求发起到首 token 返回的耗时 |
| `promptTokens` / `completionTokens` | 输入和输出的 token 消耗量 |
| `status.code` | gRPC 状态码,`0` 是成功 |
| `securityLabels` | 数据安全标签,影响日志可见性 |
---
## 四、Python SDK 中的日志集成
用 Python 脚本调用 gstack 的话,推荐显式注入 logging handler,把 gstack 和项目自身的日志框架打通。
基础日志注入:
```python
import logging
from gstack import GenerativeModel
gstack_logger = logging.getLogger("gstack")
gstack_logger.setLevel(logging.DEBUG)
handler = logging.FileHandler("logs/gstack_sdk.log")
handler.setFormatter(
logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s")
)
gstack_logger.addHandler(handler)
model = GenerativeModel("gemini-1.5-pro")
response = model.generate_content("Explain log rotation strategy.")
```
如果用 LangChain 或 LlamaIndex 调用 gstack,日志链路会更长:
```
框架层日志 (LangChain/LlamaIndex)
↓
gstack SDK 日志
↓
Vertex AI 日志 (Cloud Logging)
```
排查问题从框架层日志开始往上看。LangChain 开启 verbose 模式能输出完整 Prompt 和 Response:
```python
from langchain.chat_models import ChatVertexAI
import logging
logging.getLogger("langchain").setLevel(logging.DEBUG)
chat = ChatVertexAI(model_name="gemini-1.5-pro", verbose=True)
```
生产环境推荐把 gstack 日志和 OpenTelemetry 链路打通:
```python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
trace.set_tracer_provider(TracerProvider())
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("gstack-call") as span:
span.set_attribute("gstack.model", "gemini-1.5-pro")
response = model.generate_content(prompt)
span.set_attribute("gstack.latency", response.latency)
```
---
## 五、常见问题与排查路径
**gstack 命令无输出,也不写日志**
大概率是认证失败但异常被静默吞掉了。跑一下 `gcloud auth status`,确认 Active account 存在且没过期。Service Account 用户检查 `GOOGLE_APPLICATION_CREDENTIALS` 环境变量指向的 JSON 文件路径对不对。
```bash
gcloud auth activate-service-account --key-file=key.json
gcloud auth print-identity-token # 测试是否可用
```
**日志只有 WARNING 和 ERROR,没有 DEBUG 信息**
`GSTACK_LOG_LEVEL` 可能被其他进程或 wrapper 脚本覆盖了。docker run 场景下,`-e GSTACK_LOG_LEVEL=DEBUG` 要显式传入,写在 Dockerfile 的 ENV 里不生效。
```bash
echo $GSTACK_LOG_LEVEL
docker run -e GSTACK_LOG_LEVEL=DEBUG your-gstack-image
```
**Cloud Logging 中找不到对应 request_id**
Vertex AI 日志写入最多有 60 秒延迟,刚跑完查不到别慌,等一分钟再试。另外确认 Project ID 与 gstack 配置的 `--project` 参数一致,跨 Project 查询不会有结果。
**日志出现 `Quota Exceeded` 错误**
查看单日 token 消耗:
```bash
gcloud logging read \
'resource.type="ai_platform"' \
--freshness=24h \
--format="table(jsonPayload.promptTokens,jsonPayload.completionTokens)" | \
awk '{s+=$1;t+=$2} END {print " rompt:", s, "Completion:", t}'
```
**日志文件占满磁盘空间**
`config.yaml` 里配好日志轮转:
```yaml
logging:
max_bytes: 10485760 # 10MB
backup_count: 5 # 保留5个轮转文件
```
也可以用 logrotate 强制执行:
```bash
/usr/sbin/logrotate -f /etc/logrotate.d/gstack
```
---
## 六、日志配置方案对比
| 场景 | 推荐日志级别 | 日志存储 | 查看工具 |
|------|------------|---------|---------|
| 日常开发调试 | DEBUG | 本地文件 `~/.gstack/logs/` | `tail -f` / VSCode 日志插件 |
| CI/CD 集成 | INFO | 本地文件 + Cloud Logging | `gcloud logging read` |
| 生产环境审计 | INFO + Cloud Logging | Cloud Logging (30天) + GCS 归档 | Cloud Logging Explorer / Log Analytics |
| 超大代码库批量处理 | WARNING(减少 IO) | Cloud Logging 仅 | 按 `severity=WARNING` 过滤 |
| 安全合规审计 | INFO + Cloud Logging + Cloud Audit Logs | Cloud Audit Logs (400天) | Security Command Center |
**本地开发环境**:DEBUG 级别开满,完整日志文件留着方便断点调试。VSCode 的 Log Analyzer 插件直接解析 gstack 日志格式,体验不错。
**CI/CD 环境**:日志写本地文件的同时,通过 `gcloud logging write` 同步到 Cloud Logging。CI 日志保留 7 天后自动清理。
**生产环境**:INFO 及以上级别就够了,Cloud Logging 过滤器和路由规则搞定分级存储与长期归档。合规需求别忘了开 Cloud Audit Logs。
---
## 七、进阶:日志分析与性能优化
### 从日志提取 token 消耗成本
```bash
grep "promptTokens\|completionTokens" ~/.gstack/logs/gstack.log | \
awk -F'=' '{sum+=$2} END {print "Total tokens:", sum}'
```
### 识别慢请求进行模型切换
```bash
grep "latencyMs" ~/.gstack/logs/gstack.log | \
awk -F'latencyMs=' '{print $2}' | \
sort -n | \
awk 'BEGIN{c=0} {a[c++]=$1;} END{
print " 50:", a[int(c*0.5)];
print " 95:", a[int(c*0.95)];
print " 99:", a[int(c*0.99)];
}'
```
P99 延迟超过 10 秒的话,简单任务可以切到 `gemini-1.5-flash` 省点钱。
---
## 结语
gstack 的日志体系没有搞什么专有格式,核心就是 Python 标准 logging 加 GCP Cloud Logging,对已有 GCP 日志管理流程的团队来说接入成本不高。
关键点就两个:开发阶段日志级别设成 `DEBUG`、文件保留完整;生产环境走 Cloud Logging 的过滤器和路由规则分级存储。链路打通之后,`API_NOT_ENABLED` 这类配置问题的排查时间能从小时级压到分钟级。
有什么踩坑经历或者问题,欢迎评论区聊。 |
|