cat客户端部分核心类
message目录下面有消息相关的部分接口
internal目录包含主要的CAT客户端内部实现类;
io目录包含建立服务端连接、重连、消息队列监听、上报等io实现类;
spi目录为上报消息工具包,包含消息二进制编解码、转义等实现类。
消息的组织 - 消息树
大众点评Cat使用消息树(MessageTree)组织日志,下面为消息树的类定义
我们每次操作的实体都是消息树,其中有个domain字段,这是cat中一个非常重要的概念,一个domain可以对应成一个project,每个消息树拥有一个唯一的MessageId, 不同的消息树(比如微服务中A服务调用B服务,A,B都会生成消息树) 通过 parenMessageId、rootMessageId 串联起来,消息树下的所有实体都是Message,一共有5种类型的Message, 分别是Transaction, Event, Trace, Metric和Heartbeat。
Transaction:可以理解为是一个事务,事务之间可以互相嵌套,事务还可以嵌套任意其他消息类型,存放在List<Message> m_children 成员变量中,也只有事务才可以嵌套。一般用来记录跨越系统边界的程序访问行为,比如远程调用,数据库调用,也适合执行时间较长的业务逻辑监控。
Event:代表系统是在某个时间点发生的一次事件,例如新用户注册、登陆,系统异常等,理论上可以记录任何事情,它和transaction相比缺少了时间的统计,开销比transaction要小。还可以用来记录两个事务之间的关系,分支事务通过设置消息树的parentMessageId维护与主事务消息之间的关系。
Trace:用于记录一些trace、debug这类的信息,比如log4j打印日志。以便于快速调试定位问题
Metric:用于记录业务指标、指标可能包含对一个指标记录次数、记录平均值、记录总和
Heartbeat:主要用于记录系统的心跳信息,比如CPU%, MEM%,连接池状态,系统负载等。
客户端的初始化
客户端操作对象Cat封装了所有的接口。我们先通过下面源码来了解下Cat的初始化过程。
class Cat{ public static Transaction newTransaction(String type, String name) { return Cat.getProducer().newTransaction(type, name); } public static MessageProducer getProducer() { checkAndInitialize(); return s_instance.m_producer; } private static void checkAndInitialize() { if (!s_init) { synchronized (s_instance) { if (!s_init) { initialize(new File(getCatHome(), "client.xml")); log("WARN", "Cat is lazy initialized!"); s_init = true; } } } } public static void initialize(File configFile) { PlexusContainer container = ContainerLoader.getDefaultContainer(); initialize(container, configFile); } public static void initialize(PlexusContainer container, File configFile) { ModuleContext ctx = new DefaultModuleContext(container); Module module = ctx.lookup(Module.class, CatClientModule.ID); if (!module.isInitialized()) { ModuleInitializer initializer = ctx.lookup(ModuleInitializer.class); ctx.setAttribute("cat-client-config-file", configFile); initializer.execute(ctx, module); } } }