Package com.taobao.metamorphosis.server.stats

Source Code of com.taobao.metamorphosis.server.stats.StatsManager$TopicStats

/*
* (C) 2007-2012 Alibaba Group Holding Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Authors:
*   wuhua <wq163@163.com> , boyan <killme2008@gmail.com>
*/
package com.taobao.metamorphosis.server.stats;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.taobao.gecko.core.command.Constants;
import com.taobao.gecko.service.RemotingServer;
import com.taobao.metamorphosis.server.Service;
import com.taobao.metamorphosis.server.store.MessageStore;
import com.taobao.metamorphosis.server.store.MessageStoreManager;
import com.taobao.metamorphosis.server.utils.BuildProperties;
import com.taobao.metamorphosis.server.utils.MetaConfig;
import com.taobao.metamorphosis.server.utils.TopicConfig;
import com.taobao.metamorphosis.utils.MetaStatLog;
import com.taobao.metamorphosis.utils.StatConstants;


/**
* ͳ�ƹ�����
*
* @author boyan
* @Date 2011-4-22
* @author wuhua
* @Date 2011-9-9
*
*/
public class StatsManager implements Service {
    private final static Log log = LogFactory.getLog(StatsManager.class);
    private long startupTimestamp;
    private AtomicLong cmdPut;
    private AtomicLong txBegin;
    private AtomicLong txXABegin;
    private AtomicLong txCommit;
    private AtomicLong txRollback;
    private AtomicLong cmdGet;
    private AtomicLong cmdOffset;
    private AtomicLong getMiss;
    private AtomicLong getFailed;
    private AtomicLong putFailed;
    private final MessageStoreManager messageStoreManager;
    private final RemotingServer remotingServer;
    private RealTimeStat realTimeStat;
    private final MetaConfig metaConfig;
    private Set<Pattern> legalTopicPatSet = new HashSet<Pattern>();

    private final boolean startRealTimeStat = Boolean.valueOf(System.getProperty("meta.realtime.stat", "true"));


    public StatsManager(final MetaConfig metaConfig, final MessageStoreManager messageStoreManager,
            final RemotingServer remotingServer) {
        super();
        MetaStatLog.startRealTimeStat = this.startRealTimeStat;
        this.metaConfig = metaConfig;
        this.messageStoreManager = messageStoreManager;
        this.remotingServer = remotingServer;
        this.cmdPut = new AtomicLong(0);
        this.cmdGet = new AtomicLong(0);
        this.cmdOffset = new AtomicLong(0);
        this.getMiss = new AtomicLong(0);
        this.getFailed = new AtomicLong(0);
        this.putFailed = new AtomicLong(0);
        this.txBegin = new AtomicLong(0);
        this.txXABegin = new AtomicLong(0);
        this.txRollback = new AtomicLong(0);
        this.txCommit = new AtomicLong(0);
        this.realTimeStat = new RealTimeStat();
        this.legalTopicPatSet = new HashSet<Pattern>();
        this.metaConfig.addPropertyChangeListener("topics", new PropertyChangeListener() {
            @Override
            public void propertyChange(final PropertyChangeEvent evt) {
                StatsManager.this.makeTopicsPatSet();
            }
        });

        // topicû�б仯,ֻ��ͳ�����Է����˱仯ʱ,��̬�ı�ͳ������
        this.metaConfig.addPropertyChangeListener("topics", new PropertyChangeListener() {
            @Override
            public void propertyChange(final PropertyChangeEvent evt) {
                StatsManager.this.makeTopicsPatSet();
            }
        });

        this.makeTopicsPatSet();
    }


    private void makeTopicsPatSet() {
        final Set<Pattern> set = new HashSet<Pattern>();
        for (final TopicConfig topicConfig : this.metaConfig.getTopicConfigMap().values()) {
            if (topicConfig.isStat()) {
                set.add(Pattern.compile(topicConfig.getTopic().replaceAll("\\*", ".*")));
            }
        }
        this.legalTopicPatSet = set;
    }


    public long getStartupTimestamp() {
        return this.startupTimestamp;
    }


    private boolean isStatTopic(final String topic) {
        for (final Pattern pat : this.legalTopicPatSet) {
            if (pat.matcher(topic).matches()) {
                return true;
            }
        }
        return false;
    }


