首先来看一个基本的CAT埋点操作:
public static void main(String[] args) { Transaction transaction = Cat.newTransaction("type","transaction"); transaction.addData("key","value"); transaction.setStatus(Transaction.SUCCESS); transaction.complete(); }
上面这段代码记录了一个简单的transaction就完成了,再让线程sleep一段时间就可以在服务端页面看到如下页面。(sleep是为了让消息能够发送出去)
接下来我们就以Transaction为例看看CAT到底做了哪些工作。
一、创建Transaction
public static Transaction newTransaction(String type, String name) { return Cat.getProducer().newTransaction(type, name); }
newTransaction方法获取消息生产者创建Transaction,而getProducer方法返回在返回调用了checkAndInitialize方法,这也是整个CAT客户端IOC的开始。想了解CAT的IOC可以查看:CAT源码分析番外篇——IOC容器Plexus。
最终的newTransaction操作:
public Transaction newTransaction(String type, String name) { if (!m_manager.hasContext()) { m_manager.setup(); } if (m_manager.isMessageEnabled()) { DefaultTransaction transaction = new DefaultTransaction(type, name, m_manager); m_manager.start(transaction, false); return transaction; } else { return NullMessage.TRANSACTION; } }
检查消息管理器有没有Context,没有就建一个。创建的时候涉及到一个很重要的类:DefaultMessageTree。

判断是否可以记录消息,可以就开启事务。否则返回一个空事务。在开启事务的过程中transaction被放到了消息树中。
二、添加数据和设置状态
public void addData(String key, Object value) { if (m_data instanceof StringBuilder) { ((StringBuilder) m_data).append('&').append(key).append('=').append(value); } else { String str = String.valueOf(value); int old = m_data == null ? 0 : m_data.length(); StringBuilder sb = new StringBuilder(old + key.length() + str.length() + 16); if (m_data != null) { sb.append(m_data).append('&'); } sb.append(key).append('=').append(str); m_data = sb; } }
将数据以key1=value1&key2=value2&key3=value3…的格式累加。状态用到的一般是成功和异常。
三、Transaction完成
public void complete() { try { if (isCompleted()) { DefaultEvent event = new DefaultEvent("cat", "BadInstrument"); event.setStatus("TransactionAlreadyCompleted"); event.complete(); addChild(event); } else { m_durationInMicro = (System.nanoTime() - m_durationStart) / 1000L; setCompleted(true); if (m_manager != null) { m_manager.end(this); } } } catch (Exception e) { // ignore } }
当transaction已经完成时,会记录错误调用;没完成则通过消息管理器结束该transaction。而实际的结束transaction又交给了context。
public boolean end(DefaultMessageManager manager, Transaction transaction) { if (!m_stack.isEmpty()) { Transaction current = m_stack.pop(); if (transaction == current) { m_validator.validate(m_stack.isEmpty() ? null : m_stack.peek(), current); } else { while (transaction != current && !m_stack.empty()) { m_validator.validate(m_stack.peek(), current); current = m_stack.pop(); } } if (m_stack.isEmpty()) { MessageTree tree = getM_tree().copy(); getM_tree().setMessageId(null); getM_tree().setMessage(null); if (m_totalDurationInMicros > 0) { adjustForTruncatedTransaction((Transaction) tree.getMessage()); } manager.flush(tree); return true; } } return false; }
context做了一系列处理后,会调用flush方法将消息树发送出去。
public void flush(MessageTree tree) { if (tree.getMessageId() == null) { tree.setMessageId(nextMessageId()); } MessageSender sender = m_transportManager.getSender(); if (sender != null && isMessageEnabled()) { sender.send(tree); reset(); } else { m_throttleTimes++; if (m_throttleTimes % 10000 == 0 || m_throttleTimes == 1) { m_logger.info("Cat Message is throttled! Times:" + m_throttleTimes); } } }
可以看到,消息管理器中持有了传输管理器,而传输管理器中的消息发送器就是专门负责小学发送的。这个会在下一篇中详细介绍。
文章转载自贰级天災,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




