├── screenshot ├── menu.png ├── cluster.png ├── cusumer.png ├── cusumer1.png ├── cusumer2.png └── topiclist.png ├── src └── main │ ├── resources │ ├── app.properties │ ├── logback.xml │ └── spring │ │ ├── context.xml │ │ └── mvc.xml │ ├── webapp │ ├── META-INF │ │ └── context.xml │ ├── index.jsp │ ├── css │ │ └── style.css │ └── WEB-INF │ │ ├── web.xml │ │ └── jsp │ │ ├── topiclist.jsp │ │ ├── topicstats.jsp │ │ ├── clusterlist.jsp │ │ └── consumerprogress.jsp │ └── java │ └── com │ └── alibaba │ └── rocketmq │ └── web │ ├── util │ └── LoggerUtil.java │ └── rocketmq │ └── web │ ├── bo │ ├── TopicStatsBo.java │ ├── TotalConsumerProgress.java │ ├── ClusterInfoBo.java │ └── SingleConsumerProgress.java │ ├── controller │ └── RocketMQController.java │ └── service │ └── RocketMQService.java ├── README.md ├── nb-configuration.xml └── pom.xml /screenshot/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wang55www/rocketmq-web/HEAD/screenshot/menu.png -------------------------------------------------------------------------------- /screenshot/cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wang55www/rocketmq-web/HEAD/screenshot/cluster.png -------------------------------------------------------------------------------- /screenshot/cusumer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wang55www/rocketmq-web/HEAD/screenshot/cusumer.png -------------------------------------------------------------------------------- /screenshot/cusumer1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wang55www/rocketmq-web/HEAD/screenshot/cusumer1.png -------------------------------------------------------------------------------- /screenshot/cusumer2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wang55www/rocketmq-web/HEAD/screenshot/cusumer2.png -------------------------------------------------------------------------------- /screenshot/topiclist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wang55www/rocketmq-web/HEAD/screenshot/topiclist.png -------------------------------------------------------------------------------- /src/main/resources/app.properties: -------------------------------------------------------------------------------- 1 | #=== rocket mq config === 2 | rocketmq.namesrv.addr=192.168.152.103:9876;192.168.152.104:9876 3 | -------------------------------------------------------------------------------- /src/main/webapp/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rocketmq-web 2 | ============= 3 | 项目说明:rocketmq web版控制台 4 | 5 | namesrv设置方法: 6 | 一下几种方法按照优先级从高到低排序 7 | * 启动时设置 jvm 的启动参数 rocketmq.namesrv.addr 8 | * 设置系统的环境变量 NAMESRV_ADDR 9 | * 设置项目中 src/main/resources/app.properties 中 rocketmq.namesrv.addr属性 10 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | [%d %-5level %thread %class{0}:%line] %msg%n 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html" pageEncoding="UTF-8"%> 2 | 4 | 5 | 6 | 7 | 8 | RocketMQ 监控 9 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/webapp/css/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 wangxiangnan. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | /* 17 | Created on : 2014-9-11, 17:51:23 18 | Author : wangxiangnan 19 | */ 20 | 21 | body{ 22 | font-size: 14px; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/resources/spring/context.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/rocketmq/web/util/LoggerUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 wangxiangnan. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alibaba.rocketmq.web.util; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | /** 23 | * 24 | * @author xiangnan.wang@ipinyou.com 25 | */ 26 | public class LoggerUtil { 27 | 28 | private static Logger logger=LoggerFactory.getLogger("rocket-web"); 29 | 30 | public static Logger getLogger(){ 31 | return logger; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | rocketmq-web 7 | 8 | 9 | encoding 10 | org.springframework.web.filter.CharacterEncodingFilter 11 | 12 | encoding 13 | utf-8 14 | 15 | 16 | 17 | 18 | encoding 19 | Spring MVC Dispatcher Servlet 20 | 21 | 22 | 23 | Spring MVC Dispatcher Servlet 24 | org.springframework.web.servlet.DispatcherServlet 25 | 26 | contextConfigLocation 27 | classpath*:spring/*.xml 28 | 29 | 1 30 | 31 | 32 | 33 | Spring MVC Dispatcher Servlet 34 | / 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/topiclist.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Document : clusterlist 3 | Created on : 2014-9-10, 17:12:03 4 | Author : wangxiangnan 5 | --%> 6 | 7 | <%@page contentType="text/html" pageEncoding="UTF-8"%> 8 | <%@page isELIgnored="false" %> 9 | <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 10 | <%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 11 | 12 | 13 | 14 | 15 | 16 | topicList 17 | 18 | 19 | 20 |

