diff --git a/pom.xml b/pom.xml index f0f42e7..4473c79 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 2.6 2.4 1.2 - 4.0.0-incubating + 4.4.0-SNAPSHOT 2.19.1 1.6.11 ${basedir}/../.. diff --git a/src/main/java/org/apache/rocketmq/console/App.java b/src/main/java/org/apache/rocketmq/console/App.java index 6ed5831..15ec123 100644 --- a/src/main/java/org/apache/rocketmq/console/App.java +++ b/src/main/java/org/apache/rocketmq/console/App.java @@ -19,9 +19,11 @@ package org.apache.rocketmq.console; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.ServletComponentScan; @EnableAutoConfiguration @SpringBootApplication +@ServletComponentScan public class App { public static void main(String[] args) { diff --git a/src/main/java/org/apache/rocketmq/console/config/RMQConfigure.java b/src/main/java/org/apache/rocketmq/console/config/RMQConfigure.java index 0d9457e..e254771 100644 --- a/src/main/java/org/apache/rocketmq/console/config/RMQConfigure.java +++ b/src/main/java/org/apache/rocketmq/console/config/RMQConfigure.java @@ -41,6 +41,8 @@ public class RMQConfigure { private boolean enableDashBoardCollect; + private String msgTrackTopicName; + public String getNamesrvAddr() { return namesrvAddr; } @@ -84,4 +86,12 @@ public class RMQConfigure { public void setEnableDashBoardCollect(String enableDashBoardCollect) { this.enableDashBoardCollect = Boolean.valueOf(enableDashBoardCollect); } + + public String getMsgTrackTopicName() { + return msgTrackTopicName; + } + + public void setMsgTrackTopicName(String msgTrackTopicName) { + this.msgTrackTopicName = msgTrackTopicName; + } } diff --git a/src/main/java/org/apache/rocketmq/console/controller/MessageTraceController.java b/src/main/java/org/apache/rocketmq/console/controller/MessageTraceController.java new file mode 100644 index 0000000..ae99c9e --- /dev/null +++ b/src/main/java/org/apache/rocketmq/console/controller/MessageTraceController.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.rocketmq.console.controller; + +import com.google.common.collect.Maps; +import java.util.List; +import java.util.Map; +import javax.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.Pair; +import org.apache.rocketmq.console.config.RMQConfigure; +import org.apache.rocketmq.console.model.MessageView; +import org.apache.rocketmq.console.service.MessageService; +import org.apache.rocketmq.console.service.MessageTraceService; +import org.apache.rocketmq.tools.admin.api.MessageTrack; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +@RequestMapping("/messageTrace") +public class MessageTraceController { + + private Logger logger = LoggerFactory.getLogger(MessageController.class); + @Resource + private MessageService messageService; + + @Resource + private MessageTraceService messageTraceService; + + @Resource + private RMQConfigure rmqConfigure; + + @RequestMapping(value = "/viewMessage.query", method = RequestMethod.GET) + @ResponseBody + public Object viewMessage(@RequestParam(required = false) String topic, @RequestParam String msgId) { + Map messageViewMap = Maps.newHashMap(); + Pair> messageViewListPair = messageService.viewMessage(topic, msgId); + messageViewMap.put("messageView", messageViewListPair.getObject1()); + return messageViewMap; + } + + @RequestMapping(value = "/viewMessageTraceDetail.query", method = RequestMethod.GET) + @ResponseBody + public Object viewTraceMessages(@RequestParam(required = false) String topic, @RequestParam String msgId) { + String queryTopic = rmqConfigure.getMsgTrackTopicName(); + if (StringUtils.isEmpty(queryTopic)) { + queryTopic = MixAll.RMQ_SYS_TRACE_TOPIC; + } + logger.info("query data topic name is:{}",queryTopic); + return messageTraceService.queryMessageTraceByTopicAndKey(queryTopic, msgId); + } +} diff --git a/src/main/java/org/apache/rocketmq/console/filter/HttpBasicAuthorizedFilter.java b/src/main/java/org/apache/rocketmq/console/filter/HttpBasicAuthorizedFilter.java new file mode 100644 index 0000000..0bb113f --- /dev/null +++ b/src/main/java/org/apache/rocketmq/console/filter/HttpBasicAuthorizedFilter.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.rocketmq.console.filter; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Component; + +@Component +@WebFilter(urlPatterns = "/*", filterName = "httpBasicAuthorizedFilter") +public class HttpBasicAuthorizedFilter implements Filter { + + @Override + public void init(FilterConfig config) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.setCharacterEncoding("UTF-8"); + httpResponse.setContentType("application/json; charset=utf-8"); + httpResponse.setHeader("WWW-Authenticate", "Basic realm=\"rocketmq\""); + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } +} diff --git a/src/main/java/org/apache/rocketmq/console/model/MessageTraceView.java b/src/main/java/org/apache/rocketmq/console/model/MessageTraceView.java new file mode 100644 index 0000000..730b201 --- /dev/null +++ b/src/main/java/org/apache/rocketmq/console/model/MessageTraceView.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.rocketmq.console.model; + +import java.util.ArrayList; +import java.util.List; +import org.apache.rocketmq.client.trace.TraceBean; +import org.apache.rocketmq.client.trace.TraceContext; +import org.apache.rocketmq.console.util.MsgTraceDecodeUtil; + +public class MessageTraceView { + + private String msgId; + private String tags; + private String keys; + private String storeHost; + private int costTime; + private String msgType; + private String offSetMsgId; + private long timeStamp; + private String topic; + private String groupName; + private String status; + + public static List decodeFromTraceTransData(String key,String messageBody) { + List messageTraceViewList = new ArrayList(); + if (messageBody == null || messageBody.length() <= 0) { + return messageTraceViewList; + } + + List traceContextList = MsgTraceDecodeUtil.decoderFromTraceDataString(messageBody); + + for (TraceContext context : traceContextList) { + MessageTraceView messageTraceView = new MessageTraceView(); + TraceBean traceBean = context.getTraceBeans().get(0); + if (!traceBean.getMsgId().equals(key)) { + continue; + } + messageTraceView.setCostTime(context.getCostTime()); + messageTraceView.setGroupName(context.getGroupName()); + if (context.isSuccess()) { + messageTraceView.setStatus("Sucess"); + } + else { + messageTraceView.setStatus("failed"); + } + messageTraceView.setKeys(traceBean.getKeys()); + messageTraceView.setMsgId(traceBean.getMsgId()); + messageTraceView.setTags(traceBean.getTags()); + messageTraceView.setTopic(traceBean.getTopic()); + messageTraceView.setMsgType(context.getTraceType().name()); + messageTraceView.setOffSetMsgId(traceBean.getOffsetMsgId()); + messageTraceView.setTimeStamp(context.getTimeStamp()); + messageTraceView.setStoreHost(traceBean.getStoreHost()); + messageTraceViewList.add(messageTraceView); + } + return messageTraceViewList; + } + + public String getMsgId() { + return msgId; + } + + public void setMsgId(String msgId) { + this.msgId = msgId; + } + + public String getTags() { + return tags; + } + + public void setTags(String tags) { + this.tags = tags; + } + + public String getKeys() { + return keys; + } + + public void setKeys(String keys) { + this.keys = keys; + } + + public String getStoreHost() { + return storeHost; + } + + public void setStoreHost(String storeHost) { + this.storeHost = storeHost; + } + + public int getCostTime() { + return costTime; + } + + public void setCostTime(int costTime) { + this.costTime = costTime; + } + + public String getMsgType() { + return msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getOffSetMsgId() { + return offSetMsgId; + } + + public void setOffSetMsgId(String offSetMsgId) { + this.offSetMsgId = offSetMsgId; + } + + public long getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(long timeStamp) { + this.timeStamp = timeStamp; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } +} diff --git a/src/main/java/org/apache/rocketmq/console/service/MessageTraceService.java b/src/main/java/org/apache/rocketmq/console/service/MessageTraceService.java new file mode 100644 index 0000000..9a4449f --- /dev/null +++ b/src/main/java/org/apache/rocketmq/console/service/MessageTraceService.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.rocketmq.console.service; + +import java.util.List; +import org.apache.rocketmq.console.model.MessageTraceView; + +public interface MessageTraceService { + + List queryMessageTraceByTopicAndKey(final String topic, final String key); + +} diff --git a/src/main/java/org/apache/rocketmq/console/service/client/MQAdminExtImpl.java b/src/main/java/org/apache/rocketmq/console/service/client/MQAdminExtImpl.java index 0eba3a5..77a3784 100644 --- a/src/main/java/org/apache/rocketmq/console/service/client/MQAdminExtImpl.java +++ b/src/main/java/org/apache/rocketmq/console/service/client/MQAdminExtImpl.java @@ -44,6 +44,7 @@ import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.body.GroupList; import org.apache.rocketmq.common.protocol.body.KVTable; import org.apache.rocketmq.common.protocol.body.ProducerConnection; +import org.apache.rocketmq.common.protocol.body.QueryConsumeQueueResponseBody; import org.apache.rocketmq.common.protocol.body.QueueTimeSpan; import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper; import org.apache.rocketmq.common.protocol.body.TopicConfigSerializeWrapper; @@ -498,4 +499,10 @@ public class MQAdminExtImpl implements MQAdminExt { List list) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException, UnsupportedEncodingException { return null; } + + @Override public QueryConsumeQueueResponseBody queryConsumeQueue(String brokerAddr, String topic, + int queueId, long index, int count, + String consumerGroup) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException { + return null; + } } diff --git a/src/main/java/org/apache/rocketmq/console/service/impl/MessageTraceServiceImpl.java b/src/main/java/org/apache/rocketmq/console/service/impl/MessageTraceServiceImpl.java new file mode 100644 index 0000000..1eaeb4a --- /dev/null +++ b/src/main/java/org/apache/rocketmq/console/service/impl/MessageTraceServiceImpl.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.rocketmq.console.service.impl; + +import com.google.common.base.Charsets; +import com.google.common.base.Throwables; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Resource; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.console.model.MessageTraceView; +import org.apache.rocketmq.console.service.MessageTraceService; +import org.apache.rocketmq.tools.admin.MQAdminExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class MessageTraceServiceImpl implements MessageTraceService { + + private Logger logger = LoggerFactory.getLogger(MessageTraceServiceImpl.class); + + private final static int QUERY_MESSAGE_MAX_NUM = 64; + @Resource + private MQAdminExt mqAdminExt; + + @Override public List queryMessageTraceByTopicAndKey(String topic, String key) { + try { + List messageTraceViews = new ArrayList(); + List messageTraceList = mqAdminExt.queryMessage(topic, key, QUERY_MESSAGE_MAX_NUM, 0, System.currentTimeMillis()).getMessageList(); + for (MessageExt messageExt : messageTraceList) { + List messageTraceView = MessageTraceView.decodeFromTraceTransData(key, new String(messageExt.getBody(), Charsets.UTF_8)); + messageTraceViews.addAll(messageTraceView); + } + return messageTraceViews; + } + catch (Exception err) { + throw Throwables.propagate(err); + } + } +} diff --git a/src/main/java/org/apache/rocketmq/console/service/impl/MonitorServiceImpl.java b/src/main/java/org/apache/rocketmq/console/service/impl/MonitorServiceImpl.java index d3a109d..310f259 100644 --- a/src/main/java/org/apache/rocketmq/console/service/impl/MonitorServiceImpl.java +++ b/src/main/java/org/apache/rocketmq/console/service/impl/MonitorServiceImpl.java @@ -19,6 +19,7 @@ package org.apache.rocketmq.console.service.impl; import com.fasterxml.jackson.core.type.TypeReference; import com.google.common.base.Throwables; import java.io.File; +import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.PostConstruct; @@ -86,7 +87,7 @@ public class MonitorServiceImpl implements MonitorService { } @PostConstruct - private void loadData() { + private void loadData() throws IOException { String content = MixAll.file2String(getConsumerMonitorConfigDataPath()); if (content == null) { content = MixAll.file2String(getConsumerMonitorConfigDataPathBackUp()); diff --git a/src/main/java/org/apache/rocketmq/console/util/MsgTraceDecodeUtil.java b/src/main/java/org/apache/rocketmq/console/util/MsgTraceDecodeUtil.java new file mode 100644 index 0000000..e07d1b5 --- /dev/null +++ b/src/main/java/org/apache/rocketmq/console/util/MsgTraceDecodeUtil.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.rocketmq.console.util; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.rocketmq.client.trace.TraceBean; +import org.apache.rocketmq.client.trace.TraceConstants; +import org.apache.rocketmq.client.trace.TraceContext; +import org.apache.rocketmq.client.trace.TraceType; +import org.apache.rocketmq.common.message.MessageType; + +import static org.apache.rocketmq.client.trace.TraceType.Pub; + +public class MsgTraceDecodeUtil { + + public static List decoderFromTraceDataString(String traceData) { + List resList = new ArrayList(); + if (traceData == null || traceData.length() <= 0) { + return resList; + } + String[] contextList = traceData.split(String.valueOf(TraceConstants.FIELD_SPLITOR)); + for (String context : contextList) { + String[] line = context.split(String.valueOf(TraceConstants.CONTENT_SPLITOR)); + if (line[0].equals(Pub.name())) { + TraceContext pubContext = new TraceContext(); + pubContext.setTraceType(Pub); + pubContext.setTimeStamp(Long.parseLong(line[1])); + pubContext.setRegionId(line[2]); + pubContext.setGroupName(line[3]); + TraceBean bean = new TraceBean(); + bean.setTopic(line[4]); + bean.setMsgId(line[5]); + bean.setTags(line[6]); + bean.setKeys(line[7]); + bean.setStoreHost(line[8]); + bean.setBodyLength(Integer.parseInt(line[9])); + pubContext.setCostTime(Integer.parseInt(line[10])); + bean.setMsgType(MessageType.values()[Integer.parseInt(line[11])]); + + if (line.length == 13) { + pubContext.setSuccess(Boolean.parseBoolean(line[12])); + } else if (line.length == 14) { + bean.setOffsetMsgId(line[12]); + pubContext.setSuccess(Boolean.parseBoolean(line[13])); + } + pubContext.setTraceBeans(new ArrayList(1)); + pubContext.getTraceBeans().add(bean); + resList.add(pubContext); + } else if (line[0].equals(TraceType.SubBefore.name())) { + TraceContext subBeforeContext = new TraceContext(); + subBeforeContext.setTraceType(TraceType.SubBefore); + subBeforeContext.setTimeStamp(Long.parseLong(line[1])); + subBeforeContext.setRegionId(line[2]); + subBeforeContext.setGroupName(line[3]); + subBeforeContext.setRequestId(line[4]); + TraceBean bean = new TraceBean(); + bean.setMsgId(line[5]); + bean.setRetryTimes(Integer.parseInt(line[6])); + bean.setKeys(line[7]); + subBeforeContext.setTraceBeans(new ArrayList(1)); + subBeforeContext.getTraceBeans().add(bean); + resList.add(subBeforeContext); + } else if (line[0].equals(TraceType.SubAfter.name())) { + TraceContext subAfterContext = new TraceContext(); + subAfterContext.setTraceType(TraceType.SubAfter); + subAfterContext.setRequestId(line[1]); + TraceBean bean = new TraceBean(); + bean.setMsgId(line[2]); + bean.setKeys(line[5]); + subAfterContext.setTraceBeans(new ArrayList(1)); + subAfterContext.getTraceBeans().add(bean); + subAfterContext.setCostTime(Integer.parseInt(line[3])); + subAfterContext.setSuccess(Boolean.parseBoolean(line[4])); + if (line.length >= 7) { + // add the context type + subAfterContext.setContextCode(Integer.parseInt(line[6])); + } + resList.add(subAfterContext); + } + } + return resList; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index de8eb1b..e847ad1 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -13,4 +13,6 @@ rocketmq.config.isVIPChannel= #rocketmq-console's data path:dashboard/monitor rocketmq.config.dataPath=/tmp/rocketmq-console/data #set it false if you don't want use dashboard.default true -rocketmq.config.enableDashBoardCollect=true \ No newline at end of file +rocketmq.config.enableDashBoardCollect=true +#set the message track trace topic if you don't want use the default one +rocketmq.config.msgTrackTopicName= \ No newline at end of file diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 6e3e6aa..5dbfa21 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -109,6 +109,7 @@ + diff --git a/src/main/resources/static/src/app.js b/src/main/resources/static/src/app.js index b241010..09cc954 100644 --- a/src/main/resources/static/src/app.js +++ b/src/main/resources/static/src/app.js @@ -145,6 +145,9 @@ app.config(['$routeProvider', '$httpProvider','$cookiesProvider','getDictNamePro }).when('/message', { templateUrl: 'view/pages/message.html', controller:'messageController' + }).when('/messageTrace', { + templateUrl: 'view/pages/messageTrace.html', + controller:'messageTraceController' }).when('/ops', { templateUrl: 'view/pages/ops.html', controller:'opsController' diff --git a/src/main/resources/static/src/i18n/en.js b/src/main/resources/static/src/i18n/en.js index 651456f..05fe2dc 100644 --- a/src/main/resources/static/src/i18n/en.js +++ b/src/main/resources/static/src/i18n/en.js @@ -20,6 +20,7 @@ var en = { "CONSUMER":"Consumer", "PRODUCER":"Producer", "MESSAGE":"Message", + "MESSAGETRACE":"MessageTrace", "COMMIT": "Commit", "OPERATION": "Operation", "ADD": "Add", diff --git a/src/main/resources/static/src/i18n/zh.js b/src/main/resources/static/src/i18n/zh.js index 6cf39f0..255333e 100644 --- a/src/main/resources/static/src/i18n/zh.js +++ b/src/main/resources/static/src/i18n/zh.js @@ -21,6 +21,7 @@ var zh = { "CONSUMER":"消费者", "PRODUCER":"生产者", "MESSAGE":"消息", + "MESSAGETRACE":"消息轨迹", "OPERATION": "操作", "ADD": "新增", "UPDATE": "更新", diff --git a/src/main/resources/static/src/messageTrace.js b/src/main/resources/static/src/messageTrace.js new file mode 100644 index 0000000..d48b64e --- /dev/null +++ b/src/main/resources/static/src/messageTrace.js @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +var module = app; + +module.controller('messageTraceController', ['$scope', 'ngDialog', '$http','Notification',function ($scope, ngDialog, $http,Notification) { + $scope.allTopicList = []; + $scope.selectedTopic =[]; + $scope.key =""; + $scope.messageId =""; + $scope.queryMessageByTopicAndKeyResult=[]; + $scope.queryMessageByMessageIdResult={}; + $scope.queryMessageTraceListsByTopicAndKeyResult=[]; + + $http({ + method: "GET", + url: "topic/list.query" + }).success(function (resp) { + if(resp.status ==0){ + $scope.allTopicList = resp.data.topicList.sort(); + console.log($scope.allTopicList); + }else { + Notification.error({message: resp.errMsg, delay: 2000}); + } + }); + $scope.timepickerBegin = moment().subtract(1, 'hour').format('YYYY-MM-DD HH:mm'); + $scope.timepickerEnd = moment().add(1,'hour').format('YYYY-MM-DD HH:mm'); + $scope.timepickerOptions ={format: 'YYYY-MM-DD HH:mm', showClear: true}; + + $scope.queryMessageByTopicAndKey = function () { + console.log($scope.selectedTopic); + console.log($scope.key); + $http({ + method: "GET", + url: "message/queryMessageByTopicAndKey.query", + params: { + topic: $scope.selectedTopic, + key:$scope.key + } + }).success(function (resp) { + if (resp.status == 0) { + console.log(resp); + $scope.queryMessageByTopicAndKeyResult = resp.data; + console.log($scope.queryMessageByTopicAndKeyResult); + }else { + Notification.error({message: resp.errMsg, delay: 2000}); + } + }); + }; + + $scope.queryMessageByMessageId = function (messageId,topic) { + $http({ + method: "GET", + url: "messageTrace/viewMessage.query", + params: { + msgId: messageId, + topic:topic + } + }).success(function (resp) { + if (resp.status == 0) { + console.log(resp); + $scope.queryMessageByMessageIdResult = resp.data; + console.log($scope.queryMessageByTopicAndKeyResult); + }else { + Notification.error({message: resp.errMsg, delay: 2000}); + } + }); + }; + + $scope.queryMessageTraceByMessageId = function (messageId,topic) { + $http({ + method: "GET", + url: "messageTrace/viewMessageTraceDetail.query", + params: { + msgId: messageId, + topic:topic + } + }).success(function (resp) { + if (resp.status == 0) { + console.log(resp); + ngDialog.open({ + template: 'messageTraceDetailViewDialog', + controller: 'messageTraceDetailViewDialogController', + data:resp.data + }); + }else { + Notification.error({message: resp.errMsg, delay: 2000}); + } + }); + }; +}]); + +module.controller('messageTraceDetailViewDialogController',['$scope', 'ngDialog', '$http','Notification', function ($scope, ngDialog, $http,Notification) { + + $scope.showExceptionDesc = function (errmsg) { + if(errmsg == null){ + errmsg = "Don't have Exception" + } + ngDialog.open({ + template: 'operationResultDialog', + data:{ + result:errmsg + } + }); + }; + }] +); \ No newline at end of file diff --git a/src/main/resources/static/view/layout/_header.html b/src/main/resources/static/view/layout/_header.html index 382e85f..5f91b92 100644 --- a/src/main/resources/static/view/layout/_header.html +++ b/src/main/resources/static/view/layout/_header.html @@ -17,6 +17,7 @@ {{'CONSUMER' | translate}} {{'PRODUCER' | translate}} {{'MESSAGE' | translate}} + {{'MESSAGETRACE' | translate}} diff --git a/src/main/resources/static/view/pages/messageTrace.html b/src/main/resources/static/view/pages/messageTrace.html new file mode 100644 index 0000000..e3f4dc6 --- /dev/null +++ b/src/main/resources/static/view/pages/messageTrace.html @@ -0,0 +1,182 @@ + + + + + + + + + Only Return 64 Messages + + + + Topic: + + + + + + + + + + Key: + + + + + {{ 'SEARCH' | translate}} + + + + + Message ID + Tag + Message Key + StoreTime + Operation + + + {{item.msgId}} + {{item.properties.TAGS}} + {{item.properties.KEYS}} + {{item.storeTimestamp | date:'yyyy-MM-dd HH:mm:ss'}} + + + Message Trace Detail + + + + + + + + topic can't be empty if you producer client version>=v3.5.8 + + + + Topic: + + + + + + + + + + MessageId: + + + + {{ 'SEARCH' | translate}} + + + + + Message ID + Tag + Message Key + StoreTime + Operation + + + {{item.msgId}} + {{item.properties.TAGS}} + {{item.properties.KEYS}} + {{item.storeTimestamp | date:'yyyy-MM-dd HH:mm:ss'}} + + + Message Trace Detail + + + + + + + + + + + + + + + + + \ No newline at end of file