5.CAT-客户端 cat-clinet

客户端 代码 在04.服务端 有所 提及。

5.1 环境配置

5.1.1 源码中加载配置

public class DefaultClientConfigManager implements LogEnabled, ClientConfigManager, Initializable {
    private static final String CAT_CLIENT_XML = "/META-INF/cat/client.xml";

    private static final String PROPERTIES_CLIENT_XML = "/META-INF/app.properties";
    
    private static final String XML = "/data/appdatas/cat/client.xml";
    ......
        @Override
    public void initialize() throws InitializationException {
        File configFile = new File(XML);
        
        initialize(configFile);
    }
    @Override
   public void initialize(File configFile) throws InitializationException {
        try {
            ClientConfig globalConfig = null;
            ClientConfig clientConfig = null;

            if (configFile != null) {
                if (configFile.exists()) {
                    String xml = Files.forIO().readFrom(configFile.getCanonicalFile(), "utf-8");

                    globalConfig = DefaultSaxParser.parse(xml);
                    m_logger.info(String.format("Global config file(%s) found.", configFile));
                } else {
                    m_logger.warn(String.format("Global config file(%s) not found, IGNORED.", configFile));
                }
            }

            // load the client configure from Java class-path
            clientConfig = loadConfigFromEnviroment();

            if (clientConfig == null) {
                clientConfig = loadConfigFromXml();
            }
            // merge the two configures together to make it effected
            if (globalConfig != null && clientConfig != null) {
                globalConfig.accept(new ClientConfigMerger(clientConfig));
            }

            if (clientConfig != null) {
                clientConfig.accept(new ClientConfigValidator());
            }

            m_config = clientConfig;
        } catch (Exception e) {
            throw new InitializationException(e.getMessage(), e);
        }
   }
}

涉及到配置文件有

  • /data/appdatas/cat/client.xml
  • /META-INF/app.properties
  • /META-INF/cat/client.xml

    其中 /data/appdatas/cat/client.xml 获取服务端的地址进行连通
    app.properties 为了获取项目名,只有获取项目名后,才可以进行埋点数据上报,因为项目名 是 服务端的 domain
    cat/client.xml 是在 app.properties 获取不到数据时,才从 cat/client.xml获取。简单的说,获取项目名的逻辑顺序是 app.properties 高于 cat/client.xml

5.1.2 配置模板

client.xml 模板如下

<?xml version="1.0" encoding="utf-8"?>

<config mode="client" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd">
    <servers>
        <!-- Local mode for development -->
        <server ip="127.0.0.1" port="2280" http-port="2281" />
        <!-- If under production environment, put actual server address as list. -->
        <!-- 
            <server ip="192.168.7.71" port="2280" /> 
            <server ip="192.168.7.72" port="2280" /> 
        -->
    </servers>
</config>

app.properties模板

app.name=cat

client.xml模板

<config mode="client" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd">
    <domain id="Cat"/>
</config>

5.2 消息编码

消息编码,这里只关注消息的编码,消息结构 请参照 消息结构 章节

5.3 消息发送

消息发送离不开 消息发射器,通过消息发射器异步进行消息发送。

5.3.1 消息发送接口定义

MessageProducer

public interface MessageProducer {
    .....
    /**
     * Create a new event with given type and name.
     * 
     * @param type
     *           event type
     * @param name
     *           event name
     */
    public Event newEvent(String type, String name);

    /**
     * Create a new trace with given type and name.
     * 
     * @param type
     *           trace type
     * @param name
     *           trace name
     */
    public Trace newTrace(String type, String name);

    /**
     * Create a new heartbeat with given type and name.
     * 
     * @param type
     *           heartbeat type
     * @param name
     *           heartbeat name
     */
    public Heartbeat newHeartbeat(String type, String name);

    /**
     * Create a new metric with given type and name.
     * 
     * @param type
     *           metric type
     * @param name
     *           metric name
     */
    public Metric newMetric(String type, String name);

    /**
     * Create a new transaction with given type and name.
     * 
     * @param type
     *           transaction type
     * @param name
     *           transaction name
     */
    public Transaction newTransaction(String type, String name);

    /**
     * Create a forked transaction for child thread.
     * 
     * @param type
     *           transaction type
     * @param name
     *           transaction name
     * @return forked transaction
     */
    public ForkedTransaction newForkedTransaction(String type, String name);