    public String getStatsInfo(final String item) {
        final StringBuilder sb = new StringBuilder(1024);
        sb.append("STATS\r\n");
        if (StringUtils.isBlank(item)) {
            this.appendSystemStatsInfo(sb);
        }
        else if ("topics".equals(item)) {
            this.appendTopicsInfo(sb);
        }
        else if ("offsets".equals(item)) {
            this.appendOffsetInfo(sb);
        }
        else if ("realtime".equals(item)) {
            this.appendRealTime(sb);
        }
        else if ("help".equals(item)) {
            this.appendHelp(sb);
        }
        else if ("reset".equals(item)) {
            this.realTimeStat.resetStat();
            this.append(sb, "reset", "ok");
        }
        else {
            // ����Ϊ��topic
            this.appendTopic(item, sb);
        }
        sb.append("END\r\n");
        return sb.toString();
    }


    private void appendHelp(final StringBuilder sb) {
        this.append(sb, "*EMPTY*", "Returns broker info.");
        this.append(sb, "help", "Returns help menu.");
        this.append(sb, "topics", "Returns topics statistics detail info.");
        this.append(sb, "offsets", "Returns partitions detail info.");
        this.append(sb, "realtime", "Returns realtime statistics detail info.");
        this.append(sb, "config", "Returns broker's config file content.");
    }