topic列表

21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
topic
${topic}
35 |
36 | 返回 37 | 38 | 39 | -------------------------------------------------------------------------------- /nb-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | 1.6-web 17 | Tomcat 18 | apache20 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/main/resources/spring/mvc.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/topicstats.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Document : clusterlist 3 | Created on : 2014-9-10, 17:12:03 4 | Author : wangxiangnan 5 | --%> 6 | 7 | <%@page contentType="text/html" pageEncoding="UTF-8"%> 8 | <%@page isELIgnored="false" %> 9 | <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 10 | <%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 11 | 12 | 13 | 14 | 15 | 16 | topicStats 17 | 18 | 19 | 20 |

topic状态信息

21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
broker名称队列ID最小偏移量最大偏移量最近更新时间
${ts.brokerName}${ts.qid}${ts.minOffset}${ts.maxOffset}
43 |
44 | 返回 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/clusterlist.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Document : clusterlist 3 | Created on : 2014-9-10, 17:12:03 4 | Author : wangxiangnan 5 | --%> 6 | 7 | <%@page contentType="text/html" pageEncoding="UTF-8"%> 8 | <%@page isELIgnored="false" %> 9 | <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 10 | <%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 11 | 12 | 13 | 14 | 15 | 16 | cluster list 17 | 18 | 19 | 20 |

集群列表

