Skip to Content

日志(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/
iOSArgusSDK(Swift Package)/quickstart/ios/
Androidcom.argusplatform:argus-sdk/quickstart/android/
Flutterargus_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。

端上最小示例

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" });

后端最小示例

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 页面),先在左上角选择项目。

筛选器

筛选器说明
LevelDEBUG / INFO / WARN / ERROR / FATAL,空 = 全部级别
SourceDevice (app/SDK) = 端上日志;Backend (server) = 后端日志;空 = 全部
Search message日志正文子串搜索(大小写不敏感)
Trace IDtrace_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
WebArgus.log(level, message, attributes?)Argus.identify(userId) · Argus.flush()
AndroidArgus.log(message, level = LogLevel.INFO, attributes?)Argus.identify(userId) · Argus.addBreadcrumb(message, level) · Argus.setLogConsent(granted) · Argus.flush()
iOSArgus.log(_ message, level: .info, attributes:)Argus.identify(_:) · Argus.addBreadcrumb(_:level:) · Argus.setLogConsent(_:) · Argus.flush()
FlutterArgus.log(LogLevel, message, {attributes})Argus.identify(userId) · Argus.flush()
React NativeArgus.log(level, message, attributes?)Argus.identify(userId) · Argus.flush()

后端 SDK

后端五语言的行为一致,命名按各语言惯例——Go / Node 提供 Info/Warn/Error/Debug 分级便捷方法,Python / Java / Rust 为统一的 log(level, message, ...)

语言日志 API
Goclient.Info(ctx, msg, attrs)Debug / Warn / Error 对称,均带 ctx
Nodeclient.info(msg, { attrs, traceId? })debug / warn / error 对称)
Pythonclient.log("info", msg, attributes={...}, trace_id=...)
Javaclient.log("info", msg, attrs, traceId)
Rustclient.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_idsearch(必填)、sourcetrace_idevent_idlimit
log.recent最近 N 条日志(无关键词时看最新动态)project_idlevelsourcetrace_idlimit
log.by_user某个最终用户的日志(还原工单用户的经历)project_iduser_idlimit
log.by_session单个会话的全部日志(如崩溃前的完整序列)project_idsession_idlimit
log.aggregatelevel / user_id / platform 分组计数(找最热错误级别 / 最吵用户)project_idgroup_bylimit

配额与计费

  • 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