暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

CAT源码分析(五)——CAT客户端之CAT埋点

贰级天災 2018-09-11
558


首先来看一个基本的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;
        }
    }
复制
  1. 检查消息管理器有没有Context,没有就建一个。创建的时候涉及到一个很重要的类:DefaultMessageTree。

  1. 判断是否可以记录消息,可以就开启事务。否则返回一个空事务。在开启事务的过程中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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论