21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
集群名称broker名称brokerIdip版本输入TPS输出TPS
${cib.clusterName}${cib.brokerName}${cib.bid}${cib.addr}${cib.version}
47 |
48 | 返回 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/rocketmq/web/rocketmq/web/bo/TopicStatsBo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 wangxiangnan. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alibaba.rocketmq.web.rocketmq.web.bo; 18 | 19 | import java.util.Date; 20 | 21 | /** 22 | * 23 | * @author xiangnan.wang@ipinyou.com 24 | */ 25 | public class TopicStatsBo { 26 | 27 | private String brokerName; 28 | 29 | private int qid; 30 | 31 | private long minOffset; 32 | 33 | private long maxOffset; 34 | 35 | private Date lastUpdate; 36 | 37 | public String getBrokerName() { 38 | return brokerName; 39 | } 40 | 41 | public void setBrokerName(String brokerName) { 42 | this.brokerName = brokerName; 43 | } 44 | 45 | public int getQid() { 46 | return qid; 47 | } 48 | 49 | public void setQid(int qid) { 50 | this.qid = qid; 51 | } 52 | 53 | public long getMinOffset() { 54 | return minOffset; 55 | } 56 | 57 | public void setMinOffset(long minOffset) { 58 | this.minOffset = minOffset; 59 | } 60 | 61 | public long getMaxOffset() { 62 | return maxOffset; 63 | } 64 | 65 | public void setMaxOffset(long maxOffset) { 66 | this.maxOffset = maxOffset; 67 | } 68 | 69 | public Date getLastUpdate() { 70 | return lastUpdate; 71 | } 72 | 73 | public void setLastUpdate(Date lastUpdate) { 74 | this.lastUpdate = lastUpdate; 75 | } 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/rocketmq/web/rocketmq/web/bo/TotalConsumerProgress.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 wangxiangnan. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alibaba.rocketmq.web.rocketmq.web.bo; 18 | 19 | /** 20 | * 21 | * @author xiangnan.wang@ipinyou.com 22 | */ 23 | public class TotalConsumerProgress implements Comparable{ 24 | 25 | private String group; 26 | 27 | private int count; 28 | 29 | private String version; 30 | 31 | private String type; 32 | 33 | private long tps; 34 | 35 | private long diff; 36 | 37 | 38 | public String getGroup() { 39 | return group; 40 | } 41 | 42 | public void setGroup(String group) { 43 | this.group = group; 44 | } 45 | 46 | public int getCount() { 47 | return count; 48 | } 49 | 50 | public void setCount(int count) { 51 | this.count = count; 52 | } 53 | 54 | public String getVersion() { 55 | return version; 56 | } 57 | 58 | public void setVersion(String version) { 59 | this.version = version; 60 | } 61 | 62 | public String getType() { 63 | return type; 64 | } 65 | 66 | public void setType(String type) { 67 | this.type = type; 68 | } 69 | 70 | public long getTps() { 71 | return tps; 72 | } 73 | 74 | public void setTps(long tps) { 75 | this.tps = tps; 76 | } 77 | 78 | public long getDiff() { 79 | return diff; 80 | } 81 | 82 | public void setDiff(long diff) { 83 | this.diff = diff; 84 | } 85 | 86 | @Override 87 | public int compareTo(TotalConsumerProgress o) { 88 | if (this.count != o.count) { 89 | return o.count - this.count; 90 | } 91 | 92 | return (int) (o.diff - diff); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/rocketmq/web/rocketmq/web/bo/ClusterInfoBo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 wangxiangnan. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alibaba.rocketmq.web.rocketmq.web.bo; 18 | 19 | /** 20 | * 21 | * @author xiangnan.wang@ipinyou.com 22 | */ 23 | public class ClusterInfoBo { 24 | 25 | private String clusterName; 26 | 27 | private String brokerName; 28 | 29 | private String bid; 30 | 31 | private String addr; 32 | 33 | private String version; 34 | 35 | private double inTps; 36 | 37 | private double outTps; 38 | 39 | public String getClusterName() { 40 | return clusterName; 41 | } 42 | 43 | public void setClusterName(String clusterName) { 44 | this.clusterName = clusterName; 45 | } 46 | 47 | public String getBrokerName() { 48 | return brokerName; 49 | } 50 | 51 | public void setBrokerName(String brokerName) { 52 | this.brokerName = brokerName; 53 | } 54 | 55 | public String getBid() { 56 | return bid; 57 | } 58 | 59 | public void setBid(String bid) { 60 | this.bid = bid; 61 | } 62 | 63 | public String getAddr() { 64 | return addr; 65 | } 66 | 67 | public void setAddr(String addr) { 68 | this.addr = addr; 69 | } 70 | 71 | public String getVersion() { 72 | return version; 73 | } 74 | 75 | public void setVersion(String version) { 76 | this.version = version; 77 | } 78 | 79 | public double getInTps() { 80 | return inTps; 81 | } 82 | 83 | public void setInTps(double inTps) { 84 | this.inTps = inTps; 85 | } 86 | 87 | public double getOutTps() { 88 | return outTps; 89 | } 90 | 91 | public void setOutTps(double outTps) { 92 | this.outTps = outTps; 93 | } 94 | 95 | @Override 96 | public String toString() { 97 | return "ClusterInfoBo{" + "clusterName=" + clusterName + ", brokerName=" + brokerName + ", bid=" + bid + ", addr=" + addr + ", version=" + version + ", inTps=" + inTps + ", outTps=" + outTps + '}'; 98 | } 99 | 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/consumerprogress.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Document : clusterlist 3 | Created on : 2014-9-10, 17:12:03 4 | Author : wangxiangnan 5 | --%> 6 | 7 | <%@page contentType="text/html" pageEncoding="UTF-8"%> 8 | <%@page isELIgnored="false" %> 9 | <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 10 | <%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 11 | 12 | 13 | 14 | 15 | 16 | consumerprogress 17 | 18 | 19 | 20 |

消费进度

21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
消费组名称客户端连接数客户端版本消费类型TPS进度差
${cp.group}${cp.count}${cp.version}${cp.type}${cp.tps}${cp.diff}
47 |
48 | 49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 |
topicbrocker名称队列IDbroker偏移量消费偏移量进度差
${cd.topic}${cd.brokerName}${cd.mqId}${cd.brokerOffset}${cd.consumerOffset}${cd.diff}
75 |
76 |
77 | 返回 78 | 返回 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/rocketmq/web/rocketmq/web/bo/SingleConsumerProgress.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 wangxiangnan. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.rocketmq.web.rocketmq.web.bo; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | * 22 | * @author xiangnan.wang@ipinyou.com 23 | */ 24 | public class SingleConsumerProgress { 25 | 26 | private long tps; 27 | 28 | private long totalDiff; 29 | 30 | private List cdList; 31 | 32 | public long getTps() { 33 | return tps; 34 | } 35 | 36 | public void setTps(long tps) { 37 | this.tps = tps; 38 | } 39 | 40 | public long getTotalDiff() { 41 | return totalDiff; 42 | } 43 | 44 | public void setTotalDiff(long totalDiff) { 45 | this.totalDiff = totalDiff; 46 | } 47 | 48 | public List getCdList() { 49 | return cdList; 50 | } 51 | 52 | public void setCdList(List cdList) { 53 | this.cdList = cdList; 54 | } 55 | 56 | public static class ConsumerDetail { 57 | 58 | private String topic; 59 | 60 | private String brokerName; 61 | 62 | private int mqId; 63 | 64 | private long brokerOffset; 65 | 66 | private long consumerOffset; 67 | 68 | private long diff; 69 | 70 | public String getTopic() { 71 | return topic; 72 | } 73 | 74 | public void setTopic(String topic) { 75 | this.topic = topic; 76 | } 77 | 78 | public String getBrokerName() { 79 | return brokerName; 80 | } 81 | 82 | public void setBrokerName(String brokerName) { 83 | this.brokerName = brokerName; 84 | } 85 | 86 | public int getMqId() { 87 | return mqId; 88 | } 89 | 90 | public void setMqId(int mqId) { 91 | this.mqId = mqId; 92 | } 93 | 94 | public long getBrokerOffset() { 95 | return brokerOffset; 96 | } 97 | 98 | public void setBrokerOffset(long brokerOffset) { 99 | this.brokerOffset = brokerOffset; 100 | } 101 | 102 | public long getConsumerOffset() { 103 | return consumerOffset; 104 | } 105 | 106 | public void setConsumerOffset(long consumerOffset) { 107 | this.consumerOffset = consumerOffset; 108 | } 109 | 110 | public long getDiff() { 111 | return diff; 112 | } 113 | 114 | public void setDiff(long diff) { 115 | this.diff = diff; 116 | } 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/rocketmq/web/rocketmq/web/controller/RocketMQController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 wangxiangnan. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alibaba.rocketmq.web.rocketmq.web.controller; 18 | 19 | import com.alibaba.rocketmq.web.rocketmq.web.bo.ClusterInfoBo; 20 | import com.alibaba.rocketmq.web.rocketmq.web.bo.SingleConsumerProgress; 21 | import com.alibaba.rocketmq.web.rocketmq.web.bo.TopicStatsBo; 22 | import com.alibaba.rocketmq.web.rocketmq.web.bo.TotalConsumerProgress; 23 | import com.alibaba.rocketmq.web.rocketmq.web.service.RocketMQService; 24 | import java.util.Collections; 25 | import java.util.List; 26 | import java.util.Set; 27 | import org.springframework.beans.factory.annotation.Autowired; 28 | import org.springframework.stereotype.Controller; 29 | import org.springframework.web.bind.annotation.PathVariable; 30 | import org.springframework.web.bind.annotation.RequestMapping; 31 | import org.springframework.web.servlet.ModelAndView; 32 | 33 | /** 34 | * 35 | * @author xiangnan.wang@ipinyou.com 36 | */ 37 | @Controller 38 | public class RocketMQController { 39 | 40 | @Autowired 41 | private RocketMQService rmqService; 42 | 43 | @RequestMapping("/clusterList") 44 | public ModelAndView getClusterList(){ 45 | List cibl=rmqService.getClusterInfo(); 46 | ModelAndView mv=new ModelAndView(); 47 | mv.setViewName("clusterlist"); 48 | mv.addObject("cibl", cibl); 49 | return mv; 50 | } 51 | 52 | @RequestMapping("/consumerProgress/{group}") 53 | public ModelAndView consumerProgress(@PathVariable String group){ 54 | ModelAndView mv=new ModelAndView(); 55 | SingleConsumerProgress scp=rmqService.consumerProgress(group); 56 | mv.addObject("result", scp); 57 | mv.addObject("all",false); 58 | mv.setViewName("consumerprogress"); 59 | return mv; 60 | } 61 | 62 | @RequestMapping("/consumerProgress") 63 | public ModelAndView consumerProgress(){ 64 | ModelAndView mv=new ModelAndView(); 65 | List tcpList=rmqService.consumerProgress(); 66 | Collections.sort(tcpList); 67 | mv.addObject("result", tcpList); 68 | mv.addObject("all",true); 69 | mv.setViewName("consumerprogress"); 70 | return mv; 71 | } 72 | 73 | @RequestMapping("topicList") 74 | public ModelAndView topicList(){ 75 | ModelAndView mv=new ModelAndView(); 76 | Set topicSet=rmqService.getTopics(); 77 | mv.addObject("result",topicSet); 78 | mv.setViewName("topiclist"); 79 | return mv; 80 | } 81 | 82 | @RequestMapping("topicStats/{topic}") 83 | public ModelAndView topicStats(@PathVariable String topic){ 84 | ModelAndView mv=new ModelAndView(); 85 | List tsbList=rmqService.getTopicStats(topic); 86 | mv.addObject("result", tsbList); 87 | mv.setViewName("topicstats"); 88 | return mv; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.alibaba.rocketmq.web 6 | rocketmq-web 7 | 1.0-SNAPSHOT 8 | war 9 | 10 | rocketmq-web 11 | 12 | 13 | ${project.build.directory}/endorsed 14 | UTF-8 15 | 3.1.8 16 | 17 | 18 | 19 | 20 | org.springframework 21 | spring-webmvc 22 | 3.2.3.RELEASE 23 | 24 | 25 | com.alibaba.rocketmq 26 | rocketmq-tools 27 | ${rocketmq.version} 28 | 29 | 30 | javax.servlet 31 | jstl 32 | 1.2 33 | 34 | 35 | javax 36 | javaee-web-api 37 | 6.0 38 | provided 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-compiler-plugin 47 | 2.3.2 48 | 49 | 1.6 50 | 1.6 51 | 52 | ${endorsed.dir} 53 | 54 | 55 | 56 | 57 | org.apache.maven.plugins 58 | maven-war-plugin 59 | 2.1.1 60 | 61 | false 62 | 63 | 64 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/rocketmq/web/rocketmq/web/service/RocketMQService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 wangxiangnan. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alibaba.rocketmq.web.rocketmq.web.service; 18 | 19 | import com.alibaba.rocketmq.common.MQVersion; 20 | import com.alibaba.rocketmq.common.MixAll; 21 | import com.alibaba.rocketmq.common.admin.ConsumeStats; 22 | import com.alibaba.rocketmq.common.admin.OffsetWrapper; 23 | import com.alibaba.rocketmq.common.admin.TopicOffset; 24 | import com.alibaba.rocketmq.common.admin.TopicStatsTable; 25 | import com.alibaba.rocketmq.common.message.MessageQueue; 26 | import com.alibaba.rocketmq.common.protocol.body.ClusterInfo; 27 | import com.alibaba.rocketmq.common.protocol.body.ConsumerConnection; 28 | import com.alibaba.rocketmq.common.protocol.body.TopicList; 29 | import com.alibaba.rocketmq.common.protocol.heartbeat.ConsumeType; 30 | import com.alibaba.rocketmq.common.protocol.route.BrokerData; 31 | import com.alibaba.rocketmq.tools.admin.DefaultMQAdminExt; 32 | import com.alibaba.rocketmq.web.rocketmq.web.bo.ClusterInfoBo; 33 | import com.alibaba.rocketmq.web.rocketmq.web.bo.SingleConsumerProgress; 34 | import com.alibaba.rocketmq.web.rocketmq.web.bo.TopicStatsBo; 35 | import com.alibaba.rocketmq.web.rocketmq.web.bo.TotalConsumerProgress; 36 | import com.alibaba.rocketmq.web.util.LoggerUtil; 37 | import java.util.ArrayList; 38 | import java.util.Collections; 39 | import java.util.Date; 40 | import java.util.LinkedHashSet; 41 | import java.util.LinkedList; 42 | import java.util.List; 43 | import java.util.Map; 44 | import java.util.Set; 45 | import javax.annotation.PostConstruct; 46 | import javax.annotation.PreDestroy; 47 | import org.springframework.beans.factory.annotation.Value; 48 | import org.springframework.stereotype.Service; 49 | 50 | /** 51 | * 初始化相关业务 52 | * @author xiangnan.wang@ipinyou.com 53 | */ 54 | @Service 55 | public class RocketMQService { 56 | 57 | @Value("${rocketmq.namesrv.addr}") 58 | private String nameAddr; 59 | 60 | private DefaultMQAdminExt adminExt; 61 | 62 | @PostConstruct 63 | private void initRocketMQEnv(){ 64 | adminExt = new DefaultMQAdminExt(); 65 | if(adminExt.getNamesrvAddr()==null||adminExt.getNamesrvAddr().length()>0){ 66 | adminExt.setNamesrvAddr(nameAddr); 67 | } 68 | adminExt.setInstanceName(Long.toString(System.currentTimeMillis())); 69 | try { 70 | adminExt.start(); 71 | } catch (Exception ex) { 72 | LoggerUtil.getLogger().error("initRocketMQEnv error",ex); 73 | } 74 | } 75 | 76 | /** 77 | * 获取集群信息 78 | * @return 79 | */ 80 | public List getClusterInfo(){ 81 | List cibl=new ArrayList(); 82 | try { 83 | ClusterInfo cinfo = adminExt.examineBrokerClusterInfo(); 84 | for(Map.Entry> entry:cinfo.getClusterAddrTable().entrySet()){ 85 | String clusterName=entry.getKey(); 86 | for(String brokerName:entry.getValue()){ 87 | BrokerData bd=cinfo.getBrokerAddrTable().get(brokerName); 88 | for(Map.Entry bentry:bd.getBrokerAddrs().entrySet()){ 89 | Map rmap=adminExt.fetchBrokerRuntimeStats(bentry.getValue()).getTable(); 90 | double inTps=0d; 91 | double outTps=0d; 92 | try{ 93 | { 94 | String tpses=rmap.get("putTps"); 95 | String[] tpsArr=tpses.split(" "); 96 | if(tpsArr!=null&&tpsArr.length>0){ 97 | inTps=Double.parseDouble(tpsArr[0]); 98 | } 99 | } 100 | { 101 | String tpses=rmap.get("getTransferedTps"); 102 | String[] tpsArr=tpses.split(" "); 103 | if(tpsArr!=null&&tpsArr.length>0){ 104 | outTps=Double.parseDouble(tpsArr[0]); 105 | } 106 | } 107 | }catch(Exception e){} 108 | ClusterInfoBo cib=new ClusterInfoBo(); 109 | cib.setClusterName(clusterName); 110 | cib.setBrokerName(brokerName); 111 | cib.setInTps(inTps); 112 | cib.setOutTps(outTps); 113 | cib.setBid(bentry.getKey().toString()); 114 | cib.setVersion(rmap.get("brokerVersionDesc")); 115 | cib.setAddr(bentry.getValue()); 116 | cibl.add(cib); 117 | } 118 | } 119 | } 120 | } catch (Exception ex) { 121 | LoggerUtil.getLogger().error("getClusterInfo", ex); 122 | } 123 | return cibl; 124 | } 125 | 126 | /** 127 | * 获取消费进度信息所有的消费组 128 | * @return 129 | */ 130 | public List consumerProgress(){ 131 | List tcprogressl=new ArrayList(); 132 | try { 133 | TopicList topicl=adminExt.fetchAllTopicList(); 134 | for(String topic:topicl.getTopicList()){ 135 | if(topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)){ 136 | String consumerGroup=topic.substring(MixAll.RETRY_GROUP_TOPIC_PREFIX.length()); 137 | ConsumeStats consumeStats = null; 138 | try { 139 | consumeStats = adminExt.examineConsumeStats(consumerGroup); 140 | } catch (Exception e) { 141 | LoggerUtil.getLogger().warn("examineConsumeStats exception, " + consumerGroup, e); 142 | } 143 | ConsumerConnection cc = null; 144 | try { 145 | cc = adminExt.examineConsumerConnectionInfo(consumerGroup); 146 | } catch (Exception e) { 147 | LoggerUtil.getLogger().warn("examineConsumerConnectionInfo exception, " + consumerGroup, e); 148 | } 149 | TotalConsumerProgress tcprogress=new TotalConsumerProgress(); 150 | tcprogress.setGroup(consumerGroup); 151 | if(consumeStats!=null){ 152 | tcprogress.setTps(consumeStats.getConsumeTps()); 153 | tcprogress.setDiff(consumeStats.computeTotalDiff()); 154 | } 155 | if(cc!=null){ 156 | tcprogress.setCount(cc.getConnectionSet().size()); 157 | tcprogress.setType(cc.getConsumeType()==ConsumeType.CONSUME_ACTIVELY?"PULL":"PUSH"); 158 | tcprogress.setVersion(MQVersion.getVersionDesc(cc.computeMinVersion())); 159 | } 160 | tcprogressl.add(tcprogress); 161 | } 162 | } 163 | } catch (Exception ex) { 164 | LoggerUtil.getLogger().error("consumerProgress()",ex); 165 | } 166 | 167 | return tcprogressl; 168 | } 169 | 170 | 171 | /** 172 | * 获取某个consumergroup的消费明细 173 | * @param consumerGroup 消费组 174 | * @return 175 | */ 176 | public SingleConsumerProgress consumerProgress(String consumerGroup){ 177 | SingleConsumerProgress sp=new SingleConsumerProgress(); 178 | List cdList=new ArrayList(); 179 | try { 180 | ConsumeStats stats=adminExt.examineConsumeStats(consumerGroup); 181 | Map m=stats.getOffsetTable(); 182 | 183 | List mqList = new LinkedList(); 184 | mqList.addAll(stats.getOffsetTable().keySet()); 185 | Collections.sort(mqList); 186 | 187 | long diffTotal = 0L; 188 | 189 | for(MessageQueue mq:mqList){ 190 | OffsetWrapper offsetWrapper = stats.getOffsetTable().get(mq); 191 | long diff = offsetWrapper.getBrokerOffset() - offsetWrapper.getConsumerOffset(); 192 | diffTotal += diff; 193 | 194 | SingleConsumerProgress.ConsumerDetail cd=new SingleConsumerProgress.ConsumerDetail(); 195 | cd.setBrokerName(mq.getBrokerName()); 196 | cd.setMqId(mq.getQueueId()); 197 | cd.setTopic(mq.getTopic()); 198 | cd.setBrokerOffset(offsetWrapper.getBrokerOffset()); 199 | cd.setConsumerOffset(offsetWrapper.getConsumerOffset()); 200 | cd.setDiff(offsetWrapper.getBrokerOffset()-offsetWrapper.getConsumerOffset()); 201 | cdList.add(cd); 202 | } 203 | sp.setCdList(cdList); 204 | sp.setTotalDiff(diffTotal); 205 | sp.setTps(stats.getConsumeTps()); 206 | } catch (Exception ex) { 207 | LoggerUtil.getLogger().warn("consumerProgress single error:"+consumerGroup,ex); 208 | } 209 | return sp; 210 | } 211 | 212 | /** 213 | * 获取topic列表 214 | * @return 215 | */ 216 | public Set getTopics(){ 217 | Set topicSet=new LinkedHashSet(); 218 | try { 219 | TopicList topicList=adminExt.fetchAllTopicList(); 220 | for(String topic:topicList.getTopicList()){ 221 | if(!topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)&& 222 | !topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX)){ 223 | topicSet.add(topic); 224 | } 225 | } 226 | } catch (Exception ex) { 227 | LoggerUtil.getLogger().error("getTopics error:",ex); 228 | } 229 | return topicSet; 230 | } 231 | 232 | /** 233 | * 获取topic状态信息 234 | * @param topic topic名称 235 | * @return 236 | */ 237 | public List getTopicStats(String topicName){ 238 | List tsbList=new ArrayList(); 239 | try{ 240 | TopicStatsTable tst=adminExt.examineTopicStats(topicName); 241 | List mqList=new LinkedList(); 242 | mqList.addAll(tst.getOffsetTable().keySet()); 243 | Collections.sort(mqList); 244 | for(MessageQueue mq:mqList){ 245 | TopicOffset offset=tst.getOffsetTable().get(mq); 246 | TopicStatsBo tsb=new TopicStatsBo(); 247 | tsb.setBrokerName(mq.getBrokerName()); 248 | tsb.setQid(mq.getQueueId()); 249 | tsb.setMinOffset(offset.getMaxOffset()); 250 | tsb.setMaxOffset(offset.getMaxOffset()); 251 | tsb.setLastUpdate(new Date(offset.getLastUpdateTimestamp())); 252 | tsbList.add(tsb); 253 | } 254 | }catch(Exception e){ 255 | LoggerUtil.getLogger().error("getTopicStats error:",e); 256 | } 257 | return tsbList; 258 | } 259 | 260 | @PreDestroy 261 | public void clean(){ 262 | if(adminExt!=null){ 263 | adminExt.shutdown(); 264 | } 265 | } 266 | 267 | } 268 | --------------------------------------------------------------------------------