深入 CAT 多语言客户端消息模型:Transaction、Event、Heartbeat、Metric 与消息属性全解
深入 CAT 多语言客户端消息模型Transaction、Event、Heartbeat、Metric 与消息属性全解【免费下载链接】catCAT 作为服务端项目基础组件提供了 Java, C/C, Node.js, Python, Go 等多语言客户端已经在美团点评的基础架构中间件框架MVC框架RPC框架数据库框架缓存框架等消息队列配置系统等深度集成为美团点评各业务线提供系统丰富的性能指标、健康状况、实时告警等。项目地址: https://gitcode.com/gh_mirrors/ca/catCATCentral Application Tracking作为服务端项目基础组件提供了 Java、C、C、Python、Go、Node.js 等多语言客户端。无论你使用哪种语言接入最终上报到服务端、并在 Logview / 消息树 / 报表中呈现的基础单元都是消息Message。本文以仓库 lib/README.md 为主线系统讲解 CAT 客户端的四大消息类型Transaction、Event、Heartbeat、Metric与全部消息属性type、name、status、data、timestamp 及 Transaction 特有的 duration、durationStart并结合各语言客户端的源码实现让你在埋点前就对 CAT 的数据模型有透彻理解能够写出规范、可聚合、可排查问题的埋点代码。一、多语言支持总览CAT 客户端目前支持以下六种编程语言详见 lib 目录语言客户端名称官方文档Javacat-clientlib/java/README.mdCccatlib/c/README.mdCcppcatlib/cpp/README.mdPythonpycatlib/python/README.mdGogocatlib/go/README.mdNode.jsnodecatlib/node.js/README.md按照文档说明以下语言在支持计划之中PHP、C# (.net)。仓库中已经出现了 lib/csharp 与 lib/erlang 的客户端源码说明多语言生态仍在持续扩展。尽管语言各异所有客户端遵循同一套消息模型——消息类型与消息属性在各语言 SDK 中保持一致的设计语义这也是本文接下来的核心内容。二、四大消息类型Message TypesCAT 定义了四种消息类型Transaction、Event、Heartbeat、Metric。它们在使用目的上差异明显1. Transaction事务Transaction 用于记录一段需要耗时、且可能失败的工作单元。从 Java 客户端的接口注释可以确认其语义见 cat-client/src/main/java/com/dianping/cat/message/Transaction.javaTransaction is any interesting unit of work that takes time to complete and may fail.所有跨边界的耗时操作都应记录为 Transaction例如URL 请求、磁盘 IO、JDBC 查询、搜索查询、HTTP 请求、第三方 API 调用等。CAT 的所有消息都会构造成一棵消息树Message Tree发送到后端做分析和监控而只有 Transaction 可以作为树节点其他消息都是树的叶子节点。没有嵌套子消息的 Transaction 称为原子事务atomic transaction。这意味着 Transaction 天然支持嵌套一个 Transaction 内可以嵌套其他 Transaction、Event、Heartbeat而 Event 与 Heartbeat 不能再嵌套任何子消息。通过addChild(Message)添加子消息、getChildren()获取子消息列表即可操作这棵树。2. Event事件Event 用于记录一次发生的事件通常是一次性的、无耗时的操作记录比如调用了某台服务器发生了一次异常。Event 没有耗时概念是消息树中的叶子节点。3. Heartbeat心跳Heartbeat 用于周期性上报运行环境信息例如 CPU、内存、磁盘、线程数、GC 等系统指标。客户端内置的 heartbeat 会按固定周期自动产生并上报帮助服务端监控应用实例的健康状态。4. Metric指标Metric 用于记录业务计数与耗时聚合值它不参与消息树的构建而是按秒聚合后批量上报。Metric 分为两类Counter计数如调用次数上报的是每秒内的累加值summarizedDuration耗时如平均处理耗时上报的是每秒内的平均值averaged。例如同一秒内用相同名字调用 3 次 count客户端只汇总这 3 次的值并上报一次而 duration 则上报的是平均值而非总和。从 Java 源码 cat-client/src/main/java/com/dianping/cat/message/Metric.java 可以看到 Metric 独立于Message接口体系它继承的是MetricBag相关的独立接口这也印证了 Metric 不走消息树、而是独立聚合上报的设计。三、通用消息属性Message Properties每条消息Transaction、Event、Heartbeat 均实现Message接口见 cat-client/src/main/java/com/dianping/cat/message/Message.java都包含以下五个通用属性。1. type类型表示消息的类别用于归组。常见的取值如SQL、RPC、HTTP、URL、Cache等。type 是报表聚合的第一级维度命名时建议保持有限的枚举集合避免高基数导致报表碎片化。2. name名称表示特定的行为是 type 之下的第二级聚合维度。官方文档给出的命名示例当type为SQL时name可以是select ? from user where id ?即 SQL 模板注意不是带具体参数值的 SQL当type为RPC时name可以是QueryOrderByUserId(string, int)即 API 的函数签名当type为HTTP时name可以是/api/v8/{int}/orders即基础 URI不带实际参数。详细参数信息建议记录在data字段中比如本次 API 调用的具体参数。这个命名规范非常关键name 必须是低基数的模板否则每个请求都产生不同的 name将导致报表无法聚合、Logview 无法按规则合并进而失去统计意义。3. status状态表示消息的状态。约定0为成功Java 中定义为Message.SUCCESS 0见 Message.java。status 非0的消息会被标记为 problem问题消息并展示在 Problem 报表中。一旦消息被标记为 problem无论它是什么类型其所在的消息树将不会被聚合——这意味着你随时可以拿到这条 problem 消息完整的 Logview 结构用于逐层排查根因。这是 CAT 问题定位能力的基石正常消息会被聚合压缩以节省存储而问题消息则保留完整树形链路。4. data数据记录消息的详细信息。官方文档示例如果type为SQLdata可以是id75442432如果type为RPCdata可以是userTypedianpinguserId9987如果type为HTTPdata可以是orderId75442432。在部分场景下data字段还会包含错误堆栈error stack traces比如记录一个 exception 或 error 时完整堆栈会被写入 data。关于 data 还有两个实用细节多次 addData 会以连接Java、Go、Python、Node.js 客户端的文档都明确说明可以多次调用addData多次添加的数据会通过拼接成键值对风格字符串data 可以是结构化对象Node.js 客户端中 data 也支持传入对象此时会被序列化为 JSON见 lib/node.js/README.md。5. timestamp时间戳表示消息的创建时间会在 Logview / 消息树中展示。其定义为自1970-01-01 00:00:00以来经过的毫秒数epoch milliseconds。通常你不需要手动设置 timestamp客户端会在消息创建时自动打点只有在需要回溯补报历史数据时才通过 API 覆写。四、Transaction 特有属性Transaction 在通用消息属性之外还额外拥有两个与耗时计算相关的属性。1. duration耗时表示一个 Transaction花费的总时间单位毫秒。duration 在 Transaction完成complete时被计算duration currentTimestamp() - durationStart你可以在 Transaction 完成之前通过相关 API如 Java 的setDurationInMillis、Go 的SetDuration、Python 的set_duration显式指定 duration 的值从而跳过默认的计算过程。这在埋点时刻晚于实际执行时刻的场景下非常有用。2. durationStart起始时间表示 Transaction开始执行的时间点。它与timestamp的区别是durationStart仅用于计算 duration覆写durationStart不会影响timestamp。也就是说timestamp描述这条消息是什么时候创建的用于消息树时间轴展示durationStart描述这段工作从什么时候开始计时的仅参与耗时计算。两者解耦使得记录时间与计时起点可以灵活分开设置。使用注意各语言文档统一强调不要在同一 Transaction 上同时指定 duration 和 durationStart否则两个字段互相覆盖、语义冲突各语言文档示例中同时出现两者只是为了演示 API 用法实际业务中应二选一。Transaction API 一览下表汇总了各语言客户端提供的 Transaction 修改 API名称略有差异、能力一致能力JavaGoPythonNode.js追加数据addDataAddDataadd_dataaddData设置状态setStatusSetStatusset_statussetStatus设置耗时setDurationInMillisSetDurationset_duration—设置起始时间setDurationStartSetDurationStartset_duration_start—设置时间戳setTimestampSetTimestampset_timestamp—完成事务completeCompletecompletecomplete三个通用警告所有语言客户端文档一致强调可以多次调用 addData数据会以连接同一事务中同时指定 duration 与 durationStart 没有意义千万不要忘记 complete否则会产生损坏的消息树并造成内存泄漏。五、从源码看消息模型的落地1. Java 客户端的入口与常量Java 客户端的一切埋点都从 cat-client/src/main/java/com/dianping/cat/Cat.java 开始核心静态方法包括Cat.newTransaction(String type, String name)Cat.java—— 创建事务Cat.newEvent(String type, String name)Cat.java—— 创建事件Cat.logEvent(type, name[, status, nameValuePairs])Cat.java—— 即发即完的事件Cat.logError(Throwable)/Cat.logError(message, cause)Cat.java—— 错误事件Cat.logMetricForCount(name[, quantity])Cat.java与Cat.logMetricForDuration(name, durationInMillis)Cat.java—— 指标上报。错误事件logError是一种特殊的 Event其 type 由异常的类类型决定lib/java/README.md若异常是Error的实例type 为Error否则若异常是RuntimeException的实例type 为RuntimeException其余情况 type 为Exception。name默认取e.getClass().getName()堆栈信息自动构建并写入data。你还可以在堆栈顶部追加自定义错误消息例如Cat.logError(error(X) : exception(X), e)若想覆盖默认的 name 分类则使用Cat.logErrorWithCategory(custom-category, e)。消息接口 Message.java 定义了getType()、getName()、getStatus()、getTimestamp()、isCompleted()、isSuccess()等语义其中SUCCESS 0是全局成功约定。而 Transaction.java 在消息基础上扩展了getDurationInMicros()微秒与getDurationInMillis()毫秒、setDurationInMillis()、complete(long startInMillis, long endInMillis)、forFork()跨线程 Fork 事务用于多线程场景等能力印证了Transaction 是树节点、其余是叶子的结构设计。2. Go 客户端的实现Go 客户端gocat通过 CGO 高度依赖 C 客户端ccatlib/go/README.md。其 API 在 lib/go/gocat/api.go 中实现与消息模型一一对应NewTransaction/NewEvent/NewHeartbeat—— 分别创建三类消息LogEvent—— 即发即完的事件第 3 个参数status可选、默认0成功只有 status 等于SUCCESS才不算 problemLogError—— 错误事件默认type Exception、name error堆栈通过newStacktrace采集后写入 datalib/go/gocat/trace.goLogMetricForCount/LogMetricForDuration—— 指标上报LogMetricForCount不传第二参数时默认计数 1NewCompletedTransactionWithDuration—— 立即完成一笔带指定耗时纳秒的事务并自动把 timestamp 回拨到过去模拟过去发生的耗时调用注意耗时超过 60 秒时不会回拨 timestampapi.go。状态常量在 lib/go/gocat/const.go 中定义SUCCESS、FAIL以及编码器常量ENCODER_TEXT 0、ENCODER_BINARY 1。需要特别说明的是由于 ccat 使用线程局部存储thread local保存事务栈来构建消息树而 Go 的 goroutine 因 MPG 模型可能运行在不同线程上当前 Go 版本不支持消息树文档明确说明因此 Go 客户端每个消息完成即发送。3. Python 与 Node.js 客户端的实现Python 客户端pycat同样通过 cffi 依赖 ccatlib/python/README.mdcat.init(appkey, **kwargs)lib/python/src/cat/cat.py负责初始化且幂等保护重复初始化会输出 warningcat.log_event、cat.log_exception、cat.log_errorlib/python/src/cat/event.py分别对应事件、异常、轻量错误上报cat.metric(name).count()/.duration()lib/python/src/cat/metric.py提供链式的指标 API。Python 客户端提供了装饰器cat.transaction与上下文管理器with cat.Transaction(...) as t两种自动完成事务的用法推荐优先使用以避免漏调complete()。Node.js 客户端nodecat比较特殊lib/node.js/README.md由于 Node.js 是事件驱动模型事务可能交叉执行无法判断父子关系因此默认回退为Atomic Mode原子模式——每条消息完成即立刻发送3.1.x 版本引入了Thread Mode此时第一个 Transaction 成为根事务其后所有事务与事件都成为它的子节点整棵消息树在根事务完成后统一发送适合在单条请求链路内按序埋点的场景。六、初始化准备与通用配置各语言通用无论使用哪种语言客户端初始化前都需要完成同样的环境准备详见 lib/_/preparations.md创建/data/appdatas/cat目录并确保对该目录有读写权限权限建议不低于 0644创建/data/applogs/cat目录可选用于保存调试日志排查问题时非常有用同样需要读写权限创建/data/appdatas/cat/client.xml内容如下?xml version1.0 encodingutf-8? config xmlns:xsihttp://www.w3.org/2001/XMLSchema xsi:noNamespaceSchemaLocationconfig.xsd servers server ipcat server ip address port2280 http-port8080 / /servers /config别忘了把cat server ip address替换为真实的 CAT 服务端 IP。2280是 CAT 服务端的默认端口不允许修改http-port是 Tomcat 启动端口默认为8080建议使用默认值Java 客户端文档 lib/java/README.md 中的 client.xml 示例给出了多服务端写法可配置多台 server 做容灾。客户端还会生成client_cache.xml作为路由缓存文件如果出现路由错误删除client_cache.xml并重启服务即可。appkey 命名规范所有语言统一只允许英文字母a-z、A-Z、数字0-9、下划线_和短横线-。Java 客户端额外需要创建src/main/resources/META-INF/app.properties内容为一行app.name{appkey}。由于 Java 客户端采用懒初始化lazy initialized通常无需手动调用初始化方法。C 客户端则直接调用catClientInit(appkey)见 lib/c/README.mdGo 用gocat.Init(appkey)Python 用cat.init(appkey)Node.js 用cat.init({appkey: appkey})。各语言初始化参数差异客户端初始化方式特殊选项Java懒初始化 app.properties—CcatClientInit(appkey)默认开启 sampling、内置 heartbeat、binary 编码器可通过 API 文档定制lib/c/docs/api.mdGogocat.Init(appkey)依赖 ccat需 CGO 编译Pythoncat.init(appkey, ...)logviewFalse协程模式、samplingFalse关闭采样、encodercat.ENCODER_TEXT切换文本编码器、debugTrue输出调试日志到控制台Node.jscat.init({appkey})需先安装libcatclient.so到LD_LIBRARY_PATH参考 lib/c/README.md其中值得展开的 Python 选项Coroutine Mode协程模式由于消息树依赖 thread local 保存事务栈而 gevent、greenlet 等协程在同一线程内交替运行会破坏消息树的构建因此协程场景下应使用cat.init(appkey, logviewFalse)禁用消息树上下文管理器Sampling采样默认开启采样可通过samplingFalse关闭Encoder编码器默认使用 binary 编码器早期版本的 CAT 服务端只认文本编码器可通过encodercat.ENCODER_TEXT切换Debug logdebugTrue时调试日志输出到控制台。七、各语言快速上手示例以下示例均来自各语言官方 README展示的是同一个消息模型的埋点范式。JavaTransaction t Cat.newTransaction(URL, pageName); try { Cat.logEvent(URL.Server, serverIp, Event.SUCCESS, ip${serverIp}); Cat.logMetricForCount(metric.key); Cat.logMetricForDuration(metric.key, 5); yourBusiness(); t.setStatus(Transaction.SUCCESS); } catch (Exception e) { t.setStatus(e); Cat.logError(e); } finally { t.complete(); }Python推荐上下文管理器写法import cat import time cat.init(appkey) with cat.Transaction(foo, bar) as t: try: t.add_data(a1) cat.log_event(hook, before) # do something except Exception as e: cat.log_exception(e) finally: cat.metric(api-count).count() cat.metric(api-duration).duration(100) cat.log_event(hook, after) time.sleep(1)Got : cat.NewTransaction(TTYPE, test) defer t.Complete() t.AddData(testcase) t.AddData(foo, bar) t.SetStatus(gocat.FAIL) t.SetDurationStart(time.Now().UnixNano() - time.Second.Nanoseconds() * 5) t.SetTimestamp(time.Now().UnixNano() - time.Second.Nanoseconds()) t.SetDuration(time.Millisecond.Nanoseconds() * 1000)Go 强烈推荐使用defer t.Complete()确保事务一定完成同样地Python 推荐try-finally、装饰器或上下文管理器Java 推荐try-catch-finally包裹。八、小结CAT 的多语言客户端虽然语言各异但共享同一套消息模型Transaction 记录耗时工作并构成消息树Event 记录一次性事件Heartbeat 上报环境信息Metric 提供秒级聚合的业务指标每条消息由type、name、status、data、timestamp五个属性刻画其中status ! 0即成为不被聚合的 problem 消息data承载详细参数与错误堆栈timestamp记录创建时刻Transaction 额外拥有仅用于计时的durationStart与完成时计算的duration。理解这套模型是你写出高质量 CAT 埋点的基础规范的type/name命名保证报表可聚合正确设置status保证问题链路可追溯善用data保证可排查性不遗漏complete()保证消息树完整。各语言的详细 API 与集成方案log4j/log4j2/logback、URL 监控、Spring Boot 等可进一步参考 lib/java/README.md 与 integration 目录下的文档。【免费下载链接】catCAT 作为服务端项目基础组件提供了 Java, C/C, Node.js, Python, Go 等多语言客户端已经在美团点评的基础架构中间件框架MVC框架RPC框架数据库框架缓存框架等消息队列配置系统等深度集成为美团点评各业务线提供系统丰富的性能指标、健康状况、实时告警等。项目地址: https://gitcode.com/gh_mirrors/ca/cat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考