    private void appendTopic(final String item, final StringBuilder sb) {
        final Map<String/* topic */, ConcurrentHashMap<Integer/* partition */, MessageStore>> stores =
                this.messageStoreManager.getMessageStores();
        final ConcurrentHashMap<Integer/* partition */, MessageStore> subMap = stores.get(item);
        long msgCount = 0;
        long bytes = 0;
        int partitionCount = 0;
        int resultCode = 0;// 0:�������topic, 1:���������topic, 2:���������topic����û��Ϣ����,
        if (subMap != null) {
            partitionCount = subMap.size();
            for (final MessageStore msgStore : subMap.values()) {
                if (msgStore != null) {
                    msgCount += msgStore.getMessageCount();
                    bytes += msgStore.getSizeInBytes();
                }
            }
        }
        else {
            if (!this.metaConfig.getTopics().contains(item)) {
                resultCode = 1;
            }
            else {
                resultCode = 2;
            }
        }
        this.append(sb, item);
        this.append(sb, "resultCode", resultCode);
        this.append(sb, "partitions", partitionCount);
        this.append(sb, "message_count", msgCount);
        this.append(sb, "bytes", bytes);
        this.append(sb, "topic_realtime_put",
            this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.CMD_PUT, item));
        this.append(sb, "topic_realtime_get",
            this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.CMD_GET, item));
        this.append(sb, "topic_realtime_offset",
            this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.CMD_OFFSET, item));
        this.append(sb, "topic_realtime_get_miss",
            this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.GET_MISS, item));
        this.append(sb, "topic_realtime_put_failed",
            this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.PUT_FAILED, item));
        this.append(sb, "topic_realtime_message_size",
            this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.MESSAGE_SIZE, item));
    }


    private void appendRealTime(final StringBuilder sb) {
        this.append(sb, "realtime_put", this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.CMD_PUT));
        this.append(sb, "realtime_get", this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.CMD_GET));
        this.append(sb, "realtime_offset", this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.CMD_OFFSET));
        this.append(sb, "realtime_get_miss", this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.GET_MISS));
        this.append(sb, "realtime_put_failed", this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.PUT_FAILED));
        this.append(sb, "realtime_message_size",
            this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.MESSAGE_SIZE));
    }


    private void appendOffsetInfo(final StringBuilder sb) {
        final Map<String/* topic */, ConcurrentHashMap<Integer/* partition */, MessageStore>> stores =
                this.messageStoreManager.getMessageStores();
        for (final Map.Entry<String, ConcurrentHashMap<Integer/* partition */, MessageStore>> entry : stores.entrySet()) {
            final String topic = entry.getKey();
            final ConcurrentHashMap<Integer/* partition */, MessageStore> subMap = entry.getValue();
            if (subMap != null) {
                for (final Map.Entry<Integer, MessageStore> subEntry : subMap.entrySet()) {
                    final int partition = subEntry.getKey();
                    final MessageStore store = subEntry.getValue();
                    this.append(sb, topic, "part", partition, "min_offset", store.getMinOffset(), "max_offset",
                        store.getMaxOffset());
                }
            }
        }
    }

    public static class TopicStats {
        private final String topic;
        private final TopicConfig topicConfig;
        private final long messageCount;
        private final long messageBytes;
        private String puts = "NO";
        private String gets = "NO";
        private String getMissed = "NO";
        private String putFailed = "NO";
        private int partitions;


        public TopicStats(String topic, int partitions, TopicConfig topicConfig, long messageCount, long messageBytes,
                String realTimePut, String realTimeGet, String realTimeGetMissed, String realTimePutFailed) {
            super();
            this.topic = topic;
            this.partitions = partitions;
            this.topicConfig = topicConfig;
            this.messageCount = messageCount;
            this.messageBytes = messageBytes;
            if (realTimePut != null) {
                this.puts = realTimePut;
            }
            if (realTimeGet != null) {
                this.gets = realTimeGet;
            }
            if (realTimeGetMissed != null) {
                this.getMissed = realTimeGetMissed;
            }
            if (realTimePutFailed != null) {
                this.putFailed = realTimePutFailed;
            }
        }


        public int getPartitions() {
            return this.partitions;
        }


        public void setPartitions(int partitions) {
            this.partitions = partitions;
        }


        public String getTopic() {
            return this.topic;
        }


        public TopicConfig getTopicConfig() {
            return this.topicConfig;
        }


        public long getMessageCount() {
            return this.messageCount;
        }


        public String getAvgMsgSize() {
            if (this.messageCount == 0) {
                return "N/A";
            }
            else {
                return String.valueOf(Math.round((double) this.getMessageBytes() / this.getMessageCount()));
            }
        }


        public long getMessageBytes() {
            return this.messageBytes;
        }


        public String getPuts() {
            return this.puts;
        }


        public void setPuts(String put) {
            this.puts = put;
        }


        public String getGets() {
            return this.gets;
        }


        public void setGets(String get) {
            this.gets = get;
        }


        public String getGetMissed() {
            return this.getMissed;
        }


        public void setGetMissed(String getMissed) {
            this.getMissed = getMissed;
        }


        public String getPutFailed() {
            return this.putFailed;
        }


        public void setPutFailed(String putFailed) {
            this.putFailed = putFailed;
        }


        @Override
        public String toString() {
            return "TopicStats [topic=" + this.topic + ", topicConfig=" + this.topicConfig + ", messageCount="
                    + this.messageCount + ", messageBytes=" + this.messageBytes + ", puts=" + this.puts + ", gets="
                    + this.gets + ", getMissed=" + this.getMissed + ", putFailed=" + this.putFailed + ", partitions="
                    + this.partitions + "]";
        }

    }


    public TopicStats getTopicStats(String topic) {
        final ConcurrentHashMap<Integer/* partition */, MessageStore> subMap =
                this.messageStoreManager.getMessageStores().get(topic);
        if (subMap != null) {
            long sum = 0;
            long bytes = 0;
            int partitionCount = 0;
            if (subMap != null) {
                partitionCount = subMap.size();
                for (final MessageStore msgStore : subMap.values()) {
                    if (msgStore != null) {
                        sum += msgStore.getMessageCount();
                        bytes += msgStore.getSizeInBytes();
                    }
                }
            }
            TopicConfig topicConfig = this.metaConfig.getTopicConfig(topic);
            TopicStats stats =
                    new TopicStats(topic, partitionCount, topicConfig, sum, bytes,
                        this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.CMD_PUT, topic),
                        this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.CMD_GET, topic),
                        this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.GET_MISS, topic),
                        this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.PUT_FAILED, topic));
            return stats;
        }
        else {
            return null;
        }
    }


    public List<TopicStats> getTopicsStats() {
        List<TopicStats> result = new ArrayList<StatsManager.TopicStats>();
        final Map<String/* topic */, ConcurrentHashMap<Integer/* partition */, MessageStore>> stores =
                this.messageStoreManager.getMessageStores();
        for (final Map.Entry<String, ConcurrentHashMap<Integer/* partition */, MessageStore>> entry : stores.entrySet()) {
            final String topic = entry.getKey();
            final ConcurrentHashMap<Integer/* partition */, MessageStore> subMap = entry.getValue();
            long sum = 0;
            long bytes = 0;
            int partitionCount = 0;
            if (subMap != null) {
                partitionCount = subMap.size();
                for (final MessageStore msgStore : subMap.values()) {
                    if (msgStore != null) {
                        sum += msgStore.getMessageCount();
                        bytes += msgStore.getSizeInBytes();
                    }
                }
            }
            TopicConfig topicConfig = this.metaConfig.getTopicConfig(topic);
            TopicStats stats =
                    new TopicStats(topic, partitionCount, topicConfig, sum, bytes,
                        this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.CMD_PUT, topic),
                        this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.CMD_GET, topic),
                        this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.GET_MISS, topic),
                        this.realTimeStat.getGroupedRealTimeStatResult(StatConstants.PUT_FAILED, topic));
            result.add(stats);
        }
        return result;
    }


    private void appendTopicsInfo(final StringBuilder sb) {
        for (TopicStats stats : this.getTopicsStats()) {
            this.append(sb, stats.getTopic(), "partitions", stats.getPartitions(), "message_count", stats
                .getMessageCount(), "message_bytes", stats.getMessageBytes(), "accept_publish", stats.getTopicConfig()
                .isAcceptPublish(), "accept_subscribe", stats.getTopicConfig().isAcceptSubscribe());
        }
        final Map<String/* topic */, ConcurrentHashMap<Integer/* partition */, MessageStore>> stores =
                this.messageStoreManager.getMessageStores();
        List<String> configTopics = this.metaConfig.getTopics();
        for (String topic : configTopics) {
            if (!stores.containsKey(topic)) {
                this.append(sb, topic, "*Empty*");
            }
        }
    }


    RealTimeStat getRealTimeStat() {
        return this.realTimeStat;
    }


    private void appendSystemStatsInfo(final StringBuilder sb) {
        this.append(sb, "pid", this.getPid());
        this.append(sb, "broker_id", this.metaConfig.getBrokerId());
        this.append(sb, "port", this.getServerPort());
        this.append(sb, "uptime", this.getUpTime());
        this.append(sb, "version", this.getVersion());
        this.append(sb, "slave", this.metaConfig.isSlave());
        this.append(sb, "curr_connections", this.getCurrentConnectionCount());
        this.append(sb, "threads", this.getCurrentThreads());
        this.append(sb, "cmd_put", this.cmdPut.get());
        this.append(sb, "cmd_get", this.cmdGet.get());
        this.append(sb, "cmd_offset", this.cmdOffset.get());
        this.append(sb, "tx_begin", this.txBegin.get());
        this.append(sb, "tx_xa_begin", this.txXABegin.get());
        this.append(sb, "tx_commit", this.txCommit.get());
        this.append(sb, "tx_rollback", this.txRollback.get());
        this.append(sb, StatConstants.GET_MISS, this.getMiss.get());
        this.append(sb, StatConstants.PUT_FAILED, this.putFailed.get());
        this.append(sb, "total_messages", this.getTotalMessages());
        this.append(sb, "topics", this.getTopicCount());
        this.append(sb, "config_checksum", this.metaConfig.getConfigFileChecksum());
    }


    void append(final StringBuilder sb, final Object... values) {
        boolean wasFirst = true;
        for (final Object value : values) {
            if (wasFirst) {
                sb.append(value);
                wasFirst = false;
            }
            else {
                sb.append(" ").append(value);
            }
        }
        sb.append("\r\n");
    }


    public long getTotalMessages() {
        return this.messageStoreManager.getTotalMessagesCount();
    }


    public int getTopicCount() {
        return this.messageStoreManager.getTopicCount();
    }


    public int getCurrentConnectionCount() {
        return this.remotingServer.getConnectionCount(Constants.DEFAULT_GROUP);
    }


    public long getCmdPuts() {
        return this.cmdPut.get();
    }


    public long getCmdPutFailed() {
        return this.putFailed.get();
    }


    public long getCmdGets() {
        return this.cmdGet.get();
    }


    public long getCmdOffsets() {
        return this.cmdOffset.get();
    }


    public long getCmdGetMiss() {
        return this.getMiss.get();
    }


    public long getCmdGetFailed() {
        return this.getFailed.get();
    }


    public String getPid() {
        final String name = ManagementFactory.getRuntimeMXBean().getName();
        if (name.contains("@")) {
            return name.split("@")[0];
        }
        return name;
    }


    public long getUpTime() {
        return (System.currentTimeMillis() - this.startupTimestamp) / 1000;
    }


    public String getVersion() {
        return BuildProperties.VERSION;
    }


    public int getCurrentThreads() {
        return ManagementFactory.getThreadMXBean().getThreadCount();
    }


    public int getServerPort() {
        return this.remotingServer.getInetSocketAddress().getPort();
    }


    public void statsPut(final String topic, String partition, final int c) {
        this.statsRealtimePut(c);
        if (this.isStatTopic(topic)) {
            MetaStatLog.addStatValue2(null, StatConstants.CMD_PUT, topic, partition, c);
        }
    }


    public void statsRealtimePut(final int c) {
        this.cmdPut.addAndGet(c);
    }


    public void statsGet(final String topic, final String group, final int c) {
        this.cmdGet.addAndGet(c);
        if (this.isStatTopic(topic)) {
            MetaStatLog.addStatValue2(null, StatConstants.CMD_GET, topic, group, c);
        }
    }


    public void statsOffset(final String topic, final String group, final int c) {
        this.cmdOffset.addAndGet(c);
        if (this.isStatTopic(topic)) {
            MetaStatLog.addStatValue2(null, StatConstants.CMD_OFFSET, topic, group, c);
        }
    }


    public void statsGetMiss(final String topic, final String group, final int c) {
        this.getMiss.addAndGet(c);
        if (this.isStatTopic(topic)) {
            MetaStatLog.addStatValue2(null, StatConstants.GET_MISS, topic, group, c);
        }
    }


    public void statsPutFailed(final String topic, final String partition, final int c) {
        this.putFailed.addAndGet(c);
        if (this.isStatTopic(topic)) {
            MetaStatLog.addStatValue2(null, StatConstants.PUT_FAILED, topic, partition, c);
        }
    }


    public void statsGetFailed(final String topic, final String group, final int c) {
        this.getFailed.addAndGet(c);
        if (this.isStatTopic(topic)) {
            MetaStatLog.addStatValue2(null, StatConstants.GET_FAILED, topic, group, c);
        }
    }


    public void statsMessageSize(final String topic, final int c) {
        if (this.isStatTopic(topic)) {
            MetaStatLog.addStatValue2(null, StatConstants.MESSAGE_SIZE, topic, c);
        }
    }


    public void statsTxBegin(final boolean isXA, final int c) {
        this.txBegin.addAndGet(c);
        if (isXA) {
            this.txXABegin.addAndGet(c);
        }
    }


    public void statsTxCommit(final int c) {
        this.txCommit.addAndGet(c);
    }


    public void statsTxRollback(final int c) {
        this.txRollback.addAndGet(c);
    }


    @Override
    public void dispose() {
        this.cmdPut = new AtomicLong(0);
        this.cmdGet = new AtomicLong(0);
        this.cmdOffset = new AtomicLong(0);
        this.getMiss = new AtomicLong(0);
        this.getFailed = new AtomicLong(0);
        this.putFailed = new AtomicLong(0);
        this.txBegin = new AtomicLong(0);
        this.txXABegin = new AtomicLong(0);
        this.txRollback = new AtomicLong(0);
        this.txCommit = new AtomicLong(0);
        this.realTimeStat.stop();
        this.realTimeStat = new RealTimeStat();
    }


    /*
     * (non-Javadoc)
     *
     * @see com.taobao.metamorphosis.server.Service#init()
     */
    @Override
    public void init() {
        this.startupTimestamp = System.currentTimeMillis();
        this.realTimeStat.start();
    }

}
TOP

Related Classes of com.taobao.metamorphosis.server.stats.StatsManager$TopicStats

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.