日志(Logs)
日志是 Argus(百目)可观测能力的底盘:崩溃、性能、埋点等所有数据采集都复用同一套上报框架
(消息认证码(HMAC)签名、批量上报、本地降级队列)。你在业务代码里调用一行 Argus.log(...),
SDK 负责把这条结构化日志安全、可靠地送到服务端,几秒内即可在 Console 检索。
Argus 日志的独特之处在于端上 + 后端同一张表:浏览器 / App 里的端上日志与你自己服务器上的
后端日志统一进入 ClickHouse events_log,用同一套筛选语法查询,还能按 trace_id 把一次请求
在「用户设备 → 你的后端」两侧产生的日志串成一条链路(见 端到端 Trace)。
典型使用场景:
- 「用户
user-123反馈支付失败」→ 按user_id拉出该用户最近日志,还原操作序列; - 「崩溃前发生了什么」→ 从崩溃详情跳到同
session_id的日志; - 「这个接口报错是谁引起的」→ 按
trace_id聚合端上 + 后端日志看全链路; - 让 AI 来查——通过模型上下文协议(MCP)工具
log.search等直接在 Claude / Cursor 里检索。
核心概念
日志条目(数据模型)
每条日志是一行结构化事件,核心字段:
| 字段 | 说明 |
|---|---|
event_id | 端上生成的唯一 ID;断网重传时复用同一值,服务端按它幂等去重,统计不因重传失真 |
timestamp | 日志产生时间(epoch 毫秒,数据时间戳) |
level | 级别:DEBUG / INFO / WARN / ERROR / FATAL |
message | 日志正文,支持子串搜索 |
user_id / session_id | 归属用户与会话,Console 可点击下钻 |
attributes | 业务自定义键值对(如 {"module": "payment"}) |
platform | 上报来源平台(ios / android / web / flutter / react-native / 后端服务名) |
trace_id | 若日志产生于某条 trace 上下文中自动填充,可跳转链路瀑布图 |
两个时间戳别混:日志条目的 ts 是 epoch 毫秒(数据时间戳);上报请求签名头
X-Argus-Timestamp 是 epoch 秒(鉴权用,服务端 ±300s 防重放)。详见
DSN 与 HMAC 签名。
日志来源(source):device 与 backend
- Device(端上):来自 iOS / Android / Web / Flutter / React Native SDK,经统一事件通道
POST /v1/events上报(见 上报端点参考)。 - Backend(后端):来自 Go / Node / Python / Java / Rust 后端 SDK,经
POST /v1/backend/logs上报。
两类日志同表存储,Console 用 source 筛选器区分视图。
面包屑(Breadcrumb)
每次 Argus.log() 调用会自动记入一个端上环形缓冲(Web / Flutter / React Native 为最近
20 条,iOS 为最近 50 条)。这些面包屑不单独上报,而是在崩溃发生时随崩溃事件一并携带,
在崩溃详情页还原「崩溃前用户经历了什么」。详见 崩溃与 ANR。
可靠投递与 SDK 自保护
日志 SDK 遵循统一的自保护基线——「可观测 SDK 绝不能拖垮宿主」:
- 不阻塞业务:
Argus.log()只把事件放进异步队列即返回,序列化 / 网络在后台执行; - 批量上报:按条数 / 字节 / 定时三个阈值打包发送(如 Web / Flutter 默认 100 条 /
100 KB / 10s,Android 默认 20 条 / 50 KB / 30s,可经
queueConfig调整); - 本地降级:断网时事件落盘(Android 磁盘 batch 上限 100 个 / 5 MB;React Native 可注入
AsyncStorage持久化),恢复后自动重传,冷启动扫盘恢复未送达批次; - 失败退避:上报失败按指数退避重试;缓冲超上限时 drop-oldest(保留最新窗口),
后端 SDK 可经
dropped()/client.dropped查询丢弃计数; - 静默降级:SDK 内部错误不向业务代码抛异常——磁盘满、序列化失败、未初始化时
Argus.log()均为无害的 no-op。
完整红线清单见基线文档
docs/02-product/04-baseline-sdk-self-protection.md。
用户同意门(Consent Gate)
面向 PIPL / GDPR「收集前同意」场景,iOS / Android SDK 支持
requireLogConsent(初始化配置,默认 false):开启后,在最终用户授予同意
(Argus.setLogConsent(true))之前不采集、不上报。Argus.isLogConsentGranted() 可查询当前状态。
接入
平台支持矩阵
| 端 | SDK | 快速开始 |
|---|---|---|
| Web(浏览器) | @argus/sdk-web | /quickstart/web/ |
| iOS | ArgusSDK(Swift Package) | /quickstart/ios/ |
| Android | com.argusplatform:argus-sdk | /quickstart/android/ |
| Flutter | argus_flutter | /quickstart/flutter/ |
| React Native | @argus/sdk-react-native | /quickstart/react-native/ |
| Go 后端 | go.argusplatform.com/sdk/go-backend | /quickstart/go-backend/ |
| Node 后端 | @argus/sdk-node-backend | /quickstart/node-backend/ |
| Python 后端 | argus-backend | /quickstart/python-backend/ |
| Java 后端 | com.argusplatform:argus-backend | /quickstart/java-backend/ |
| Rust 后端 | argus-backend(crate) | /quickstart/rust-backend/ |
接入只需两步:初始化(传入 DSN,见 DSN 与 HMAC 签名)+ 调用日志 API。
端上最小示例
Web
import { Argus } from "@argus/sdk-web";
Argus.init({ dsn: "argus://<public_key>:<secret_key>@<host>:4318/<project_id>" });
Argus.log("INFO", "page loaded", { route: "/home" });
Argus.log("ERROR", "payment failed", { reason: "declined" });后端最小示例
Go
client, err := argus.New(argus.Config{
DSN: os.Getenv("ARGUS_DSN"),
ServiceName: "checkout-api",
})
defer client.Close()
// 首参 ctx:若携带 active span,日志自动带上 trace_id
client.Info(ctx, "order received", map[string]string{"user_id": "u-42"})
client.Error(ctx, "payment failed", map[string]string{"reason": "card_declined"})Console 使用
进入 Console → Logs(/logs 页面),先在左上角选择项目。
筛选器
| 筛选器 | 说明 |
|---|---|
| Level | DEBUG / INFO / WARN / ERROR / FATAL,空 = 全部级别 |
| Source | Device (app/SDK) = 端上日志;Backend (server) = 后端日志;空 = 全部 |
| Search message | 日志正文子串搜索(大小写不敏感) |
| Trace ID | 按 trace_id 聚合同一请求 / 链路的全部日志(端上 + 后端) |
列表与下钻
结果按时间倒序展示 Time / Level / Message / User / Session / Trace 列:
- 点 User → 跳转该用户的日志时间线(
/logs/users/<user_id>); - 点 Session → 跳转该会话的完整日志序列(
/logs/sessions/<session_id>); - 点 Trace → 跳转 trace 详情瀑布图(
/traces/<trace_id>),日志与链路双向可达。
接入后看不到日志?先看页面空态提示(未选项目 / 无匹配日志),再按 故障排查 的「上报返回 200 但 Console 看不到数据」逐项自查 (时钟偏移、DSN、级别筛选、项目错配是四大高频原因)。
SDK API
端上 SDK
| 端 | 日志 API | 相关 API |
|---|---|---|
| Web | Argus.log(level, message, attributes?) | Argus.identify(userId) · Argus.flush() |
| Android | Argus.log(message, level = LogLevel.INFO, attributes?) | Argus.identify(userId) · Argus.addBreadcrumb(message, level) · Argus.setLogConsent(granted) · Argus.flush() |
| iOS | Argus.log(_ message, level: .info, attributes:) | Argus.identify(_:) · Argus.addBreadcrumb(_:level:) · Argus.setLogConsent(_:) · Argus.flush() |
| Flutter | Argus.log(LogLevel, message, {attributes}) | Argus.identify(userId) · Argus.flush() |
| React Native | Argus.log(level, message, attributes?) | Argus.identify(userId) · Argus.flush() |
后端 SDK
后端五语言的行为一致,命名按各语言惯例——Go / Node 提供 Info/Warn/Error/Debug
分级便捷方法,Python / Java / Rust 为统一的 log(level, message, ...):
| 语言 | 日志 API |
|---|---|
| Go | client.Info(ctx, msg, attrs)(Debug / Warn / Error 对称,均带 ctx) |
| Node | client.info(msg, { attrs, traceId? })(debug / warn / error 对称) |
| Python | client.log("info", msg, attributes={...}, trace_id=...) |
| Java | client.log("info", msg, attrs, traceId) |
| Rust | client.log("info", msg, &[("k", "v")], trace_id) |
完整的跨语言 API 对照(初始化 / 关闭 / metric / trace)见
docs/10-reference/05-backend-sdk-api-matrix.md。
MCP 工具
接入 MCP 后,AI(Claude / Cursor / Copilot)可用以下只读工具查日志:
| 工具 | 用途 | 关键参数 |
|---|---|---|
log.search | 按日志正文子串搜索(大小写不敏感的字面匹配,非全文索引) | project_id、search(必填)、source、trace_id、event_id、limit |
log.recent | 最近 N 条日志(无关键词时看最新动态) | project_id、level、source、trace_id、limit |
log.by_user | 某个最终用户的日志(还原工单用户的经历) | project_id、user_id、limit |
log.by_session | 单个会话的全部日志(如崩溃前的完整序列) | project_id、session_id、limit |
log.aggregate | 按 level / user_id / platform 分组计数(找最热错误级别 / 最吵用户) | project_id、group_by、limit |
配额与计费
- 1 条日志 = 1 个 event,计入项目的 events 配额;日志不计 MAU。
- 保留期默认 30 天(可配置,决定 storage 配额占用),到期真删——详见 数据保留。
- 超出配额时服务端返回
429 + Retry-After,SDK 本地降级、恢复后补传。
详见 配额与计费。
常见问题
接入了却看不到日志?
按顺序检查:① DSN 是否为 Console 颁发的原值(host / 项目 ID 未改错);② 设备时钟是否准确
(签名时间戳偏差超 ±300s 会被拒);③ 是否还没到批量 flush 时机——调 Argus.flush() 立即上报;
④ Console 左上角项目、level / source 筛选是否与上报一致。更多见 故障排查。
大量打日志会拖垮 App 或打爆账单吗?
Argus.log() 只入队即返回,不阻塞业务线程;队列有条数 / 字节上限,超限丢弃而非无界增长。
但每条日志都计入 events 配额——不建议把循环内高频日志原样接入,先在业务侧控制频率,
并善用 DEBUG 级别 + 上报前筛选。
日志里的敏感信息(手机号 / token)怎么办?
message / attributes 中可能含个人身份信息(PII)的内容应在离开设备前处理——不要把
密码、完整卡号、身份证号写进日志正文。各字段在端上有长度上限并截断,超大日志不会拖垮上报。
断网 / 杀进程会丢日志吗?
断网时日志进入本地队列(Android 落盘、React Native 可注入 AsyncStorage 持久化),恢复网络
或下次冷启动时自动重传;重传复用同一 event_id,服务端幂等去重,不会重复计数。队列满载时
按 drop-oldest 淘汰最旧数据。
端上日志和后端日志怎么关联?
让两侧共享同一条 trace:端上 SDK 给出站请求注入 W3C traceparent,后端 SDK 中间件继承它,
两侧日志都会带上同一个 trace_id。在 Console Logs 页输入该 Trace ID 即可看到跨端合并视图。
详见 端到端 Trace。