    /**
     * Create a tagged transaction for another process or thread.
     * 
     * @param type
     *           transaction type
     * @param name
     *           transaction name
     * @param tag
     *           tag applied to the transaction
     * @return tagged transaction
     */
    public TaggedTransaction newTaggedTransaction(String type, String name, String tag);

说明

从接口定义上,CAT支持的埋点类型
A. Event
B. Trace
C. Heartbeat
D. Metric
E. Transaction    

5.3.2 消息发射器 MessageProducer

DefaultMessageProducer 是 MessageProducer 的默认实现

public class DefaultMessageProducer implements MessageProducer {
    @Inject
    private MessageManager m_manager;

    @Inject
    private MessageIdFactory m_factory;
    .....

CAT 调用消息生成器

package com.dianping.cat;

public class Cat {
    private static Cat s_instance = new Cat();
    
    public static void logTrace(String type, String name, String status, String nameValuePairs) {
        Cat.getProducer().logTrace(type, name, status, nameValuePairs);
    }
    ....
    

DefaultMessageProducer 具体产生消息

public class DefaultMessageProducer implements MessageProducer {
    @Override
    public void logTrace(String type, String name, String status, String nameValuePairs) {
        if (m_manager.isTraceMode()) {
            Trace trace = newTrace(type, name);

            if (nameValuePairs != null && nameValuePairs.length() > 0) {
                trace.addData(nameValuePairs);
            }

            trace.setStatus(status);
            trace.complete();
        }
    }
    @Override
    public Trace newTrace(String type, String name) {
        if (!m_manager.hasContext()) {
            m_manager.setup();
        }

        if (m_manager.isMessageEnabled()) {
            DefaultTrace trace = new DefaultTrace(type, name, m_manager);

            return trace;
        } else {
            return NullMessage.TRACE;
        }
    }

MessageManager 站点 接收消息

public class DefaultTrace extends AbstractMessage implements Trace {
    private MessageManager m_manager;

    public DefaultTrace(String type, String name) {
        super(type, name);
    }

    public DefaultTrace(String type, String name, MessageManager manager) {
        super(type, name);

        m_manager = manager;
    }

    @Override
    public void complete() {
        setCompleted(true);

        if (m_manager != null) {
            m_manager.add(this);
        }
    }
}

核心代码 m_manager.add(this)

DefaultMessageManager

public class DefaultMessageManager extends ContainerHolder implements MessageManager, Initializable, LogEnabled {

    private ThreadLocal<Context> m_context = new ThreadLocal<Context>();
    @Override
    public void add(Message message) {
        Context ctx = getContext();

        if (ctx != null) {
            ctx.add(message);
        }
    }

    private Context getContext() {
        if (Cat.isInitialized()) {
            Context ctx = m_context.get();

            if (ctx != null) {
                return ctx;
            } else {
                if (m_domain != null) {
                    ctx = new Context(m_domain.getId(), m_hostName, m_domain.getIp());
                } else {
                    ctx = new Context("Unknown", m_hostName, "");
                }

                m_context.set(ctx);
                return ctx;
            }
        }

        return null;
    }
    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 = m_tree.copy();

                    m_tree.setMessageId(null);
                    m_tree.setMessage(null);

                    if (m_totalDurationInMicros > 0) {
                        adjustForTruncatedTransaction((Transaction) tree.getMessage());
                    }

                    manager.flush(tree);
                    return true;
                }
            }

            return false;
        }

5.3.3 消息异步发送

public class DefaultMessageManager extends ContainerHolder implements MessageManager, Initializable, LogEnabled {
    ....
    
    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);
                }
            }
        }
        
        
    class Context {
            ....
    
            public void add(Message message) {
                if (m_stack.isEmpty()) {
                    MessageTree tree = m_tree.copy();
    
                    tree.setMessage(message);
                    flush(tree);
                } else {
                    Transaction parent = m_stack.peek();
    
                    addTransactionChild(message, parent);
                }
            }
            
            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 = m_tree.copy();
    
                        m_tree.setMessageId(null);
                        m_tree.setMessage(null);
    
                        if (m_totalDurationInMicros > 0) {
                            adjustForTruncatedTransaction((Transaction) tree.getMessage());
                        }
    
                        manager.flush(tree);
                        return true;
                    }
                }
    
                return false;
            }

posted @ 2021-02-09 16:59  可可逗豆  阅读(173)  评论(0)    收藏  举报