Use rocketmq-dashboard instead of rocketmq-console

This commit is contained in:
StyleTang
2021-08-13 22:46:16 +08:00
parent 446d89789f
commit 119cf0d58c
123 changed files with 366 additions and 366 deletions

View File

@@ -0,0 +1,33 @@
/*
* 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.dashboard;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@ServletComponentScan
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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.dashboard.aspect.admin;
import org.apache.rocketmq.dashboard.aspect.admin.annotation.MultiMQAdminCmdMethod;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.service.client.MQAdminInstance;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
@Aspect
@Service
public class MQAdminAspect {
private Logger logger = LoggerFactory.getLogger(MQAdminAspect.class);
@Autowired
private RMQConfigure rmqConfigure;
public MQAdminAspect() {
}
@Pointcut("execution(* org.apache.rocketmq.dashboard.service.client.MQAdminExtImpl..*(..))")
public void mQAdminMethodPointCut() {
}
@Pointcut("@annotation(org.apache.rocketmq.dashboard.aspect.admin.annotation.MultiMQAdminCmdMethod)")
public void multiMQAdminMethodPointCut() {
}
@Around(value = "mQAdminMethodPointCut() || multiMQAdminMethodPointCut()")
public Object aroundMQAdminMethod(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object obj = null;
try {
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
MultiMQAdminCmdMethod multiMQAdminCmdMethod = method.getAnnotation(MultiMQAdminCmdMethod.class);
if (multiMQAdminCmdMethod != null && multiMQAdminCmdMethod.timeoutMillis() > 0) {
MQAdminInstance.initMQAdminInstance(multiMQAdminCmdMethod.timeoutMillis(),rmqConfigure.getAccessKey(),rmqConfigure.getSecretKey(), rmqConfigure.isUseTLS());
}
else {
MQAdminInstance.initMQAdminInstance(0,rmqConfigure.getAccessKey(),rmqConfigure.getSecretKey(), rmqConfigure.isUseTLS());
}
obj = joinPoint.proceed();
}
finally {
MQAdminInstance.destroyMQAdminInstance();
logger.debug("op=look method={} cost={}", joinPoint.getSignature().getName(), System.currentTimeMillis() - start);
}
return obj;
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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.dashboard.aspect.admin.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MultiMQAdminCmdMethod {
long timeoutMillis() default 0;
}

View File

@@ -0,0 +1,30 @@
/*
* 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.dashboard.aspect.admin.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OriginalControllerReturnValue {
}

View File

@@ -0,0 +1,89 @@
/*
* 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.dashboard.config;
import org.apache.rocketmq.dashboard.interceptor.AuthInterceptor;
import org.apache.rocketmq.dashboard.model.UserInfo;
import org.apache.rocketmq.dashboard.util.WebUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Configuration
public class AuthWebMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
@Autowired
@Qualifier("authInterceptor")
private AuthInterceptor authInterceptor;
@Resource
RMQConfigure configure;
@Override
public void addInterceptors(InterceptorRegistry registry) {
if (configure.isLoginRequired()) {
registry.addInterceptor(authInterceptor).addPathPatterns(
"/cluster/**",
"/consumer/**",
"/dashboard/**",
"/message/**",
"/messageTrace/**",
"/monitor/**",
"/rocketmq/**",
"/ops/**",
"/producer/**",
"/test/**",
"/topic/**");
}
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new HandlerMethodArgumentResolver() {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterType().isAssignableFrom(UserInfo.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
UserInfo userInfo = (UserInfo) WebUtil.getValueFromSession((HttpServletRequest) nativeWebRequest.getNativeRequest(),
UserInfo.USER_INFO);
if (userInfo != null) {
return userInfo;
}
throw new MissingServletRequestPartException(UserInfo.USER_INFO);
}
});
super.addArgumentResolvers(argumentResolvers); //REVIEW ME
}
}

View File

@@ -0,0 +1,165 @@
/*
* 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.dashboard.config;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.topic.TopicValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import java.io.File;
import static org.apache.rocketmq.client.ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY;
@Configuration
@ConfigurationProperties(prefix = "rocketmq.config")
public class RMQConfigure {
private Logger logger = LoggerFactory.getLogger(RMQConfigure.class);
//use rocketmq.namesrv.addr first,if it is empty,than use system proerty or system env
private volatile String namesrvAddr = System.getProperty(MixAll.NAMESRV_ADDR_PROPERTY, System.getenv(MixAll.NAMESRV_ADDR_ENV));
private volatile String isVIPChannel = System.getProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "true");
private String dataPath = "/tmp/rocketmq-console/data";
private boolean enableDashBoardCollect;
private String msgTrackTopicName;
private boolean loginRequired = false;
private String accessKey;
private String secretKey;
private boolean useTLS = false;
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getNamesrvAddr() {
return namesrvAddr;
}
public void setNamesrvAddr(String namesrvAddr) {
if (StringUtils.isNotBlank(namesrvAddr)) {
this.namesrvAddr = namesrvAddr;
System.setProperty(MixAll.NAMESRV_ADDR_PROPERTY, namesrvAddr);
logger.info("setNameSrvAddrByProperty nameSrvAddr={}", namesrvAddr);
}
}
public boolean isACLEnabled() {
return !(StringUtils.isAnyBlank(this.accessKey, this.secretKey) ||
StringUtils.isAnyEmpty(this.accessKey, this.secretKey));
}
public String getRocketMqDashboardDataPath() {
return dataPath;
}
public String getDashboardCollectData() {
return dataPath + File.separator + "dashboard";
}
public void setDataPath(String dataPath) {
this.dataPath = dataPath;
}
public String getIsVIPChannel() {
return isVIPChannel;
}
public void setIsVIPChannel(String isVIPChannel) {
if (StringUtils.isNotBlank(isVIPChannel)) {
this.isVIPChannel = isVIPChannel;
System.setProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, isVIPChannel);
logger.info("setIsVIPChannel isVIPChannel={}", isVIPChannel);
}
}
public boolean isEnableDashBoardCollect() {
return enableDashBoardCollect;
}
public void setEnableDashBoardCollect(String enableDashBoardCollect) {
this.enableDashBoardCollect = Boolean.valueOf(enableDashBoardCollect);
}
public String getMsgTrackTopicNameOrDefault() {
if (StringUtils.isEmpty(msgTrackTopicName)) {
return TopicValidator.RMQ_SYS_TRACE_TOPIC;
}
return msgTrackTopicName;
}
public void setMsgTrackTopicName(String msgTrackTopicName) {
this.msgTrackTopicName = msgTrackTopicName;
}
public boolean isLoginRequired() {
return loginRequired;
}
public void setLoginRequired(boolean loginRequired) {
this.loginRequired = loginRequired;
}
public boolean isUseTLS() {
return useTLS;
}
public void setUseTLS(boolean useTLS) {
this.useTLS = useTLS;
}
// Error Page process logic, move to a central configure later
@Bean
public ErrorPageRegistrar errorPageRegistrar() {
return new MyErrorPageRegistrar();
}
private static class MyErrorPageRegistrar implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/404"));
}
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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.dashboard.controller;
import org.apache.rocketmq.dashboard.service.ClusterService;
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 javax.annotation.Resource;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/cluster")
public class ClusterController {
@Resource
private ClusterService clusterService;
@RequestMapping(value = "/list.query", method = RequestMethod.GET)
@ResponseBody
public Object list() {
return clusterService.list();
}
@RequestMapping(value = "/brokerConfig.query", method = RequestMethod.GET)
@ResponseBody
public Object brokerConfig(@RequestParam String brokerAddr) {
return clusterService.getBrokerConfig(brokerAddr);
}
}

View File

@@ -0,0 +1,118 @@
/*
* 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.dashboard.controller;
import com.google.common.base.Preconditions;
import javax.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
import org.apache.rocketmq.dashboard.model.ConnectionInfo;
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
import org.apache.rocketmq.dashboard.model.request.DeleteSubGroupRequest;
import org.apache.rocketmq.dashboard.model.request.ResetOffsetRequest;
import org.apache.rocketmq.dashboard.service.ConsumerService;
import org.apache.rocketmq.dashboard.util.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
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("/consumer")
public class ConsumerController {
private Logger logger = LoggerFactory.getLogger(ConsumerController.class);
@Resource
private ConsumerService consumerService;
@RequestMapping(value = "/groupList.query")
@ResponseBody
public Object list() {
return consumerService.queryGroupList();
}
@RequestMapping(value = "/group.query")
@ResponseBody
public Object groupQuery(@RequestParam String consumerGroup) {
return consumerService.queryGroup(consumerGroup);
}
@RequestMapping(value = "/resetOffset.do", method = {RequestMethod.POST})
@ResponseBody
public Object resetOffset(@RequestBody ResetOffsetRequest resetOffsetRequest) {
logger.info("op=look resetOffsetRequest={}", JsonUtil.obj2String(resetOffsetRequest));
return consumerService.resetOffset(resetOffsetRequest);
}
@RequestMapping(value = "/skipAccumulate.do", method = {RequestMethod.POST})
@ResponseBody
public Object skipAccumulate(@RequestBody ResetOffsetRequest resetOffsetRequest) {
logger.info("op=look resetOffsetRequest={}", JsonUtil.obj2String(resetOffsetRequest));
return consumerService.resetOffset(resetOffsetRequest);
}
@RequestMapping(value = "/examineSubscriptionGroupConfig.query")
@ResponseBody
public Object examineSubscriptionGroupConfig(@RequestParam String consumerGroup) {
return consumerService.examineSubscriptionGroupConfig(consumerGroup);
}
@RequestMapping(value = "/deleteSubGroup.do", method = {RequestMethod.POST})
@ResponseBody
public Object deleteSubGroup(@RequestBody DeleteSubGroupRequest deleteSubGroupRequest) {
return consumerService.deleteSubGroup(deleteSubGroupRequest);
}
@RequestMapping(value = "/createOrUpdate.do", method = {RequestMethod.POST})
@ResponseBody
public Object consumerCreateOrUpdateRequest(@RequestBody ConsumerConfigInfo consumerConfigInfo) {
Preconditions.checkArgument(CollectionUtils.isNotEmpty(consumerConfigInfo.getBrokerNameList()) || CollectionUtils.isNotEmpty(consumerConfigInfo.getClusterNameList()),
"clusterName or brokerName can not be all blank");
return consumerService.createAndUpdateSubscriptionGroupConfig(consumerConfigInfo);
}
@RequestMapping(value = "/fetchBrokerNameList.query", method = {RequestMethod.GET})
@ResponseBody
public Object fetchBrokerNameList(@RequestParam String consumerGroup) {
return consumerService.fetchBrokerNameSetBySubscriptionGroup(consumerGroup);
}
@RequestMapping(value = "/queryTopicByConsumer.query")
@ResponseBody
public Object queryConsumerByTopic(@RequestParam String consumerGroup) {
return consumerService.queryConsumeStatsListByGroupName(consumerGroup);
}
@RequestMapping(value = "/consumerConnection.query")
@ResponseBody
public Object consumerConnection(@RequestParam(required = false) String consumerGroup) {
ConsumerConnection consumerConnection = consumerService.getConsumerConnection(consumerGroup);
consumerConnection.setConnectionSet(ConnectionInfo.buildConnectionInfoHashSet(consumerConnection.getConnectionSet()));
return consumerConnection;
}
@RequestMapping(value = "/consumerRunningInfo.query")
@ResponseBody
public Object getConsumerRunningInfo(@RequestParam String consumerGroup, @RequestParam String clientId,
@RequestParam boolean jstack) {
return consumerService.getConsumerRunningInfo(consumerGroup, clientId, jstack);
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.dashboard.controller;
import javax.annotation.Resource;
import com.google.common.base.Strings;
import org.apache.rocketmq.dashboard.service.DashboardService;
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("/dashboard")
public class DashboardController {
@Resource
DashboardService dashboardService;
@RequestMapping(value = "/broker.query", method = RequestMethod.GET)
@ResponseBody
public Object broker(@RequestParam String date) {
return dashboardService.queryBrokerData(date);
}
@RequestMapping(value = "/topic.query", method = RequestMethod.GET)
@ResponseBody
public Object topic(@RequestParam String date, String topicName) {
if (Strings.isNullOrEmpty(topicName)) {
return dashboardService.queryTopicData(date);
}
return dashboardService.queryTopicData(date,topicName);
}
@RequestMapping(value = "/topicCurrent", method = RequestMethod.GET)
@ResponseBody
public Object topicCurrent() {
return dashboardService.queryTopicCurrentData();
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.dashboard.controller;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.model.LoginInfo;
import org.apache.rocketmq.dashboard.model.User;
import org.apache.rocketmq.dashboard.model.UserInfo;
import org.apache.rocketmq.dashboard.service.UserService;
import org.apache.rocketmq.dashboard.support.JsonResult;
import org.apache.rocketmq.dashboard.util.WebUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
@RequestMapping("/login")
public class LoginController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private RMQConfigure configure;
@Autowired
private UserService userService;
@Value("${server.servlet.context-path:/}")
private String contextPath;
@RequestMapping(value = "/check.query", method = RequestMethod.GET)
@ResponseBody
public Object check(HttpServletRequest request) {
LoginInfo loginInfo = new LoginInfo();
loginInfo.setLogined(WebUtil.getValueFromSession(request, WebUtil.USER_NAME) != null);
loginInfo.setLoginRequired(configure.isLoginRequired());
return loginInfo;
}
@RequestMapping(value = "/login.do", method = RequestMethod.POST)
@ResponseBody
public JsonResult<String> login(@RequestParam("username") String username,
@RequestParam(value = "password") String password,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
logger.info("user:{} login", username);
User user = userService.queryByUsernameAndPassword(username, password);
if (user == null) {
throw new IllegalArgumentException("Bad username or password!");
} else {
user.setPassword(null);
UserInfo userInfo = WebUtil.setLoginInfo(request, response, user);
WebUtil.setSessionValue(request, WebUtil.USER_INFO, userInfo);
WebUtil.setSessionValue(request, WebUtil.USER_NAME, username);
userInfo.setSessionId(WebUtil.getSessionId(request));
return new JsonResult<>(contextPath);
}
}
@RequestMapping(value = "/logout.do", method = RequestMethod.POST)
@ResponseBody
public JsonResult<String> logout(HttpServletRequest request) {
WebUtil.removeSession(request);
return new JsonResult<>(contextPath);
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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.dashboard.controller;
import com.google.common.collect.Maps;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
import org.apache.rocketmq.dashboard.model.MessagePage;
import org.apache.rocketmq.dashboard.model.MessageView;
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
import org.apache.rocketmq.dashboard.service.MessageService;
import org.apache.rocketmq.dashboard.util.JsonUtil;
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.ResponseBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/message")
public class MessageController {
private Logger logger = LoggerFactory.getLogger(MessageController.class);
@Resource
private MessageService messageService;
@RequestMapping(value = "/viewMessage.query", method = RequestMethod.GET)
@ResponseBody
public Object viewMessage(@RequestParam(required = false) String topic, @RequestParam String msgId) {
Map<String, Object> messageViewMap = Maps.newHashMap();
Pair<MessageView, List<MessageTrack>> messageViewListPair = messageService.viewMessage(topic, msgId);
messageViewMap.put("messageView", messageViewListPair.getObject1());
messageViewMap.put("messageTrackList", messageViewListPair.getObject2());
return messageViewMap;
}
@PostMapping("/queryMessagePageByTopic.query")
@ResponseBody
public MessagePage queryMessagePageByTopic(@RequestBody MessageQuery query) {
return messageService.queryMessageByPage(query);
}
@RequestMapping(value = "/queryMessageByTopicAndKey.query", method = RequestMethod.GET)
@ResponseBody
public Object queryMessageByTopicAndKey(@RequestParam String topic, @RequestParam String key) {
return messageService.queryMessageByTopicAndKey(topic, key);
}
@RequestMapping(value = "/queryMessageByTopic.query", method = RequestMethod.GET)
@ResponseBody
public Object queryMessageByTopic(@RequestParam String topic, @RequestParam long begin,
@RequestParam long end) {
return messageService.queryMessageByTopic(topic, begin, end);
}
@RequestMapping(value = "/consumeMessageDirectly.do", method = RequestMethod.POST)
@ResponseBody
public Object consumeMessageDirectly(@RequestParam String topic, @RequestParam String consumerGroup,
@RequestParam String msgId,
@RequestParam(required = false) String clientId) {
logger.info("msgId={} consumerGroup={} clientId={}", msgId, consumerGroup, clientId);
ConsumeMessageDirectlyResult consumeMessageDirectlyResult = messageService.consumeMessageDirectly(topic, msgId, consumerGroup, clientId);
logger.info("consumeMessageDirectlyResult={}", JsonUtil.obj2String(consumeMessageDirectlyResult));
return consumeMessageDirectlyResult;
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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.dashboard.controller;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.dashboard.model.MessageView;
import org.apache.rocketmq.dashboard.model.trace.MessageTraceGraph;
import org.apache.rocketmq.dashboard.service.MessageService;
import org.apache.rocketmq.dashboard.service.MessageTraceService;
import org.apache.rocketmq.tools.admin.api.MessageTrack;
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 {
@Resource
private MessageService messageService;
@Resource
private MessageTraceService messageTraceService;
@RequestMapping(value = "/viewMessage.query", method = RequestMethod.GET)
@ResponseBody
public Object viewMessage(@RequestParam(required = false) String topic, @RequestParam String msgId) {
Map<String, Object> messageViewMap = Maps.newHashMap();
Pair<MessageView, List<MessageTrack>> messageViewListPair = messageService.viewMessage(topic, msgId);
messageViewMap.put("messageView", messageViewListPair.getObject1());
return messageViewMap;
}
@RequestMapping(value = "/viewMessageTraceDetail.query", method = RequestMethod.GET)
@ResponseBody
public Object viewTraceMessages(@RequestParam String msgId) {
return messageTraceService.queryMessageTraceKey(msgId);
}
@RequestMapping(value = "/viewMessageTraceGraph.query", method = RequestMethod.GET)
@ResponseBody
public MessageTraceGraph viewMessageTraceGraph(@RequestParam String msgId) {
return messageTraceService.queryMessageTraceGraph(msgId);
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.dashboard.controller;
import javax.annotation.Resource;
import org.apache.rocketmq.dashboard.model.ConsumerMonitorConfig;
import org.apache.rocketmq.dashboard.service.MonitorService;
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("/monitor")
public class MonitorController {
private Logger logger = LoggerFactory.getLogger(MonitorController.class);
@Resource
private MonitorService monitorService;
@RequestMapping(value = "/createOrUpdateConsumerMonitor.do", method = {RequestMethod.POST})
@ResponseBody
public Object createOrUpdateConsumerMonitor(@RequestParam String consumeGroupName, @RequestParam int minCount,
@RequestParam int maxDiffTotal) {
return monitorService.createOrUpdateConsumerMonitor(consumeGroupName, new ConsumerMonitorConfig(minCount, maxDiffTotal));
}
@RequestMapping(value = "/consumerMonitorConfig.query", method = {RequestMethod.GET})
@ResponseBody
public Object consumerMonitorConfig() {
return monitorService.queryConsumerMonitorConfig();
}
@RequestMapping(value = "/consumerMonitorConfigByGroupName.query", method = {RequestMethod.GET})
@ResponseBody
public Object consumerMonitorConfigByGroupName(@RequestParam String consumeGroupName) {
return monitorService.queryConsumerMonitorConfigByGroupName(consumeGroupName);
}
@RequestMapping(value = "/deleteConsumerMonitor.do", method = {RequestMethod.POST})
@ResponseBody
public Object deleteConsumerMonitor(@RequestParam String consumeGroupName) {
return monitorService.deleteConsumerMonitor(consumeGroupName);
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.dashboard.controller;
import javax.annotation.Resource;
import org.apache.rocketmq.dashboard.aspect.admin.annotation.OriginalControllerReturnValue;
import org.apache.rocketmq.dashboard.service.OpsService;
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.ResponseBody;
@Controller
@RequestMapping("/rocketmq")
public class NamesvrController {
@Resource
private OpsService opsService;
@RequestMapping(value = "/nsaddr", method = RequestMethod.GET)
@ResponseBody
@OriginalControllerReturnValue
public Object nsaddr() {
return opsService.getNameSvrList();
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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.dashboard.controller;
import javax.annotation.Resource;
import org.apache.rocketmq.dashboard.service.OpsService;
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("/ops")
public class OpsController {
@Resource
private OpsService opsService;
@RequestMapping(value = "/homePage.query", method = RequestMethod.GET)
@ResponseBody
public Object homePage() {
return opsService.homePageInfo();
}
@RequestMapping(value = "/updateNameSvrAddr.do", method = RequestMethod.POST)
@ResponseBody
public Object updateNameSvrAddr(@RequestParam String nameSvrAddrList) {
opsService.updateNameSvrAddrList(nameSvrAddrList);
return true;
}
@RequestMapping(value = "/updateIsVIPChannel.do", method = RequestMethod.POST)
@ResponseBody
public Object updateIsVIPChannel(@RequestParam String useVIPChannel) {
opsService.updateIsVIPChannel(useVIPChannel);
return true;
}
@RequestMapping(value = "/rocketMqStatus.query", method = RequestMethod.GET)
@ResponseBody
public Object clusterStatus() {
return opsService.rocketMqStatusCheck();
}
@RequestMapping(value = "/updateUseTLS.do", method = RequestMethod.POST)
@ResponseBody
public Object updateUseTLS(@RequestParam String useTLS) {
opsService.updateUseTLS(Boolean.parseBoolean(useTLS));
return true;
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.dashboard.controller;
import javax.annotation.Resource;
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
import org.apache.rocketmq.dashboard.model.ConnectionInfo;
import org.apache.rocketmq.dashboard.service.ProducerService;
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("/producer")
public class ProducerController {
@Resource
private ProducerService producerService;
@RequestMapping(value = "/producerConnection.query", method = {RequestMethod.GET})
@ResponseBody
public Object producerConnection(@RequestParam String producerGroup, @RequestParam String topic) {
ProducerConnection producerConnection = producerService.getProducerConnection(producerGroup, topic);
producerConnection.setConnectionSet(ConnectionInfo.buildConnectionInfoHashSet(producerConnection.getConnectionSet()));
return producerConnection;
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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.dashboard.controller;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.util.List;
import javax.annotation.Resource;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.util.JsonUtil;
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.ResponseBody;
@Controller
@RequestMapping("/test")
public class TestController {
private Logger logger = LoggerFactory.getLogger(TestController.class);
private String testTopic = "TestTopic";
@Resource
private RMQConfigure rMQConfigure;
@RequestMapping(value = "/runTask.do", method = RequestMethod.GET)
@ResponseBody
public Object list() throws MQClientException, RemotingException, InterruptedException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(testTopic + "Group");
consumer.setNamesrvAddr(rMQConfigure.getNamesrvAddr());
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
consumer.subscribe(testTopic, "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
logger.info("receiveMessage msgSize={}", msgs.size());
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
final DefaultMQProducer producer = new DefaultMQProducer(testTopic + "Group");
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
producer.setNamesrvAddr(rMQConfigure.getNamesrvAddr());
producer.start();
new Thread(new Runnable() {
@Override public void run() {
int i = 0;
while (true) {
try {
Message msg = new Message(testTopic,
"TagA" + i,
"KEYS" + i,
("Hello RocketMQ " + i).getBytes()
);
Thread.sleep(1000L);
SendResult sendResult = producer.send(msg);
logger.info("sendMessage={}", JsonUtil.obj2String(sendResult));
}
catch (Exception e) {
e.printStackTrace();
try {
Thread.sleep(1000);
}
catch (Exception ignore) {
}
}
}
}
}).start();
return true;
}
}

View File

@@ -0,0 +1,122 @@
/*
* 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.dashboard.controller;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
import org.apache.rocketmq.dashboard.service.ConsumerService;
import org.apache.rocketmq.dashboard.service.TopicService;
import org.apache.rocketmq.dashboard.util.JsonUtil;
import com.google.common.base.Preconditions;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/topic")
public class TopicController {
private Logger logger = LoggerFactory.getLogger(TopicController.class);
@Resource
private TopicService topicService;
@Resource
private ConsumerService consumerService;
@RequestMapping(value = "/list.query", method = RequestMethod.GET)
@ResponseBody
public Object list(@RequestParam(value = "skipSysProcess", required = false) String skipSysProcess)
throws MQClientException, RemotingException, InterruptedException {
boolean flag = false;
if ("true".equals(skipSysProcess)) {
flag = true;
}
return topicService.fetchAllTopicList(flag);
}
@RequestMapping(value = "/stats.query", method = RequestMethod.GET)
@ResponseBody
public Object stats(@RequestParam String topic) {
return topicService.stats(topic);
}
@RequestMapping(value = "/route.query", method = RequestMethod.GET)
@ResponseBody
public Object route(@RequestParam String topic) {
return topicService.route(topic);
}
@RequestMapping(value = "/createOrUpdate.do", method = { RequestMethod.POST})
@ResponseBody
public Object topicCreateOrUpdateRequest(@RequestBody TopicConfigInfo topicCreateOrUpdateRequest) {
Preconditions.checkArgument(CollectionUtils.isNotEmpty(topicCreateOrUpdateRequest.getBrokerNameList()) || CollectionUtils.isNotEmpty(topicCreateOrUpdateRequest.getClusterNameList()),
"clusterName or brokerName can not be all blank");
logger.info("op=look topicCreateOrUpdateRequest={}", JsonUtil.obj2String(topicCreateOrUpdateRequest));
topicService.createOrUpdate(topicCreateOrUpdateRequest);
return true;
}
@RequestMapping(value = "/queryConsumerByTopic.query")
@ResponseBody
public Object queryConsumerByTopic(@RequestParam String topic) {
return consumerService.queryConsumeStatsListByTopicName(topic);
}
@RequestMapping(value = "/queryTopicConsumerInfo.query")
@ResponseBody
public Object queryTopicConsumerInfo(@RequestParam String topic) {
return topicService.queryTopicConsumerInfo(topic);
}
@RequestMapping(value = "/examineTopicConfig.query")
@ResponseBody
public Object examineTopicConfig(@RequestParam String topic,
@RequestParam(required = false) String brokerName) throws RemotingException, MQClientException, InterruptedException {
return topicService.examineTopicConfig(topic);
}
@RequestMapping(value = "/sendTopicMessage.do", method = {RequestMethod.POST})
@ResponseBody
public Object sendTopicMessage(
@RequestBody SendTopicMessageRequest sendTopicMessageRequest) throws RemotingException, MQClientException, InterruptedException {
return topicService.sendTopicMessageRequest(sendTopicMessageRequest);
}
@RequestMapping(value = "/deleteTopic.do", method = {RequestMethod.POST})
@ResponseBody
public Object delete(@RequestParam(required = false) String clusterName, @RequestParam String topic) {
return topicService.deleteTopic(topic, clusterName);
}
@RequestMapping(value = "/deleteTopicByBroker.do", method = {RequestMethod.POST})
@ResponseBody
public Object deleteTopicByBroker(@RequestParam String brokerName, @RequestParam String topic) {
return topicService.deleteTopicInBroker(brokerName, topic);
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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.dashboard.exception;
public class ServiceException extends RuntimeException {
private static final long serialVersionUID = 9213584003139969215L;
private int code;
public ServiceException(int code, String message) {
super(message);
this.code = code;
}
public int getCode() {
return code;
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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.dashboard.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;
@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() {
}
}

View File

@@ -0,0 +1,38 @@
/*
* 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.dashboard.interceptor;
import org.apache.rocketmq.dashboard.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
@Autowired
private LoginService loginService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return loginService.login(request, response);
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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.dashboard.model;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.HashSet;
import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.common.protocol.body.Connection;
public class ConnectionInfo extends Connection {
private String versionDesc;
public static ConnectionInfo buildConnectionInfo(Connection connection) {
ConnectionInfo connectionInfo = new ConnectionInfo();
connectionInfo.setClientId(connection.getClientId());
connectionInfo.setClientAddr(connection.getClientAddr());
connectionInfo.setLanguage(connection.getLanguage());
connectionInfo.setVersion(connection.getVersion());
connectionInfo.setVersionDesc(MQVersion.getVersionDesc(connection.getVersion()));
return connectionInfo;
}
public static HashSet<Connection> buildConnectionInfoHashSet(Collection<Connection> connectionList) {
HashSet<Connection> connectionHashSet = Sets.newHashSet();
for (Connection connection : connectionList) {
connectionHashSet.add(buildConnectionInfo(connection));
}
return connectionHashSet;
}
public String getVersionDesc() {
return versionDesc;
}
public void setVersionDesc(String versionDesc) {
this.versionDesc = versionDesc;
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.dashboard.model;
import org.apache.rocketmq.common.admin.RollbackStats;
import com.google.common.collect.Lists;
import java.util.List;
public class ConsumerGroupRollBackStat {
private boolean status;
private String errMsg;
private List<RollbackStats> rollbackStatsList = Lists.newArrayList();
public ConsumerGroupRollBackStat(boolean status) {
this.status = status;
}
public ConsumerGroupRollBackStat(boolean status, String errMsg) {
this.status = status;
this.errMsg = errMsg;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public List<RollbackStats> getRollbackStatsList() {
return rollbackStatsList;
}
public void setRollbackStatsList(List<RollbackStats> rollbackStatsList) {
this.rollbackStatsList = rollbackStatsList;
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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.dashboard.model;
public class ConsumerMonitorConfig {
private int minCount;
private int maxDiffTotal;
public ConsumerMonitorConfig() {
}
public ConsumerMonitorConfig(int minCount, int maxDiffTotal) {
this.minCount = minCount;
this.maxDiffTotal = maxDiffTotal;
}
public int getMinCount() {
return minCount;
}
public void setMinCount(int minCount) {
this.minCount = minCount;
}
public int getMaxDiffTotal() {
return maxDiffTotal;
}
public void setMaxDiffTotal(int maxDiffTotal) {
this.maxDiffTotal = maxDiffTotal;
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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.dashboard.model;
import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
public class GroupConsumeInfo implements Comparable<GroupConsumeInfo> {
private String group;
private String version;
private int count;
private ConsumeType consumeType;
private MessageModel messageModel;
private int consumeTps;
private long diffTotal = -1;
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public ConsumeType getConsumeType() {
return consumeType;
}
public void setConsumeType(ConsumeType consumeType) {
this.consumeType = consumeType;
}
public MessageModel getMessageModel() {
return messageModel;
}
public void setMessageModel(MessageModel messageModel) {
this.messageModel = messageModel;
}
public long getDiffTotal() {
return diffTotal;
}
public void setDiffTotal(long diffTotal) {
this.diffTotal = diffTotal;
}
@Override
public int compareTo(GroupConsumeInfo o) {
if (this.count != o.count) {
return Integer.compare(o.count, this.count);
}
return Long.compare(o.diffTotal, this.diffTotal);
}
public int getConsumeTps() {
return consumeTps;
}
public void setConsumeTps(int consumeTps) {
this.consumeTps = consumeTps;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.dashboard.model;
public class LoginInfo {
private boolean loginRequired;
private boolean logined;
public boolean isLoginRequired() {
return loginRequired;
}
public void setLoginRequired(boolean loginRequired) {
this.loginRequired = loginRequired;
}
public boolean isLogined() {
return logined;
}
public void setLogined(boolean logined) {
this.logined = logined;
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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.dashboard.model;
import org.springframework.data.domain.Page;
public class MessagePage {
private Page<MessageView> page;
private String taskId;
public MessagePage(Page<MessageView> page, String taskId) {
this.page = page;
this.taskId = taskId;
}
public Page<MessageView> getPage() {
return page;
}
public void setPage(Page<MessageView> page) {
this.page = page;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
@Override
public String toString() {
return "MessagePage{" +
"page=" + page +
", taskId='" + taskId + '\'' +
'}';
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.dashboard.model;
import org.springframework.data.domain.Page;
import java.util.List;
public class MessagePageTask {
private Page<MessageView> page;
private List<QueueOffsetInfo> queueOffsetInfos;
public MessagePageTask(Page<MessageView> page, List<QueueOffsetInfo> queueOffsetInfos) {
this.page = page;
this.queueOffsetInfos = queueOffsetInfos;
}
public Page<MessageView> getPage() {
return page;
}
public void setPage(Page<MessageView> page) {
this.page = page;
}
public List<QueueOffsetInfo> getQueueOffsetInfos() {
return queueOffsetInfos;
}
public void setQueueOffsetInfos(List<QueueOffsetInfo> queueOffsetInfos) {
this.queueOffsetInfos = queueOffsetInfos;
}
@Override
public String toString() {
return "MessagePageTask{" +
"page=" + page +
", queueOffsetInfos=" + queueOffsetInfos +
'}';
}
}

View File

@@ -0,0 +1,107 @@
/*
* 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.dashboard.model;
import org.springframework.data.domain.PageRequest;
public class MessageQueryByPage {
public static final int DEFAULT_PAGE = 0;
public static final int MIN_PAGE_SIZE = 10;
public static final int MAX_PAGE_SIZE = 100;
/**
* current page num
*/
private int pageNum;
private int pageSize;
private String topic;
private long begin;
private long end;
public MessageQueryByPage(int pageNum, int pageSize, String topic, long begin, long end) {
this.pageNum = pageNum;
this.pageSize = pageSize;
this.topic = topic;
this.begin = begin;
this.end = end;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public long getBegin() {
return begin;
}
public void setBegin(long begin) {
this.begin = begin;
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
}
public int getPageNum() {
return pageNum <= 0 ? DEFAULT_PAGE : pageNum - 1;
}
public int getPageSize() {
if (pageSize <= 1) {
return MIN_PAGE_SIZE;
} else if (pageSize > MAX_PAGE_SIZE) {
return MAX_PAGE_SIZE;
}
return this.pageSize;
}
public PageRequest page() {
return PageRequest.of(this.getPageNum(), this.getPageSize());
}
@Override
public String toString() {
return "MessageQueryByPage{" +
"pageNum=" + pageNum +
", pageSize=" + pageSize +
", topic='" + topic + '\'' +
", begin=" + begin +
", end=" + end +
'}';
}
}

View File

@@ -0,0 +1,237 @@
/*
* 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.dashboard.model;
import com.google.common.base.Charsets;
import org.apache.rocketmq.client.trace.TraceBean;
import org.apache.rocketmq.client.trace.TraceContext;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.dashboard.model.trace.MessageTraceStatusEnum;
import org.apache.rocketmq.dashboard.util.MsgTraceDecodeUtil;
import java.util.ArrayList;
import java.util.List;
public class MessageTraceView {
private String requestId;
private String msgId;
private String tags;
private String keys;
private String storeHost;
private String clientHost;
private int costTime;
private String msgType;
private String offSetMsgId;
private long timeStamp;
private String topic;
private String groupName;
private int retryTimes;
private String status;
private String transactionState;
private String transactionId;
private boolean fromTransactionCheck;
private String traceType;
public MessageTraceView() {
}
public static List<MessageTraceView> decodeFromTraceTransData(String key, MessageExt messageExt) {
List<MessageTraceView> messageTraceViewList = new ArrayList<MessageTraceView>();
String messageBody = new String(messageExt.getBody(), Charsets.UTF_8);
if (messageBody == null || messageBody.length() <= 0) {
return messageTraceViewList;
}
List<TraceContext> 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(MessageTraceStatusEnum.SUCCESS.getStatus());
} else {
messageTraceView.setStatus(MessageTraceStatusEnum.FAILED.getStatus());
}
messageTraceView.setKeys(traceBean.getKeys());
messageTraceView.setMsgId(traceBean.getMsgId());
messageTraceView.setTags(traceBean.getTags());
messageTraceView.setTopic(traceBean.getTopic());
messageTraceView.setMsgType(traceBean.getMsgType() == null ? null : traceBean.getMsgType().name());
messageTraceView.setOffSetMsgId(traceBean.getOffsetMsgId());
messageTraceView.setTimeStamp(context.getTimeStamp());
messageTraceView.setStoreHost(traceBean.getStoreHost());
messageTraceView.setClientHost(messageExt.getBornHostString());
messageTraceView.setRequestId(context.getRequestId());
messageTraceView.setRetryTimes(traceBean.getRetryTimes());
messageTraceView.setTransactionState(traceBean.getTransactionState() == null ? null : traceBean.getTransactionState().name());
messageTraceView.setTransactionId(traceBean.getTransactionId());
messageTraceView.setFromTransactionCheck(traceBean.isFromTransactionCheck());
messageTraceView.setTraceType(context.getTraceType() == null ? null : context.getTraceType().name());
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;
}
public String getClientHost() {
return clientHost;
}
public void setClientHost(String clientHost) {
this.clientHost = clientHost;
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
public int getRetryTimes() {
return retryTimes;
}
public void setRetryTimes(int retryTimes) {
this.retryTimes = retryTimes;
}
public String getTransactionState() {
return transactionState;
}
public void setTransactionState(String transactionState) {
this.transactionState = transactionState;
}
public String getTransactionId() {
return transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public boolean isFromTransactionCheck() {
return fromTransactionCheck;
}
public void setFromTransactionCheck(boolean fromTransactionCheck) {
this.fromTransactionCheck = fromTransactionCheck;
}
public String getTraceType() {
return traceType;
}
public void setTraceType(String traceType) {
this.traceType = traceType;
}
}

View File

@@ -0,0 +1,196 @@
/*
* 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.dashboard.model;
import org.apache.rocketmq.common.message.MessageExt;
import com.google.common.base.Charsets;
import org.springframework.beans.BeanUtils;
import java.net.SocketAddress;
import java.util.Map;
public class MessageView {
/** from MessageExt **/
private int queueId;
private int storeSize;
private long queueOffset;
private int sysFlag;
private long bornTimestamp;
private SocketAddress bornHost;
private long storeTimestamp;
private SocketAddress storeHost;
private String msgId;
private long commitLogOffset;
private int bodyCRC;
private int reconsumeTimes;
private long preparedTransactionOffset;
/**from MessageExt**/
/** from Message **/
private String topic;
private int flag;
private Map<String, String> properties;
private String messageBody; // body
/** from Message **/
public static MessageView fromMessageExt(MessageExt messageExt) {
MessageView messageView = new MessageView();
BeanUtils.copyProperties(messageExt, messageView);
if (messageExt.getBody() != null) {
messageView.setMessageBody(new String(messageExt.getBody(), Charsets.UTF_8));
}
return messageView;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
public int getQueueId() {
return queueId;
}
public void setQueueId(int queueId) {
this.queueId = queueId;
}
public int getStoreSize() {
return storeSize;
}
public void setStoreSize(int storeSize) {
this.storeSize = storeSize;
}
public long getQueueOffset() {
return queueOffset;
}
public void setQueueOffset(long queueOffset) {
this.queueOffset = queueOffset;
}
public int getSysFlag() {
return sysFlag;
}
public void setSysFlag(int sysFlag) {
this.sysFlag = sysFlag;
}
public long getBornTimestamp() {
return bornTimestamp;
}
public void setBornTimestamp(long bornTimestamp) {
this.bornTimestamp = bornTimestamp;
}
public SocketAddress getBornHost() {
return bornHost;
}
public void setBornHost(SocketAddress bornHost) {
this.bornHost = bornHost;
}
public long getStoreTimestamp() {
return storeTimestamp;
}
public void setStoreTimestamp(long storeTimestamp) {
this.storeTimestamp = storeTimestamp;
}
public SocketAddress getStoreHost() {
return storeHost;
}
public void setStoreHost(SocketAddress storeHost) {
this.storeHost = storeHost;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public long getCommitLogOffset() {
return commitLogOffset;
}
public void setCommitLogOffset(long commitLogOffset) {
this.commitLogOffset = commitLogOffset;
}
public int getBodyCRC() {
return bodyCRC;
}
public void setBodyCRC(int bodyCRC) {
this.bodyCRC = bodyCRC;
}
public int getReconsumeTimes() {
return reconsumeTimes;
}
public void setReconsumeTimes(int reconsumeTimes) {
this.reconsumeTimes = reconsumeTimes;
}
public long getPreparedTransactionOffset() {
return preparedTransactionOffset;
}
public void setPreparedTransactionOffset(long preparedTransactionOffset) {
this.preparedTransactionOffset = preparedTransactionOffset;
}
public String getMessageBody() {
return messageBody;
}
public void setMessageBody(String messageBody) {
this.messageBody = messageBody;
}
}

View File

@@ -0,0 +1,104 @@
/*
* 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.dashboard.model;
import org.apache.rocketmq.common.message.MessageQueue;
public class QueueOffsetInfo {
private Integer idx;
private Long start;
private Long end;
private Long startOffset;
private Long endOffset;
private MessageQueue messageQueues;
public QueueOffsetInfo() {
}
public QueueOffsetInfo(Integer idx, Long start, Long end, Long startOffset, Long endOffset, MessageQueue messageQueues) {
this.idx = idx;
this.start = start;
this.end = end;
this.startOffset = startOffset;
this.endOffset = endOffset;
this.messageQueues = messageQueues;
}
public Integer getIdx() {
return idx;
}
public void setIdx(Integer idx) {
this.idx = idx;
}
public Long getStart() {
return start;
}
public void setStart(Long start) {
this.start = start;
}
public Long getEnd() {
return end;
}
public void setEnd(Long end) {
this.end = end;
}
public Long getStartOffset() {
return startOffset;
}
public void setStartOffset(Long startOffset) {
this.startOffset = startOffset;
}
public Long getEndOffset() {
return endOffset;
}
public void setEndOffset(Long endOffset) {
this.endOffset = endOffset;
}
public MessageQueue getMessageQueues() {
return messageQueues;
}
public void setMessageQueues(MessageQueue messageQueues) {
this.messageQueues = messageQueues;
}
public void incStartOffset() {
this.startOffset++;
this.endOffset++;
}
public void incEndOffset() {
this.endOffset++;
}
public void incStartOffset(long size) {
this.startOffset += size;
this.endOffset += size;
}
}

View File

@@ -0,0 +1,85 @@
/*
* 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.dashboard.model;
import org.apache.rocketmq.common.admin.OffsetWrapper;
import org.apache.rocketmq.common.message.MessageQueue;
import org.springframework.beans.BeanUtils;
public class QueueStatInfo {
private String brokerName;
private int queueId;
private long brokerOffset;
private long consumerOffset;
private String clientInfo;
private long lastTimestamp;
public static QueueStatInfo fromOffsetTableEntry(MessageQueue key, OffsetWrapper value) {
QueueStatInfo queueStatInfo = new QueueStatInfo();
BeanUtils.copyProperties(key, queueStatInfo);
BeanUtils.copyProperties(value, queueStatInfo);
return queueStatInfo;
}
public String getClientInfo() {
return clientInfo;
}
public void setClientInfo(String clientInfo) {
this.clientInfo = clientInfo;
}
public String getBrokerName() {
return brokerName;
}
public void setBrokerName(String brokerName) {
this.brokerName = brokerName;
}
public int getQueueId() {
return queueId;
}
public void setQueueId(int queueId) {
this.queueId = queueId;
}
public long getBrokerOffset() {
return brokerOffset;
}
public void setBrokerOffset(long brokerOffset) {
this.brokerOffset = brokerOffset;
}
public long getConsumerOffset() {
return consumerOffset;
}
public void setConsumerOffset(long consumerOffset) {
this.consumerOffset = consumerOffset;
}
public long getLastTimestamp() {
return lastTimestamp;
}
public void setLastTimestamp(long lastTimestamp) {
this.lastTimestamp = lastTimestamp;
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.dashboard.model;
import com.google.common.collect.Lists;
import java.util.List;
public class TopicConsumerInfo {
private String topic;
private long diffTotal;
private long lastTimestamp;
private List<QueueStatInfo> queueStatInfoList = Lists.newArrayList();
public TopicConsumerInfo(String topic) {
this.topic = topic;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public long getDiffTotal() {
return diffTotal;
}
public void setDiffTotal(long diffTotal) {
this.diffTotal = diffTotal;
}
public List<QueueStatInfo> getQueueStatInfoList() {
return queueStatInfoList;
}
public long getLastTimestamp() {
return lastTimestamp;
}
public void appendQueueStatInfo(QueueStatInfo queueStatInfo) {
queueStatInfoList.add(queueStatInfo);
diffTotal = diffTotal + (queueStatInfo.getBrokerOffset() - queueStatInfo.getConsumerOffset());
lastTimestamp = Math.max(lastTimestamp, queueStatInfo.getLastTimestamp());
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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.dashboard.model;
import org.hibernate.validator.constraints.Range;
public class User {
public static final int ORDINARY = 0;
public static final int ADMIN = 1;
private long id;
private String name;
private String password;
@Range(min = 0, max = 1)
private int type = 0;
public User(String name, String password, int type) {
this.name = name;
this.password = password;
this.type = type;
}
public User cloneOne() {
return new User(this.name, this.password, this.type);
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
", type=" + type +
'}';
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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.dashboard.model;
public class UserInfo {
public static final String USER_INFO = "userInfo";
private User user;
private long loginTime;
private String ip;
private String sessionId;
public long getLoginTime() {
return loginTime;
}
public void setLoginTime(long loginTime) {
this.loginTime = loginTime;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
@Override
public String toString() {
return "UserInfo{" +
"user=" + user +
", loginTime=" + loginTime +
", ip='" + ip + '\'' +
", sessionId='" + sessionId + '\'' +
'}';
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.dashboard.model.request;
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
import java.util.List;
public class ConsumerConfigInfo {
private List<String> clusterNameList;
private List<String> brokerNameList;
private SubscriptionGroupConfig subscriptionGroupConfig;
public ConsumerConfigInfo() {
}
public ConsumerConfigInfo(List<String> brokerNameList, SubscriptionGroupConfig subscriptionGroupConfig) {
this.brokerNameList = brokerNameList;
this.subscriptionGroupConfig = subscriptionGroupConfig;
}
public List<String> getClusterNameList() {
return clusterNameList;
}
public void setClusterNameList(List<String> clusterNameList) {
this.clusterNameList = clusterNameList;
}
public List<String> getBrokerNameList() {
return brokerNameList;
}
public void setBrokerNameList(List<String> brokerNameList) {
this.brokerNameList = brokerNameList;
}
public SubscriptionGroupConfig getSubscriptionGroupConfig() {
return subscriptionGroupConfig;
}
public void setSubscriptionGroupConfig(SubscriptionGroupConfig subscriptionGroupConfig) {
this.subscriptionGroupConfig = subscriptionGroupConfig;
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.dashboard.model.request;
import java.util.List;
public class DeleteSubGroupRequest {
private String groupName;
private List<String> brokerNameList;
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public List<String> getBrokerNameList() {
return brokerNameList;
}
public void setBrokerNameList(List<String> brokerNameList) {
this.brokerNameList = brokerNameList;
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.dashboard.model.request;
public class MessageQuery {
/**
* current page num
*/
private int pageNum;
private int pageSize;
private String topic;
private String taskId;
private long begin;
private long end;
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public long getBegin() {
return begin;
}
public void setBegin(long begin) {
this.begin = begin;
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.dashboard.model.request;
import java.util.List;
public class ResetOffsetRequest {
private List<String> consumerGroupList;
private String topic;
private long resetTime;
private boolean force;
public List<String> getConsumerGroupList() {
return consumerGroupList;
}
public void setConsumerGroupList(List<String> consumerGroupList) {
this.consumerGroupList = consumerGroupList;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public long getResetTime() {
return resetTime;
}
public void setResetTime(long resetTime) {
this.resetTime = resetTime;
}
public boolean isForce() {
return force;
}
public void setForce(boolean force) {
this.force = force;
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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.dashboard.model.request;
import lombok.Data;
@Data
public class SendTopicMessageRequest {
private String topic;
private String key;
private String tag;
private String messageBody;
private boolean traceEnabled;
}

View File

@@ -0,0 +1,114 @@
/*
* 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.dashboard.model.request;
import com.google.common.base.Objects;
import java.util.List;
public class TopicConfigInfo {
private List<String> clusterNameList;
private List<String> brokerNameList;
/** topicConfig */
private String topicName;
private int writeQueueNums;
private int readQueueNums;
private int perm;
private boolean order;
public List<String> getClusterNameList() {
return clusterNameList;
}
public void setClusterNameList(List<String> clusterNameList) {
this.clusterNameList = clusterNameList;
}
/** topicConfig */
public List<String> getBrokerNameList() {
return brokerNameList;
}
public void setBrokerNameList(List<String> brokerNameList) {
this.brokerNameList = brokerNameList;
}
public String getTopicName() {
return topicName;
}
public void setTopicName(String topicName) {
this.topicName = topicName;
}
public int getWriteQueueNums() {
return writeQueueNums;
}
public void setWriteQueueNums(int writeQueueNums) {
this.writeQueueNums = writeQueueNums;
}
public int getReadQueueNums() {
return readQueueNums;
}
public void setReadQueueNums(int readQueueNums) {
this.readQueueNums = readQueueNums;
}
public int getPerm() {
return perm;
}
public void setPerm(int perm) {
this.perm = perm;
}
public boolean isOrder() {
return order;
}
public void setOrder(boolean order) {
this.order = order;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
TopicConfigInfo that = (TopicConfigInfo) o;
return writeQueueNums == that.writeQueueNums &&
readQueueNums == that.readQueueNums &&
perm == that.perm &&
order == that.order &&
Objects.equal(topicName, that.topicName);
}
@Override
public int hashCode() {
return Objects.hashCode(topicName, writeQueueNums, readQueueNums, perm, order);
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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.dashboard.model.trace;
import lombok.Data;
import org.apache.rocketmq.dashboard.model.MessageTraceView;
import java.util.List;
@Data
public class MessageTraceGraph {
private ProducerNode producerNode;
private List<SubscriptionNode> subscriptionNodeList;
private List<MessageTraceView> messageTraceViews;
}

View File

@@ -0,0 +1,32 @@
/*
* 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.dashboard.model.trace;
import lombok.Getter;
@Getter
public enum MessageTraceStatusEnum {
SUCCESS("success"),
FAILED("failed"),
UNKNOWN("unknown");
private final String status;
MessageTraceStatusEnum(String status) {
this.status = status;
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.dashboard.model.trace;
import lombok.Data;
import java.util.List;
@Data
public class ProducerNode {
private String msgId;
private String tags;
private String keys;
private String offSetMsgId;
private String topic;
private String groupName;
private TraceNode traceNode;
private List<TraceNode> transactionNodeList;
}

View File

@@ -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.dashboard.model.trace;
import lombok.Data;
import java.util.List;
@Data
public class SubscriptionNode {
private String subscriptionGroup;
private List<TraceNode> consumeNodeList;
}

View File

@@ -0,0 +1,36 @@
/*
* 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.dashboard.model.trace;
import lombok.Data;
@Data
public class TraceNode {
private String requestId;
private String storeHost;
private String clientHost;
private int costTime;
private long beginTimestamp;
private long endTimestamp;
private int retryTimes;
private String status;
private String transactionState;
private String transactionId;
private boolean fromTransactionCheck;
private String msgType;
}

View File

@@ -0,0 +1,49 @@
/*
* 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.dashboard.service;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import com.google.common.base.Throwables;
import com.google.common.collect.Sets;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import javax.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
public abstract class AbstractCommonService {
@Resource
protected MQAdminExt mqAdminExt;
protected final Set<String> changeToBrokerNameSet(HashMap<String, Set<String>> clusterAddrTable,
List<String> clusterNameList, List<String> brokerNameList) {
Set<String> finalBrokerNameList = Sets.newHashSet();
if (CollectionUtils.isNotEmpty(clusterNameList)) {
try {
for (String clusterName : clusterNameList) {
finalBrokerNameList.addAll(clusterAddrTable.get(clusterName));
}
}
catch (Exception e) {
throw Throwables.propagate(e);
}
}
if (CollectionUtils.isNotEmpty(brokerNameList)) {
finalBrokerNameList.addAll(brokerNameList);
}
return finalBrokerNameList;
}
}

View File

@@ -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.dashboard.service;
import java.util.Map;
import java.util.Properties;
public interface ClusterService {
Map<String, Object> list();
Properties getBrokerConfig(String brokerAddr);
}

View File

@@ -0,0 +1,58 @@
/*
* 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.dashboard.service;
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
import org.apache.rocketmq.dashboard.model.ConsumerGroupRollBackStat;
import org.apache.rocketmq.dashboard.model.GroupConsumeInfo;
import org.apache.rocketmq.dashboard.model.TopicConsumerInfo;
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
import org.apache.rocketmq.dashboard.model.request.DeleteSubGroupRequest;
import org.apache.rocketmq.dashboard.model.request.ResetOffsetRequest;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface ConsumerService {
List<GroupConsumeInfo> queryGroupList();
GroupConsumeInfo queryGroup(String consumerGroup);
List<TopicConsumerInfo> queryConsumeStatsListByGroupName(String groupName);
List<TopicConsumerInfo> queryConsumeStatsList(String topic, String groupName);
Map<String, TopicConsumerInfo> queryConsumeStatsListByTopicName(String topic);
Map<String /*consumerGroup*/, ConsumerGroupRollBackStat> resetOffset(ResetOffsetRequest resetOffsetRequest);
List<ConsumerConfigInfo> examineSubscriptionGroupConfig(String group);
boolean deleteSubGroup(DeleteSubGroupRequest deleteSubGroupRequest);
boolean createAndUpdateSubscriptionGroupConfig(ConsumerConfigInfo consumerConfigInfo);
Set<String> fetchBrokerNameSetBySubscriptionGroup(String group);
ConsumerConnection getConsumerConnection(String consumerGroup);
ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack);
}

View File

@@ -0,0 +1,36 @@
/*
* 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.dashboard.service;
import com.google.common.cache.LoadingCache;
import java.io.File;
import java.util.List;
import java.util.Map;
public interface DashboardCollectService {
// todo just move the task to org.apache.rocketmq.dashboard.task.DashboardCollectTask
// the code can be reconstruct
LoadingCache<String, List<String>> getBrokerMap();
LoadingCache<String, List<String>> getTopicMap();
Map<String, List<String>> jsonDataFile2map(File file);
Map<String, List<String>> getBrokerCache(String date);
Map<String, List<String>> getTopicCache(String date);
}

View File

@@ -0,0 +1,42 @@
/*
* 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.dashboard.service;
import java.util.List;
import java.util.Map;
public interface DashboardService {
/**
* @param date format yyyy-MM-dd
*/
Map<String, List<String>> queryBrokerData(String date);
/**
* @param date format yyyy-MM-dd
*/
Map<String, List<String>> queryTopicData(String date);
/**
* @param date format yyyy-MM-dd
* @param topicName
*/
List<String> queryTopicData(String date, String topicName);
List<String> queryTopicCurrentData();
}

View File

@@ -0,0 +1,25 @@
/*
* 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.dashboard.service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface LoginService {
boolean login(HttpServletRequest request, HttpServletResponse response);
}

View File

@@ -0,0 +1,59 @@
/*
* 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.dashboard.service;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
import org.apache.rocketmq.dashboard.model.MessagePage;
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
import org.apache.rocketmq.tools.admin.api.MessageTrack;
import org.apache.rocketmq.dashboard.model.MessageView;
import java.util.List;
public interface MessageService {
/**
* @param subject
* @param msgId
*/
Pair<MessageView, List<MessageTrack>> viewMessage(String subject, final String msgId);
List<MessageView> queryMessageByTopicAndKey(final String topic, final String key);
/**
* @param topic
* @param begin
* @param end
* org.apache.rocketmq.tools.command.message.PrintMessageSubCommand
*/
List<MessageView> queryMessageByTopic(final String topic, final long begin,
final long end);
List<MessageTrack> messageTrackDetail(MessageExt msg);
ConsumeMessageDirectlyResult consumeMessageDirectly(String topic, String msgId, String consumerGroup,
String clientId);
MessagePage queryMessageByPage(MessageQuery query);
}

View File

@@ -0,0 +1,31 @@
/*
* 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.dashboard.service;
import java.util.List;
import org.apache.rocketmq.dashboard.model.MessageTraceView;
import org.apache.rocketmq.dashboard.model.trace.MessageTraceGraph;
public interface MessageTraceService {
List<MessageTraceView> queryMessageTraceKey(final String key);
List<MessageTraceView> queryMessageTraceByTopicAndKey(final String topic, final String key);
MessageTraceGraph queryMessageTraceGraph(final String key);
}

View File

@@ -0,0 +1,30 @@
/*
* 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.dashboard.service;
import java.util.Map;
import org.apache.rocketmq.dashboard.model.ConsumerMonitorConfig;
public interface MonitorService {
boolean createOrUpdateConsumerMonitor(String name, ConsumerMonitorConfig config);
Map<String, ConsumerMonitorConfig> queryConsumerMonitorConfig();
ConsumerMonitorConfig queryConsumerMonitorConfigByGroupName(String consumeGroupName);
boolean deleteConsumerMonitor(String consumeGroupName);
}

View File

@@ -0,0 +1,34 @@
/*
* 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.dashboard.service;
import java.util.Map;
import org.apache.rocketmq.dashboard.service.checker.CheckerType;
public interface OpsService {
Map<String, Object> homePageInfo();
void updateNameSvrAddrList(String nameSvrAddrList);
String getNameSvrList();
Map<CheckerType,Object> rocketMqStatusCheck();
boolean updateIsVIPChannel(String useVIPChannel);
boolean updateUseTLS(boolean useTLS);
}

View File

@@ -0,0 +1,24 @@
/*
* 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.dashboard.service;
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
public interface ProducerService {
ProducerConnection getProducerConnection(String producerGroup, String topic);
}

View File

@@ -0,0 +1,54 @@
/*
* 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.dashboard.service;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.common.admin.TopicStatsTable;
import org.apache.rocketmq.common.protocol.body.GroupList;
import org.apache.rocketmq.common.protocol.body.TopicList;
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
import java.util.List;
public interface TopicService {
TopicList fetchAllTopicList(boolean skipSysProcess);
TopicStatsTable stats(String topic);
TopicRouteData route(String topic);
GroupList queryTopicConsumerInfo(String topic);
void createOrUpdate(TopicConfigInfo topicCreateOrUpdateRequest);
TopicConfig examineTopicConfig(String topic, String brokerName);
List<TopicConfigInfo> examineTopicConfig(String topic);
boolean deleteTopic(String topic, String clusterName);
boolean deleteTopic(String topic);
boolean deleteTopicInBroker(String brokerName, String topic);
SendResult sendTopicMessageRequest(SendTopicMessageRequest sendTopicMessageRequest);
}

View File

@@ -0,0 +1,25 @@
/*
* 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.dashboard.service;
import org.apache.rocketmq.dashboard.model.User;
public interface UserService {
User queryByName(String name);
User queryByUsernameAndPassword(String username, String password);
}

View File

@@ -0,0 +1,23 @@
/*
* 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.dashboard.service.checker;
public enum CheckerType {
CLUSTER_HEALTH_CHECK,
TOPIC_ONLY_ONE_BROKER_CHECK
}

View File

@@ -0,0 +1,24 @@
/*
* 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.dashboard.service.checker;
public interface RocketMqChecker {
public Object doCheck();
public CheckerType checkerType();
}

View File

@@ -0,0 +1,34 @@
/*
* 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.dashboard.service.checker.impl;
import org.apache.rocketmq.dashboard.service.checker.CheckerType;
import org.apache.rocketmq.dashboard.service.checker.RocketMqChecker;
import org.springframework.stereotype.Service;
@Service
public class ClusterHealthCheckerImpl implements RocketMqChecker {
@Override
public Object doCheck() {
return null;
}
@Override
public CheckerType checkerType() {
return CheckerType.CLUSTER_HEALTH_CHECK;
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.dashboard.service.checker.impl;
import org.apache.rocketmq.dashboard.service.checker.CheckerType;
import org.apache.rocketmq.dashboard.service.checker.RocketMqChecker;
import org.springframework.stereotype.Service;
/**
* TODO
* here the checkers is not implemented yet
*/
@Service
public class TopicOnlyOneBrokerCheckerImpl implements RocketMqChecker {
@Override
public Object doCheck() {
return null;
}
@Override
public CheckerType checkerType() {
return CheckerType.TOPIC_ONLY_ONE_BROKER_CHECK;
}
}

View File

@@ -0,0 +1,551 @@
/*
* 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.dashboard.service.client;
import com.google.common.base.Throwables;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.rocketmq.client.QueryResult;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.impl.MQAdminImpl;
import org.apache.rocketmq.common.AclConfig;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.common.admin.ConsumeStats;
import org.apache.rocketmq.common.admin.RollbackStats;
import org.apache.rocketmq.common.admin.TopicStatsTable;
import org.apache.rocketmq.common.message.MessageClientIDSetter;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.protocol.RequestCode;
import org.apache.rocketmq.common.protocol.ResponseCode;
import org.apache.rocketmq.common.protocol.body.BrokerStatsData;
import org.apache.rocketmq.common.protocol.body.ClusterAclVersionInfo;
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
import org.apache.rocketmq.common.protocol.body.ConsumeStatsList;
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
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;
import org.apache.rocketmq.common.protocol.body.TopicList;
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
import org.apache.rocketmq.dashboard.util.JsonUtil;
import org.apache.rocketmq.remoting.RemotingClient;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.exception.RemotingConnectException;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.apache.rocketmq.tools.admin.api.MessageTrack;
import org.joor.Reflect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import static org.apache.rocketmq.remoting.protocol.RemotingSerializable.decode;
@Service
public class MQAdminExtImpl implements MQAdminExt {
private Logger logger = LoggerFactory.getLogger(MQAdminExtImpl.class);
public MQAdminExtImpl() {
}
@Override
public void updateBrokerConfig(String brokerAddr, Properties properties)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
UnsupportedEncodingException, InterruptedException, MQBrokerException {
MQAdminInstance.threadLocalMQAdminExt().updateBrokerConfig(brokerAddr, properties);
}
@Override
public void createAndUpdateTopicConfig(String addr, TopicConfig config)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createAndUpdateTopicConfig(addr, config);
}
@Override public void createAndUpdatePlainAccessConfig(String addr,
PlainAccessConfig plainAccessConfig) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
}
@Override public void deletePlainAccessConfig(String addr,
String accessKey) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
}
@Override public void updateGlobalWhiteAddrConfig(String addr,
String globalWhiteAddrs) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
}
@Override public ClusterAclVersionInfo examineBrokerClusterAclVersionInfo(
String addr) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
return null;
}
@Override public AclConfig examineBrokerClusterAclConfig(
String addr) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
return null;
}
@Override
public void createAndUpdateSubscriptionGroupConfig(String addr, SubscriptionGroupConfig config)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createAndUpdateSubscriptionGroupConfig(addr, config);
}
@Override
public SubscriptionGroupConfig examineSubscriptionGroupConfig(String addr, String group) {
RemotingClient remotingClient = MQAdminInstance.threadLocalRemotingClient();
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ALL_SUBSCRIPTIONGROUP_CONFIG, null);
RemotingCommand response = null;
try {
response = remotingClient.invokeSync(addr, request, 3000);
}
catch (Exception err) {
throw Throwables.propagate(err);
}
assert response != null;
switch (response.getCode()) {
case ResponseCode.SUCCESS: {
SubscriptionGroupWrapper subscriptionGroupWrapper = decode(response.getBody(), SubscriptionGroupWrapper.class);
return subscriptionGroupWrapper.getSubscriptionGroupTable().get(group);
}
default:
throw Throwables.propagate(new MQBrokerException(response.getCode(), response.getRemark()));
}
}
@Override
public TopicConfig examineTopicConfig(String addr, String topic) {
RemotingClient remotingClient = MQAdminInstance.threadLocalRemotingClient();
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ALL_TOPIC_CONFIG, null);
RemotingCommand response = null;
try {
response = remotingClient.invokeSync(addr, request, 3000);
}
catch (Exception err) {
throw Throwables.propagate(err);
}
switch (response.getCode()) {
case ResponseCode.SUCCESS: {
TopicConfigSerializeWrapper topicConfigSerializeWrapper = decode(response.getBody(), TopicConfigSerializeWrapper.class);
return topicConfigSerializeWrapper.getTopicConfigTable().get(topic);
}
default:
throw Throwables.propagate(new MQBrokerException(response.getCode(), response.getRemark()));
}
}
@Override
public TopicStatsTable examineTopicStats(String topic)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineTopicStats(topic);
}
@Override
public TopicList fetchAllTopicList() throws RemotingException, MQClientException, InterruptedException {
TopicList topicList = MQAdminInstance.threadLocalMQAdminExt().fetchAllTopicList();
logger.debug("op=look={}", JsonUtil.obj2String(topicList.getTopicList()));
return topicList;
}
@Override
public KVTable fetchBrokerRuntimeStats(String brokerAddr)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().fetchBrokerRuntimeStats(brokerAddr);
}
@Override
public ConsumeStats examineConsumeStats(String consumerGroup)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(consumerGroup);
}
@Override
public ConsumeStats examineConsumeStats(String consumerGroup, String topic)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(consumerGroup, topic);
}
@Override
public ClusterInfo examineBrokerClusterInfo()
throws InterruptedException, MQBrokerException, RemotingTimeoutException, RemotingSendRequestException,
RemotingConnectException {
return MQAdminInstance.threadLocalMQAdminExt().examineBrokerClusterInfo();
}
@Override
public TopicRouteData examineTopicRouteInfo(String topic)
throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().examineTopicRouteInfo(topic);
}
@Override
public ConsumerConnection examineConsumerConnectionInfo(String consumerGroup)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException, RemotingException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().examineConsumerConnectionInfo(consumerGroup);
}
@Override
public ProducerConnection examineProducerConnectionInfo(String producerGroup, String topic)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().examineProducerConnectionInfo(producerGroup, topic);
}
@Override
public List<String> getNameServerAddressList() {
return MQAdminInstance.threadLocalMQAdminExt().getNameServerAddressList();
}
@Override
public int wipeWritePermOfBroker(String namesrvAddr, String brokerName)
throws RemotingCommandException, RemotingConnectException, RemotingSendRequestException,
RemotingTimeoutException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().wipeWritePermOfBroker(namesrvAddr, brokerName);
}
@Override
public void putKVConfig(String namespace, String key, String value) {
MQAdminInstance.threadLocalMQAdminExt().putKVConfig(namespace, key, value);
}
@Override
public String getKVConfig(String namespace, String key)
throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getKVConfig(namespace, key);
}
@Override
public KVTable getKVListByNamespace(String namespace)
throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getKVListByNamespace(namespace);
}
@Override
public void deleteTopicInBroker(Set<String> addrs, String topic)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
logger.info("addrs={} topic={}", JsonUtil.obj2String(addrs), topic);
MQAdminInstance.threadLocalMQAdminExt().deleteTopicInBroker(addrs, topic);
}
@Override
public void deleteTopicInNameServer(Set<String> addrs, String topic)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().deleteTopicInNameServer(addrs, topic);
}
@Override
public void deleteSubscriptionGroup(String addr, String groupName)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().deleteSubscriptionGroup(addr, groupName);
}
@Override
public void deleteSubscriptionGroup(String addr, String groupName, boolean removeOffset) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
throw new UnsupportedOperationException();
}
@Override
public void createAndUpdateKvConfig(String namespace, String key, String value)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createAndUpdateKvConfig(namespace, key, value);
}
@Override
public void deleteKvConfig(String namespace, String key)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().deleteKvConfig(namespace, key);
}
@Override
public List<RollbackStats> resetOffsetByTimestampOld(String consumerGroup, String topic, long timestamp,
boolean force) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().resetOffsetByTimestampOld(consumerGroup, topic, timestamp, force);
}
@Override
public Map<MessageQueue, Long> resetOffsetByTimestamp(String topic, String group, long timestamp,
boolean isForce) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().resetOffsetByTimestamp(topic, group, timestamp, isForce);
}
@Override
public void resetOffsetNew(String consumerGroup, String topic, long timestamp)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().resetOffsetNew(consumerGroup, topic, timestamp);
}
@Override
public Map<String, Map<MessageQueue, Long>> getConsumeStatus(String topic, String group,
String clientAddr) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().getConsumeStatus(topic, group, clientAddr);
}
@Override
public void createOrUpdateOrderConf(String key, String value, boolean isCluster)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createOrUpdateOrderConf(key, value, isCluster);
}
@Override
public GroupList queryTopicConsumeByWho(String topic)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
InterruptedException, MQBrokerException, RemotingException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().queryTopicConsumeByWho(topic);
}
@Override
public boolean cleanExpiredConsumerQueue(String cluster)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException,
InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanExpiredConsumerQueue(cluster);
}
@Override
public boolean cleanExpiredConsumerQueueByAddr(String addr)
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException,
InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanExpiredConsumerQueueByAddr(addr);
}
@Override
public ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack)
throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getConsumerRunningInfo(consumerGroup, clientId, jstack);
}
@Override
public ConsumeMessageDirectlyResult consumeMessageDirectly(String consumerGroup, String clientId,
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().consumeMessageDirectly(consumerGroup, clientId, msgId);
}
@Override
public List<MessageTrack> messageTrackDetail(MessageExt msg)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().messageTrackDetail(msg);
}
@Override
public void cloneGroupOffset(String srcGroup, String destGroup, String topic, boolean isOffline)
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
MQAdminInstance.threadLocalMQAdminExt().cloneGroupOffset(srcGroup, destGroup, topic, isOffline);
}
@Override
public void createTopic(String key, String newTopic, int queueNum) throws MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum);
}
@Override
public void createTopic(String key, String newTopic, int queueNum, int topicSysFlag)
throws MQClientException {
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum, topicSysFlag);
}
@Override
public long searchOffset(MessageQueue mq, long timestamp) throws MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().searchOffset(mq, timestamp);
}
@Override
public long maxOffset(MessageQueue mq) throws MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().maxOffset(mq);
}
@Override
public long minOffset(MessageQueue mq) throws MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().minOffset(mq);
}
@Override
public long earliestMsgStoreTime(MessageQueue mq) throws MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().earliestMsgStoreTime(mq);
}
@Override
public MessageExt viewMessage(String msgId)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().viewMessage(msgId);
}
@Override
public QueryResult queryMessage(String topic, String key, int maxNum, long begin, long end)
throws MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().queryMessage(topic, key, maxNum, begin, end);
}
@Override
@Deprecated
public void start() throws MQClientException {
throw new IllegalStateException("thisMethod is deprecated.use org.apache.rocketmq.dashboard.aspect.admin.MQAdminAspect instead of this");
}
@Override
@Deprecated
public void shutdown() {
throw new IllegalStateException("thisMethod is deprecated.use org.apache.rocketmq.dashboard.aspect.admin.MQAdminAspect instead of this");
}
// below is 3.2.6->3.5.8 updated
@Override
public List<QueueTimeSpan> queryConsumeTimeSpan(String topic,
String group) throws InterruptedException, MQBrokerException, RemotingException, MQClientException {
return MQAdminInstance.threadLocalMQAdminExt().queryConsumeTimeSpan(topic, group);
}
//MessageClientIDSetter.getNearlyTimeFromID has bug,so we subtract half a day
//next version we will remove it
//https://issues.apache.org/jira/browse/ROCKETMQ-111
//https://github.com/apache/incubator-rocketmq/pull/69
@Override
public MessageExt viewMessage(String topic,
String msgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
logger.info("MessageClientIDSetter.getNearlyTimeFromID(msgId)={} msgId={}", MessageClientIDSetter.getNearlyTimeFromID(msgId), msgId);
try {
return viewMessage(msgId);
}
catch (Exception e) {
}
MQAdminImpl mqAdminImpl = MQAdminInstance.threadLocalMqClientInstance().getMQAdminImpl();
QueryResult qr = Reflect.on(mqAdminImpl).call("queryMessage", topic, msgId, 32,
MessageClientIDSetter.getNearlyTimeFromID(msgId).getTime() - 1000 * 60 * 60 * 13L, Long.MAX_VALUE, true).get();
if (qr != null && qr.getMessageList() != null && qr.getMessageList().size() > 0) {
return qr.getMessageList().get(0);
}
else {
return null;
}
}
@Override
public ConsumeMessageDirectlyResult consumeMessageDirectly(String consumerGroup, String clientId, String topic,
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().consumeMessageDirectly(consumerGroup, clientId, topic, msgId);
}
@Override
public Properties getBrokerConfig(
String brokerAddr) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, UnsupportedEncodingException, InterruptedException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().getBrokerConfig(brokerAddr);
}
@Override
public TopicList fetchTopicsByCLuster(
String clusterName) throws RemotingException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().fetchTopicsByCLuster(clusterName);
}
@Override
public boolean cleanUnusedTopic(
String cluster) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanUnusedTopic(cluster);
}
@Override
public boolean cleanUnusedTopicByAddr(
String addr) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().cleanUnusedTopicByAddr(addr);
}
@Override
public BrokerStatsData viewBrokerStatsData(String brokerAddr, String statsName,
String statsKey) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().viewBrokerStatsData(brokerAddr, statsName, statsKey);
}
@Override
public Set<String> getClusterList(
String topic) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().getClusterList(topic);
}
@Override
public ConsumeStatsList fetchConsumeStatsInBroker(String brokerAddr, boolean isOrder,
long timeoutMillis) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
return MQAdminInstance.threadLocalMQAdminExt().fetchConsumeStatsInBroker(brokerAddr, isOrder, timeoutMillis);
}
@Override
public Set<String> getTopicClusterList(
String topic) throws InterruptedException, MQBrokerException, MQClientException, RemotingException {
return MQAdminInstance.threadLocalMQAdminExt().getTopicClusterList(topic);
}
@Override
public SubscriptionGroupWrapper getAllSubscriptionGroup(String brokerAddr,
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().getAllSubscriptionGroup(brokerAddr, timeoutMillis);
}
@Override
public TopicConfigSerializeWrapper getAllTopicGroup(String brokerAddr,
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException {
return MQAdminInstance.threadLocalMQAdminExt().getAllTopicGroup(brokerAddr, timeoutMillis);
}
@Override
public void updateConsumeOffset(String brokerAddr, String consumeGroup, MessageQueue mq,
long offset) throws RemotingException, InterruptedException, MQBrokerException {
MQAdminInstance.threadLocalMQAdminExt().updateConsumeOffset(brokerAddr, consumeGroup, mq, offset);
}
// 4.0.0 added
@Override public void updateNameServerConfig(Properties properties,
List<String> list) throws InterruptedException, RemotingConnectException, UnsupportedEncodingException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, MQBrokerException {
}
@Override public Map<String, Properties> getNameServerConfig(
List<String> 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;
}
@Override public boolean resumeCheckHalfMessage(
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return false;
}
@Override public boolean resumeCheckHalfMessage(String topic,
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
return false;
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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.dashboard.service.client;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.acl.common.AclClientRPCHook;
import org.apache.rocketmq.acl.common.SessionCredentials;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.impl.MQClientAPIImpl;
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.RemotingClient;
import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
import org.apache.rocketmq.tools.admin.DefaultMQAdminExtImpl;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.joor.Reflect;
public class MQAdminInstance {
private static final ThreadLocal<DefaultMQAdminExt> MQ_ADMIN_EXT_THREAD_LOCAL = new ThreadLocal<DefaultMQAdminExt>();
private static final ThreadLocal<Integer> INIT_COUNTER = new ThreadLocal<Integer>();
public static MQAdminExt threadLocalMQAdminExt() {
DefaultMQAdminExt defaultMQAdminExt = MQ_ADMIN_EXT_THREAD_LOCAL.get();
if (defaultMQAdminExt == null) {
throw new IllegalStateException("defaultMQAdminExt should be init before you get this");
}
return defaultMQAdminExt;
}
public static RemotingClient threadLocalRemotingClient() {
MQClientInstance mqClientInstance = threadLocalMqClientInstance();
MQClientAPIImpl mQClientAPIImpl = Reflect.on(mqClientInstance).get("mQClientAPIImpl");
return Reflect.on(mQClientAPIImpl).get("remotingClient");
}
public static MQClientInstance threadLocalMqClientInstance() {
DefaultMQAdminExtImpl defaultMQAdminExtImpl = Reflect.on(MQAdminInstance.threadLocalMQAdminExt()).get("defaultMQAdminExtImpl");
return Reflect.on(defaultMQAdminExtImpl).get("mqClientInstance");
}
public static void initMQAdminInstance(long timeoutMillis,String accessKey,String secretKey, boolean useTLS) throws MQClientException {
Integer nowCount = INIT_COUNTER.get();
if (nowCount == null) {
RPCHook rpcHook = null;
boolean isEnableAcl = !StringUtils.isEmpty(accessKey) && !StringUtils.isEmpty(secretKey);
if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(accessKey, secretKey));
}
DefaultMQAdminExt defaultMQAdminExt;
if (timeoutMillis > 0) {
defaultMQAdminExt = new DefaultMQAdminExt(rpcHook,timeoutMillis);
}
else {
defaultMQAdminExt = new DefaultMQAdminExt(rpcHook);
}
defaultMQAdminExt.setUseTLS(useTLS);
defaultMQAdminExt.setInstanceName(Long.toString(System.currentTimeMillis()));
defaultMQAdminExt.start();
MQ_ADMIN_EXT_THREAD_LOCAL.set(defaultMQAdminExt);
INIT_COUNTER.set(1);
}
else {
INIT_COUNTER.set(nowCount + 1);
}
}
public static void destroyMQAdminInstance() {
Integer nowCount = INIT_COUNTER.get() - 1;
if (nowCount > 0) {
INIT_COUNTER.set(nowCount);
return;
}
MQAdminExt mqAdminExt = MQ_ADMIN_EXT_THREAD_LOCAL.get();
if (mqAdminExt != null) {
mqAdminExt.shutdown();
MQ_ADMIN_EXT_THREAD_LOCAL.remove();
INIT_COUNTER.remove();
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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.dashboard.service.impl;
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
import org.apache.rocketmq.common.protocol.body.KVTable;
import org.apache.rocketmq.common.protocol.route.BrokerData;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.apache.rocketmq.dashboard.service.ClusterService;
import org.apache.rocketmq.dashboard.util.JsonUtil;
import com.google.common.base.Throwables;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Map;
import java.util.Properties;
@Service
public class ClusterServiceImpl implements ClusterService {
private Logger logger = LoggerFactory.getLogger(ClusterServiceImpl.class);
@Resource
private MQAdminExt mqAdminExt;
@Override
public Map<String, Object> list() {
try {
Map<String, Object> resultMap = Maps.newHashMap();
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
logger.info("op=look_clusterInfo {}", JsonUtil.obj2String(clusterInfo));
Map<String/*brokerName*/, Map<Long/* brokerId */, Object/* brokerDetail */>> brokerServer = Maps.newHashMap();
for (BrokerData brokerData : clusterInfo.getBrokerAddrTable().values()) {
Map<Long, Object> brokerMasterSlaveMap = Maps.newHashMap();
for (Map.Entry<Long/* brokerId */, String/* broker address */> brokerAddr : brokerData.getBrokerAddrs().entrySet()) {
KVTable kvTable = mqAdminExt.fetchBrokerRuntimeStats(brokerAddr.getValue());
brokerMasterSlaveMap.put(brokerAddr.getKey(), kvTable.getTable());
}
brokerServer.put(brokerData.getBrokerName(), brokerMasterSlaveMap);
}
resultMap.put("clusterInfo", clusterInfo);
resultMap.put("brokerServer", brokerServer);
return resultMap;
}
catch (Exception err) {
throw Throwables.propagate(err);
}
}
@Override
public Properties getBrokerConfig(String brokerAddr) {
try {
return mqAdminExt.getBrokerConfig(brokerAddr);
}
catch (Exception e) {
throw Throwables.propagate(e);
}
}
}

View File

@@ -0,0 +1,341 @@
/*
* 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.dashboard.service.impl;
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.common.admin.ConsumeStats;
import org.apache.rocketmq.common.admin.RollbackStats;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.protocol.ResponseCode;
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
import org.apache.rocketmq.common.protocol.body.Connection;
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
import org.apache.rocketmq.common.protocol.body.GroupList;
import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper;
import org.apache.rocketmq.common.protocol.route.BrokerData;
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
import org.apache.rocketmq.dashboard.aspect.admin.annotation.MultiMQAdminCmdMethod;
import org.apache.rocketmq.dashboard.model.ConsumerGroupRollBackStat;
import org.apache.rocketmq.dashboard.model.GroupConsumeInfo;
import org.apache.rocketmq.dashboard.model.QueueStatInfo;
import org.apache.rocketmq.dashboard.model.TopicConsumerInfo;
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
import org.apache.rocketmq.dashboard.model.request.DeleteSubGroupRequest;
import org.apache.rocketmq.dashboard.model.request.ResetOffsetRequest;
import org.apache.rocketmq.dashboard.service.AbstractCommonService;
import org.apache.rocketmq.dashboard.service.ConsumerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import static com.google.common.base.Throwables.propagate;
@Service
public class ConsumerServiceImpl extends AbstractCommonService implements ConsumerService {
private Logger logger = LoggerFactory.getLogger(ConsumerServiceImpl.class);
@Override
@MultiMQAdminCmdMethod
public List<GroupConsumeInfo> queryGroupList() {
Set<String> consumerGroupSet = Sets.newHashSet();
try {
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
for (BrokerData brokerData : clusterInfo.getBrokerAddrTable().values()) {
SubscriptionGroupWrapper subscriptionGroupWrapper = mqAdminExt.getAllSubscriptionGroup(brokerData.selectBrokerAddr(), 3000L);
consumerGroupSet.addAll(subscriptionGroupWrapper.getSubscriptionGroupTable().keySet());
}
}
catch (Exception err) {
throw Throwables.propagate(err);
}
List<GroupConsumeInfo> groupConsumeInfoList = Lists.newArrayList();
for (String consumerGroup : consumerGroupSet) {
groupConsumeInfoList.add(queryGroup(consumerGroup));
}
Collections.sort(groupConsumeInfoList);
return groupConsumeInfoList;
}
@Override
@MultiMQAdminCmdMethod
public GroupConsumeInfo queryGroup(String consumerGroup) {
GroupConsumeInfo groupConsumeInfo = new GroupConsumeInfo();
try {
ConsumeStats consumeStats = null;
try {
consumeStats = mqAdminExt.examineConsumeStats(consumerGroup);
}
catch (Exception e) {
logger.warn("examineConsumeStats exception to consumerGroup {}, response [{}]", consumerGroup, e.getMessage());
}
ConsumerConnection consumerConnection = null;
try {
consumerConnection = mqAdminExt.examineConsumerConnectionInfo(consumerGroup);
}
catch (Exception e) {
logger.warn("examineConsumeStats exception to consumerGroup {}, response [{}]", consumerGroup, e.getMessage());
}
groupConsumeInfo.setGroup(consumerGroup);
if (consumeStats != null) {
groupConsumeInfo.setConsumeTps((int)consumeStats.getConsumeTps());
groupConsumeInfo.setDiffTotal(consumeStats.computeTotalDiff());
}
if (consumerConnection != null) {
groupConsumeInfo.setCount(consumerConnection.getConnectionSet().size());
groupConsumeInfo.setMessageModel(consumerConnection.getMessageModel());
groupConsumeInfo.setConsumeType(consumerConnection.getConsumeType());
groupConsumeInfo.setVersion(MQVersion.getVersionDesc(consumerConnection.computeMinVersion()));
}
}
catch (Exception e) {
logger.warn("examineConsumeStats or examineConsumerConnectionInfo exception, "
+ consumerGroup, e);
}
return groupConsumeInfo;
}
@Override
public List<TopicConsumerInfo> queryConsumeStatsListByGroupName(String groupName) {
return queryConsumeStatsList(null, groupName);
}
@Override
@MultiMQAdminCmdMethod
public List<TopicConsumerInfo> queryConsumeStatsList(final String topic, String groupName) {
ConsumeStats consumeStats = null;
try {
consumeStats = mqAdminExt.examineConsumeStats(groupName, topic);
}
catch (Exception e) {
throw propagate(e);
}
List<MessageQueue> mqList = Lists.newArrayList(Iterables.filter(consumeStats.getOffsetTable().keySet(), new Predicate<MessageQueue>() {
@Override
public boolean apply(MessageQueue o) {
return StringUtils.isBlank(topic) || o.getTopic().equals(topic);
}
}));
Collections.sort(mqList);
List<TopicConsumerInfo> topicConsumerInfoList = Lists.newArrayList();
TopicConsumerInfo nowTopicConsumerInfo = null;
Map<MessageQueue, String> messageQueueClientMap = getClientConnection(groupName);
for (MessageQueue mq : mqList) {
if (nowTopicConsumerInfo == null || (!StringUtils.equals(mq.getTopic(), nowTopicConsumerInfo.getTopic()))) {
nowTopicConsumerInfo = new TopicConsumerInfo(mq.getTopic());
topicConsumerInfoList.add(nowTopicConsumerInfo);
}
QueueStatInfo queueStatInfo = QueueStatInfo.fromOffsetTableEntry(mq, consumeStats.getOffsetTable().get(mq));
queueStatInfo.setClientInfo(messageQueueClientMap.get(mq));
nowTopicConsumerInfo.appendQueueStatInfo(queueStatInfo);
}
return topicConsumerInfoList;
}
private Map<MessageQueue, String> getClientConnection(String groupName) {
Map<MessageQueue, String> results = Maps.newHashMap();
try {
ConsumerConnection consumerConnection = mqAdminExt.examineConsumerConnectionInfo(groupName);
for (Connection connection : consumerConnection.getConnectionSet()) {
String clinetId = connection.getClientId();
ConsumerRunningInfo consumerRunningInfo = mqAdminExt.getConsumerRunningInfo(groupName, clinetId, false);
for (MessageQueue messageQueue : consumerRunningInfo.getMqTable().keySet()) {
// results.put(messageQueue, clinetId + " " + connection.getClientAddr());
results.put(messageQueue, clinetId);
}
}
}
catch (Exception err) {
logger.error("op=getClientConnection_error", err);
}
return results;
}
@Override
@MultiMQAdminCmdMethod
public Map<String /*groupName*/, TopicConsumerInfo> queryConsumeStatsListByTopicName(String topic) {
Map<String, TopicConsumerInfo> group2ConsumerInfoMap = Maps.newHashMap();
try {
GroupList groupList = mqAdminExt.queryTopicConsumeByWho(topic);
for (String group : groupList.getGroupList()) {
List<TopicConsumerInfo> topicConsumerInfoList = null;
try {
topicConsumerInfoList = queryConsumeStatsList(topic, group);
}
catch (Exception ignore) {
}
group2ConsumerInfoMap.put(group, CollectionUtils.isEmpty(topicConsumerInfoList) ? new TopicConsumerInfo(topic) : topicConsumerInfoList.get(0));
}
return group2ConsumerInfoMap;
}
catch (Exception e) {
throw propagate(e);
}
}
@Override
@MultiMQAdminCmdMethod
public Map<String, ConsumerGroupRollBackStat> resetOffset(ResetOffsetRequest resetOffsetRequest) {
Map<String, ConsumerGroupRollBackStat> groupRollbackStats = Maps.newHashMap();
for (String consumerGroup : resetOffsetRequest.getConsumerGroupList()) {
try {
Map<MessageQueue, Long> rollbackStatsMap =
mqAdminExt.resetOffsetByTimestamp(resetOffsetRequest.getTopic(), consumerGroup, resetOffsetRequest.getResetTime(), resetOffsetRequest.isForce());
ConsumerGroupRollBackStat consumerGroupRollBackStat = new ConsumerGroupRollBackStat(true);
List<RollbackStats> rollbackStatsList = consumerGroupRollBackStat.getRollbackStatsList();
for (Map.Entry<MessageQueue, Long> rollbackStatsEntty : rollbackStatsMap.entrySet()) {
RollbackStats rollbackStats = new RollbackStats();
rollbackStats.setRollbackOffset(rollbackStatsEntty.getValue());
rollbackStats.setQueueId(rollbackStatsEntty.getKey().getQueueId());
rollbackStats.setBrokerName(rollbackStatsEntty.getKey().getBrokerName());
rollbackStatsList.add(rollbackStats);
}
groupRollbackStats.put(consumerGroup, consumerGroupRollBackStat);
}
catch (MQClientException e) {
if (ResponseCode.CONSUMER_NOT_ONLINE == e.getResponseCode()) {
try {
ConsumerGroupRollBackStat consumerGroupRollBackStat = new ConsumerGroupRollBackStat(true);
List<RollbackStats> rollbackStatsList = mqAdminExt.resetOffsetByTimestampOld(consumerGroup, resetOffsetRequest.getTopic(), resetOffsetRequest.getResetTime(), true);
consumerGroupRollBackStat.setRollbackStatsList(rollbackStatsList);
groupRollbackStats.put(consumerGroup, consumerGroupRollBackStat);
continue;
}
catch (Exception err) {
logger.error("op=resetOffset_which_not_online_error", err);
}
}
else {
logger.error("op=resetOffset_error", e);
}
groupRollbackStats.put(consumerGroup, new ConsumerGroupRollBackStat(false, e.getMessage()));
}
catch (Exception e) {
logger.error("op=resetOffset_error", e);
groupRollbackStats.put(consumerGroup, new ConsumerGroupRollBackStat(false, e.getMessage()));
}
}
return groupRollbackStats;
}
@Override
@MultiMQAdminCmdMethod
public List<ConsumerConfigInfo> examineSubscriptionGroupConfig(String group) {
List<ConsumerConfigInfo> consumerConfigInfoList = Lists.newArrayList();
try {
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
for (String brokerName : clusterInfo.getBrokerAddrTable().keySet()) { //foreach brokerName
String brokerAddress = clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr();
SubscriptionGroupConfig subscriptionGroupConfig = mqAdminExt.examineSubscriptionGroupConfig(brokerAddress, group);
if (subscriptionGroupConfig == null) {
continue;
}
consumerConfigInfoList.add(new ConsumerConfigInfo(Lists.newArrayList(brokerName), subscriptionGroupConfig));
}
}
catch (Exception e) {
throw propagate(e);
}
return consumerConfigInfoList;
}
@Override
@MultiMQAdminCmdMethod
public boolean deleteSubGroup(DeleteSubGroupRequest deleteSubGroupRequest) {
try {
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
for (String brokerName : deleteSubGroupRequest.getBrokerNameList()) {
logger.info("addr={} groupName={}", clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), deleteSubGroupRequest.getGroupName());
mqAdminExt.deleteSubscriptionGroup(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), deleteSubGroupRequest.getGroupName());
}
}
catch (Exception e) {
throw propagate(e);
}
return true;
}
@Override
public boolean createAndUpdateSubscriptionGroupConfig(ConsumerConfigInfo consumerConfigInfo) {
try {
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
for (String brokerName : changeToBrokerNameSet(clusterInfo.getClusterAddrTable(),
consumerConfigInfo.getClusterNameList(), consumerConfigInfo.getBrokerNameList())) {
mqAdminExt.createAndUpdateSubscriptionGroupConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), consumerConfigInfo.getSubscriptionGroupConfig());
}
}
catch (Exception err) {
throw Throwables.propagate(err);
}
return true;
}
@Override
@MultiMQAdminCmdMethod
public Set<String> fetchBrokerNameSetBySubscriptionGroup(String group) {
Set<String> brokerNameSet = Sets.newHashSet();
try {
List<ConsumerConfigInfo> consumerConfigInfoList = examineSubscriptionGroupConfig(group);
for (ConsumerConfigInfo consumerConfigInfo : consumerConfigInfoList) {
brokerNameSet.addAll(consumerConfigInfo.getBrokerNameList());
}
}
catch (Exception e) {
throw Throwables.propagate(e);
}
return brokerNameSet;
}
@Override
public ConsumerConnection getConsumerConnection(String consumerGroup) {
try {
return mqAdminExt.examineConsumerConnectionInfo(consumerGroup);
}
catch (Exception e) {
throw Throwables.propagate(e);
}
}
@Override
public ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack) {
try {
return mqAdminExt.getConsumerRunningInfo(consumerGroup, clientId, jstack);
}
catch (Exception e) {
throw Throwables.propagate(e);
}
}
}

View File

@@ -0,0 +1,157 @@
/*
* 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.dashboard.service.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Charsets;
import com.google.common.base.Throwables;
import com.google.common.base.Ticker;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.service.DashboardCollectService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class DashboardCollectServiceImpl implements DashboardCollectService {
@Resource
private RMQConfigure configure;
private final static Logger log = LoggerFactory.getLogger(DashboardCollectServiceImpl.class);
private LoadingCache<String, List<String>> brokerMap = CacheBuilder.newBuilder()
.maximumSize(1000)
.concurrencyLevel(10)
.recordStats()
.ticker(Ticker.systemTicker())
.removalListener(new RemovalListener<Object, Object>() {
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
log.debug(notification.getKey() + " was removed, cause is " + notification.getCause());
}
})
.build(
new CacheLoader<String, List<String>>() {
@Override
public List<String> load(String key) {
List<String> list = Lists.newArrayList();
return list;
}
}
);
private LoadingCache<String, List<String>> topicMap = CacheBuilder.newBuilder()
.maximumSize(1000)
.concurrencyLevel(10)
.recordStats()
.ticker(Ticker.systemTicker())
.removalListener(new RemovalListener<Object, Object>() {
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
log.debug(notification.getKey() + " was removed, cause is " + notification.getCause());
}
})
.build(
new CacheLoader<String, List<String>>() {
@Override
public List<String> load(String key) {
List<String> list = Lists.newArrayList();
return list;
}
}
);
@Override
public LoadingCache<String, List<String>> getBrokerMap() {
return brokerMap;
}
@Override
public LoadingCache<String, List<String>> getTopicMap() {
return topicMap;
}
@Override
public Map<String, List<String>> jsonDataFile2map(File file) {
List<String> strings;
try {
strings = Files.readLines(file, Charsets.UTF_8);
}
catch (IOException e) {
throw Throwables.propagate(e);
}
StringBuffer sb = new StringBuffer();
for (String string : strings) {
sb.append(string);
}
JSONObject json = (JSONObject) JSONObject.parse(sb.toString());
Set<Map.Entry<String, Object>> entries = json.entrySet();
Map<String, List<String>> map = Maps.newHashMap();
for (Map.Entry<String, Object> entry : entries) {
JSONArray tpsArray = (JSONArray) entry.getValue();
if (tpsArray == null) {
continue;
}
Object[] tpsStrArray = tpsArray.toArray();
List<String> tpsList = Lists.newArrayList();
for (Object tpsObj : tpsStrArray) {
tpsList.add("" + tpsObj);
}
map.put(entry.getKey(), tpsList);
}
return map;
}
@Override
public Map<String, List<String>> getBrokerCache(String date) {
String dataLocationPath = configure.getDashboardCollectData();
File file = new File(dataLocationPath + date + ".json");
if (!file.exists()) {
log.info(String.format("No dashboard data for broker cache data: %s", date));
return Maps.newHashMap();
}
return jsonDataFile2map(file);
}
@Override
public Map<String, List<String>> getTopicCache(String date) {
String dataLocationPath = configure.getDashboardCollectData();
File file = new File(dataLocationPath + date + "_topic" + ".json");
if (!file.exists()) {
log.info(String.format("No dashboard data for data: %s", date));
//throw Throwables.propagate(new ServiceException(1, "This date have't data!"));
return Maps.newHashMap();
}
return jsonDataFile2map(file);
}
}

View File

@@ -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.dashboard.service.impl;
import com.google.common.collect.Lists;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.rocketmq.dashboard.service.DashboardCollectService;
import org.apache.rocketmq.dashboard.service.DashboardService;
import org.springframework.stereotype.Service;
@Service
public class DashboardServiceImpl implements DashboardService {
@Resource
private DashboardCollectService dashboardCollectService;
/**
* @param date format yyyy-MM-dd
*/
@Override
public Map<String, List<String>> queryBrokerData(String date) {
return dashboardCollectService.getBrokerCache(date);
}
@Override
public Map<String, List<String>> queryTopicData(String date) {
return dashboardCollectService.getTopicCache(date);
}
/**
* @param date format yyyy-MM-dd
* @param topicName
*/
@Override
public List<String> queryTopicData(String date, String topicName) {
if (null != dashboardCollectService.getTopicCache(date)) {
return dashboardCollectService.getTopicCache(date).get(topicName);
}
return null;
}
@Override
public List<String> queryTopicCurrentData() {
Date date = new Date();
DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Map<String, List<String>> topicCache = dashboardCollectService.getTopicCache(format.format(date));
List<String> result = Lists.newArrayList();
for (Map.Entry<String, List<String>> entry : topicCache.entrySet()) {
List<String> value = entry.getValue();
result.add(entry.getKey() + "," + value.get(value.size() - 1).split(",")[4]);
}
return result;
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.dashboard.service.impl;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.service.LoginService;
import org.apache.rocketmq.dashboard.service.UserService;
import org.apache.rocketmq.dashboard.util.WebUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@Service
public class LoginServiceImpl implements LoginService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private RMQConfigure rmqConfigure;
@Autowired
private UserService userService;
@Override
public boolean login(HttpServletRequest request, HttpServletResponse response) {
if (WebUtil.getValueFromSession(request, WebUtil.USER_NAME) != null) {
return true;
}
auth(request, response);
return false;
}
protected void auth(HttpServletRequest request, HttpServletResponse response) {
try {
String url = WebUtil.getUrl(request);
try {
url = URLEncoder.encode(url, "UTF-8");
} catch (UnsupportedEncodingException e) {
logger.error("url encode:{}", url, e);
}
logger.debug("redirect url : {}", url);
WebUtil.redirect(response, request, "/#/login?redirect=" + url);
} catch (IOException e) {
logger.error("redirect err", e);
}
}
}

View File

@@ -0,0 +1,544 @@
/*
* 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.dashboard.service.impl;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.acl.common.AclClientRPCHook;
import org.apache.rocketmq.acl.common.SessionCredentials;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.consumer.PullStatus;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.message.MessageClientIDSetter;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.protocol.body.Connection;
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.exception.ServiceException;
import org.apache.rocketmq.dashboard.model.QueueOffsetInfo;
import org.apache.rocketmq.dashboard.model.MessageView;
import org.apache.rocketmq.dashboard.model.MessagePage;
import org.apache.rocketmq.dashboard.model.MessagePageTask;
import org.apache.rocketmq.dashboard.model.MessageQueryByPage;
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
import org.apache.rocketmq.dashboard.service.MessageService;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.apache.rocketmq.tools.admin.api.MessageTrack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Comparator;
import java.util.ArrayList;
import java.util.Set;
import java.util.Collection;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Service
public class MessageServiceImpl implements MessageService {
private Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class);
private static final Cache<String, List<QueueOffsetInfo>> CACHE = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(60, TimeUnit.MINUTES)
.build();
@Autowired
private RMQConfigure configure;
/**
* @see org.apache.rocketmq.store.config.MessageStoreConfig maxMsgsNumBatch = 64;
* @see org.apache.rocketmq.store.index.IndexService maxNum = Math.min(maxNum, this.defaultMessageStore.getMessageStoreConfig().getMaxMsgsNumBatch());
*/
private final static int QUERY_MESSAGE_MAX_NUM = 64;
@Resource
private MQAdminExt mqAdminExt;
@Override
public Pair<MessageView, List<MessageTrack>> viewMessage(String subject, final String msgId) {
try {
MessageExt messageExt = mqAdminExt.viewMessage(subject, msgId);
List<MessageTrack> messageTrackList = messageTrackDetail(messageExt);
return new Pair<>(MessageView.fromMessageExt(messageExt), messageTrackList);
} catch (Exception e) {
throw new ServiceException(-1, String.format("Failed to query message by Id: %s", msgId));
}
}
@Override
public List<MessageView> queryMessageByTopicAndKey(String topic, String key) {
try {
return Lists.transform(mqAdminExt.queryMessage(topic, key, QUERY_MESSAGE_MAX_NUM, 0, System.currentTimeMillis()).getMessageList(), new Function<MessageExt, MessageView>() {
@Override
public MessageView apply(MessageExt messageExt) {
return MessageView.fromMessageExt(messageExt);
}
});
} catch (Exception err) {
throw Throwables.propagate(err);
}
}
@Override
public List<MessageView> queryMessageByTopic(String topic, final long begin, final long end) {
boolean isEnableAcl = !StringUtils.isEmpty(configure.getAccessKey()) && !StringUtils.isEmpty(configure.getSecretKey());
RPCHook rpcHook = null;
if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
}
DefaultMQPullConsumer consumer = buildDefaultMQPullConsumer(rpcHook, configure.isUseTLS());
List<MessageView> messageViewList = Lists.newArrayList();
try {
String subExpression = "*";
consumer.start();
Set<MessageQueue> mqs = consumer.fetchSubscribeMessageQueues(topic);
for (MessageQueue mq : mqs) {
long minOffset = consumer.searchOffset(mq, begin);
long maxOffset = consumer.searchOffset(mq, end);
READQ:
for (long offset = minOffset; offset <= maxOffset; ) {
try {
if (messageViewList.size() > 2000) {
break;
}
PullResult pullResult = consumer.pull(mq, subExpression, offset, 32);
offset = pullResult.getNextBeginOffset();
switch (pullResult.getPullStatus()) {
case FOUND:
List<MessageView> messageViewListByQuery = Lists.transform(pullResult.getMsgFoundList(), new Function<MessageExt, MessageView>() {
@Override
public MessageView apply(MessageExt messageExt) {
messageExt.setBody(null);
return MessageView.fromMessageExt(messageExt);
}
});
List<MessageView> filteredList = Lists.newArrayList(Iterables.filter(messageViewListByQuery, new Predicate<MessageView>() {
@Override
public boolean apply(MessageView messageView) {
if (messageView.getStoreTimestamp() < begin || messageView.getStoreTimestamp() > end) {
logger.info("begin={} end={} time not in range {} {}", begin, end, messageView.getStoreTimestamp(), new Date(messageView.getStoreTimestamp()).toString());
}
return messageView.getStoreTimestamp() >= begin && messageView.getStoreTimestamp() <= end;
}
}));
messageViewList.addAll(filteredList);
break;
case NO_MATCHED_MSG:
case NO_NEW_MSG:
case OFFSET_ILLEGAL:
break READQ;
}
} catch (Exception e) {
break;
}
}
}
Collections.sort(messageViewList, new Comparator<MessageView>() {
@Override
public int compare(MessageView o1, MessageView o2) {
if (o1.getStoreTimestamp() - o2.getStoreTimestamp() == 0) {
return 0;
}
return (o1.getStoreTimestamp() > o2.getStoreTimestamp()) ? -1 : 1;
}
});
return messageViewList;
} catch (Exception e) {
throw Throwables.propagate(e);
} finally {
consumer.shutdown();
}
}
@Override
public List<MessageTrack> messageTrackDetail(MessageExt msg) {
try {
return mqAdminExt.messageTrackDetail(msg);
} catch (Exception e) {
logger.error("op=messageTrackDetailError", e);
return Collections.emptyList();
}
}
@Override
public ConsumeMessageDirectlyResult consumeMessageDirectly(String topic, String msgId, String consumerGroup,
String clientId) {
if (StringUtils.isNotBlank(clientId)) {
try {
return mqAdminExt.consumeMessageDirectly(consumerGroup, clientId, topic, msgId);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
try {
ConsumerConnection consumerConnection = mqAdminExt.examineConsumerConnectionInfo(consumerGroup);
for (Connection connection : consumerConnection.getConnectionSet()) {
if (StringUtils.isBlank(connection.getClientId())) {
continue;
}
logger.info("clientId={}", connection.getClientId());
return mqAdminExt.consumeMessageDirectly(consumerGroup, connection.getClientId(), topic, msgId);
}
} catch (Exception e) {
throw Throwables.propagate(e);
}
throw new IllegalStateException("NO CONSUMER");
}
@Override
public MessagePage queryMessageByPage(MessageQuery query) {
MessageQueryByPage queryByPage = new MessageQueryByPage(
query.getPageNum(),
query.getPageSize(),
query.getTopic(),
query.getBegin(),
query.getEnd());
List<QueueOffsetInfo> queueOffsetInfos = CACHE.getIfPresent(query.getTaskId());
if (queueOffsetInfos == null) {
query.setPageNum(1);
MessagePageTask task = this.queryFirstMessagePage(queryByPage);
String taskId = MessageClientIDSetter.createUniqID();
CACHE.put(taskId, task.getQueueOffsetInfos());
return new MessagePage(task.getPage(), taskId);
}
Page<MessageView> messageViews = queryMessageByTaskPage(queryByPage, queueOffsetInfos);
return new MessagePage(messageViews, query.getTaskId());
}
private MessagePageTask queryFirstMessagePage(MessageQueryByPage query) {
boolean isEnableAcl = !StringUtils.isEmpty(configure.getAccessKey()) && !StringUtils.isEmpty(configure.getSecretKey());
RPCHook rpcHook = null;
if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
}
DefaultMQPullConsumer consumer = buildDefaultMQPullConsumer(rpcHook, configure.isUseTLS());
long total = 0;
List<QueueOffsetInfo> queueOffsetInfos = new ArrayList<>();
List<MessageView> messageViews = new ArrayList<>();
try {
consumer.start();
Collection<MessageQueue> messageQueues = consumer.fetchSubscribeMessageQueues(query.getTopic());
int idx = 0;
for (MessageQueue messageQueue : messageQueues) {
Long minOffset = consumer.searchOffset(messageQueue, query.getBegin());
Long maxOffset = consumer.searchOffset(messageQueue, query.getEnd()) + 1;
queueOffsetInfos.add(new QueueOffsetInfo(idx++, minOffset, maxOffset, minOffset, minOffset, messageQueue));
}
// check first offset has message
// filter the begin time
for (QueueOffsetInfo queueOffset : queueOffsetInfos) {
Long start = queueOffset.getStart();
boolean hasData = false;
boolean hasIllegalOffset = true;
while (hasIllegalOffset) {
PullResult pullResult = consumer.pull(queueOffset.getMessageQueues(), "*", start, 32);
if (pullResult.getPullStatus() == PullStatus.FOUND) {
hasData = true;
List<MessageExt> msgFoundList = pullResult.getMsgFoundList();
for (MessageExt messageExt : msgFoundList) {
if (messageExt.getStoreTimestamp() < query.getBegin()) {
start++;
} else {
hasIllegalOffset = false;
break;
}
}
} else {
hasIllegalOffset = false;
}
}
if (!hasData) {
queueOffset.setEnd(queueOffset.getStart());
}
queueOffset.setStart(start);
queueOffset.setStartOffset(start);
queueOffset.setEndOffset(start);
}
// filter the end time
for (QueueOffsetInfo queueOffset : queueOffsetInfos) {
if (queueOffset.getStart().equals(queueOffset.getEnd())) {
continue;
}
long end = queueOffset.getEnd();
long pullOffset = end;
int pullSize = 32;
boolean hasIllegalOffset = true;
while (hasIllegalOffset) {
if (pullOffset - pullSize > queueOffset.getStart()) {
pullOffset = pullOffset - pullSize;
} else {
pullOffset = queueOffset.getStartOffset();
pullSize = (int) (end - pullOffset);
}
PullResult pullResult = consumer.pull(queueOffset.getMessageQueues(), "*", pullOffset, pullSize);
if (pullResult.getPullStatus() == PullStatus.FOUND) {
List<MessageExt> msgFoundList = pullResult.getMsgFoundList();
for (int i = msgFoundList.size() - 1; i >= 0; i--) {
MessageExt messageExt = msgFoundList.get(i);
if (messageExt.getStoreTimestamp() < query.getBegin()) {
end--;
} else {
hasIllegalOffset = false;
break;
}
}
} else {
hasIllegalOffset = false;
}
if (pullOffset == queueOffset.getStartOffset()) {
break;
}
}
queueOffset.setEnd(end);
total += queueOffset.getEnd() - queueOffset.getStart();
}
long pageSize = total > query.getPageSize() ? query.getPageSize() : total;
// move startOffset
int next = moveStartOffset(queueOffsetInfos, query);
moveEndOffset(queueOffsetInfos, query, next);
// find the first page of message
for (QueueOffsetInfo queueOffsetInfo : queueOffsetInfos) {
Long start = queueOffsetInfo.getStartOffset();
Long end = queueOffsetInfo.getEndOffset();
long size = Math.min(end - start, pageSize);
if (size == 0) {
continue;
}
while (size > 0) {
PullResult pullResult = consumer.pull(queueOffsetInfo.getMessageQueues(), "*", start, 32);
if (pullResult.getPullStatus() == PullStatus.FOUND) {
List<MessageExt> poll = pullResult.getMsgFoundList();
if (poll.size() == 0) {
break;
}
List<MessageView> collect = poll.stream()
.map(MessageView::fromMessageExt).collect(Collectors.toList());
for (MessageView view : collect) {
if (size > 0) {
messageViews.add(view);
size--;
}
}
} else {
break;
}
}
}
PageImpl<MessageView> page = new PageImpl<>(messageViews, query.page(), total);
return new MessagePageTask(page, queueOffsetInfos);
} catch (Exception e) {
throw Throwables.propagate(e);
} finally {
consumer.shutdown();
}
}
private Page<MessageView> queryMessageByTaskPage(MessageQueryByPage query, List<QueueOffsetInfo> queueOffsetInfos) {
boolean isEnableAcl = !StringUtils.isEmpty(configure.getAccessKey()) && !StringUtils.isEmpty(configure.getSecretKey());
RPCHook rpcHook = null;
if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
}
DefaultMQPullConsumer consumer = buildDefaultMQPullConsumer(rpcHook, configure.isUseTLS());
List<MessageView> messageViews = new ArrayList<>();
long offset = query.getPageNum() * query.getPageSize();
long total = 0;
try {
consumer.start();
for (QueueOffsetInfo queueOffsetInfo : queueOffsetInfos) {
long start = queueOffsetInfo.getStart();
long end = queueOffsetInfo.getEnd();
queueOffsetInfo.setStartOffset(start);
queueOffsetInfo.setEndOffset(start);
total += end - start;
}
if (total <= offset) {
return Page.empty();
}
long pageSize = total - offset > query.getPageSize() ? query.getPageSize() : total - offset;
int next = moveStartOffset(queueOffsetInfos, query);
moveEndOffset(queueOffsetInfos, query, next);
for (QueueOffsetInfo queueOffsetInfo : queueOffsetInfos) {
Long start = queueOffsetInfo.getStartOffset();
Long end = queueOffsetInfo.getEndOffset();
long size = Math.min(end - start, pageSize);
if (size == 0) {
continue;
}
while (size > 0) {
PullResult pullResult = consumer.pull(queueOffsetInfo.getMessageQueues(), "*", start, 32);
if (pullResult.getPullStatus() == PullStatus.FOUND) {
List<MessageExt> poll = pullResult.getMsgFoundList();
if (poll.size() == 0) {
break;
}
List<MessageView> collect = poll.stream()
.map(MessageView::fromMessageExt).collect(Collectors.toList());
for (MessageView view : collect) {
if (size > 0) {
messageViews.add(view);
size--;
}
}
} else {
break;
}
}
}
return new PageImpl<>(messageViews, query.page(), total);
} catch (Exception e) {
throw Throwables.propagate(e);
} finally {
consumer.shutdown();
}
}
private int moveStartOffset(List<QueueOffsetInfo> queueOffsets, MessageQueryByPage query) {
int size = queueOffsets.size();
int next = 0;
long offset = query.getPageNum() * query.getPageSize();
if (offset == 0) {
return next;
}
// sort by queueOffset size
List<QueueOffsetInfo> orderQueue = queueOffsets
.stream()
.sorted((o1, o2) -> {
long size1 = o1.getEnd() - o1.getStart();
long size2 = o2.getEnd() - o2.getStart();
if (size1 < size2) {
return -1;
} else if (size1 > size2) {
return 1;
}
return 0;
}).collect(Collectors.toList());
// Take the smallest one each time
for (int i = 0; i < size && offset >= (size - i); i++) {
long minSize = orderQueue.get(i).getEnd() - orderQueue.get(i).getStartOffset();
if (minSize == 0) {
continue;
}
long reduce = minSize * (size - i);
if (reduce <= offset) {
offset -= reduce;
for (int j = i; j < size; j++) {
orderQueue.get(j).incStartOffset(minSize);
}
} else {
long addOffset = offset / (size - i);
offset -= addOffset * (size - i);
if (addOffset != 0) {
for (int j = i; j < size; j++) {
orderQueue.get(j).incStartOffset(addOffset);
}
}
}
}
for (QueueOffsetInfo info : orderQueue) {
QueueOffsetInfo queueOffsetInfo = queueOffsets.get(info.getIdx());
queueOffsetInfo.setStartOffset(info.getStartOffset());
queueOffsetInfo.setEndOffset(info.getEndOffset());
}
for (QueueOffsetInfo info : queueOffsets) {
if (offset == 0) {
break;
}
next = (next + 1) % size;
if (info.getStartOffset() < info.getEnd()) {
info.incStartOffset();
--offset;
}
}
return next;
}
private void moveEndOffset(List<QueueOffsetInfo> queueOffsets, MessageQueryByPage query, int next) {
int size = queueOffsets.size();
for (int j = 0; j < query.getPageSize(); j++) {
QueueOffsetInfo nextQueueOffset = queueOffsets.get(next);
next = (next + 1) % size;
int start = next;
while (nextQueueOffset.getEndOffset() >= nextQueueOffset.getEnd()) {
nextQueueOffset = queueOffsets.get(next);
next = (next + 1) % size;
if (start == next) {
return;
}
}
nextQueueOffset.incEndOffset();
}
}
public DefaultMQPullConsumer buildDefaultMQPullConsumer(RPCHook rpcHook, boolean useTLS) {
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook);
consumer.setUseTLS(useTLS);
return consumer;
}
}

View File

@@ -0,0 +1,239 @@
/*
* 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.dashboard.service.impl;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.base.Throwables;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.trace.TraceType;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.model.MessageTraceView;
import org.apache.rocketmq.dashboard.model.trace.ProducerNode;
import org.apache.rocketmq.dashboard.model.trace.MessageTraceGraph;
import org.apache.rocketmq.dashboard.model.trace.SubscriptionNode;
import org.apache.rocketmq.dashboard.model.trace.TraceNode;
import org.apache.rocketmq.dashboard.model.trace.MessageTraceStatusEnum;
import org.apache.rocketmq.dashboard.service.MessageTraceService;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@Service
public class MessageTraceServiceImpl implements MessageTraceService {
private Logger logger = LoggerFactory.getLogger(MessageTraceServiceImpl.class);
private final static int QUERY_MESSAGE_MAX_NUM = 64;
private final static String UNKNOWN_GROUP_NAME = "%UNKNOWN_GROUP%";
private final static int MESSAGE_TRACE_MISSING_VALUE = -1;
@Resource
private MQAdminExt mqAdminExt;
@Resource
private RMQConfigure configure;
@Override
public List<MessageTraceView> queryMessageTraceKey(String key) {
String queryTopic = configure.getMsgTrackTopicNameOrDefault();
logger.info("query data topic name is:{}", queryTopic);
return queryMessageTraceByTopicAndKey(queryTopic, key);
}
@Override
public List<MessageTraceView> queryMessageTraceByTopicAndKey(String topic, String key) {
try {
List<MessageTraceView> messageTraceViews = new ArrayList<MessageTraceView>();
List<MessageExt> messageTraceList = mqAdminExt.queryMessage(topic, key, QUERY_MESSAGE_MAX_NUM, 0, System.currentTimeMillis()).getMessageList();
for (MessageExt messageExt : messageTraceList) {
List<MessageTraceView> messageTraceView = MessageTraceView.decodeFromTraceTransData(key, messageExt);
messageTraceViews.addAll(messageTraceView);
}
return messageTraceViews;
} catch (Exception err) {
throw Throwables.propagate(err);
}
}
@Override
public MessageTraceGraph queryMessageTraceGraph(String key) {
List<MessageTraceView> messageTraceViews = queryMessageTraceKey(key);
return buildMessageTraceGraph(messageTraceViews);
}
private MessageTraceGraph buildMessageTraceGraph(List<MessageTraceView> messageTraceViews) {
MessageTraceGraph messageTraceGraph = new MessageTraceGraph();
messageTraceGraph.setMessageTraceViews(messageTraceViews);
if (CollectionUtils.isEmpty(messageTraceViews)) {
return messageTraceGraph;
}
ProducerNode producerNode = null;
List<TraceNode> transactionNodeList = new ArrayList<>();
Map<String, Pair<MessageTraceView, MessageTraceView>> requestIdTracePairMap = Maps.newHashMap();
for (MessageTraceView messageTraceView : messageTraceViews) {
switch (TraceType.valueOf(messageTraceView.getTraceType())) {
case Pub:
producerNode = buildMessageRoot(messageTraceView);
break;
case EndTransaction:
transactionNodeList.add(buildTransactionNode(messageTraceView));
break;
case SubBefore:
case SubAfter:
putIntoMessageTraceViewGroupMap(messageTraceView, requestIdTracePairMap);
break;
default:
break;
}
}
if (producerNode != null) {
producerNode.setTransactionNodeList(sortTraceNodeListByBeginTimestamp(transactionNodeList));
}
messageTraceGraph.setProducerNode(producerNode);
messageTraceGraph.setSubscriptionNodeList(buildSubscriptionNodeList(requestIdTracePairMap));
return messageTraceGraph;
}
private TraceNode buildTransactionNode(MessageTraceView messageTraceView) {
TraceNode transactionNode = buildTraceNode(messageTraceView);
transactionNode.setCostTime(MESSAGE_TRACE_MISSING_VALUE);
return transactionNode;
}
private List<SubscriptionNode> buildSubscriptionNodeList(
Map<String, Pair<MessageTraceView, MessageTraceView>> requestIdTracePairMap) {
Map<String, List<TraceNode>> subscriptionTraceNodeMap = Maps.newHashMap();
for (Pair<MessageTraceView, MessageTraceView> traceNodePair : requestIdTracePairMap.values()) {
List<TraceNode> traceNodeList = subscriptionTraceNodeMap
.computeIfAbsent(buildGroupName(traceNodePair), (o) -> Lists.newArrayList());
traceNodeList.add(buildConsumeMessageTraceNode(traceNodePair));
}
return subscriptionTraceNodeMap.entrySet().stream()
.map((Function<Map.Entry<String, List<TraceNode>>, SubscriptionNode>) subscriptionEntry -> {
List<TraceNode> traceNodeList = subscriptionEntry.getValue();
SubscriptionNode subscriptionNode = new SubscriptionNode();
subscriptionNode.setSubscriptionGroup(subscriptionEntry.getKey());
subscriptionNode.setConsumeNodeList(sortTraceNodeListByBeginTimestamp(traceNodeList));
return subscriptionNode;
}).collect(Collectors.toList());
}
private <E> E getTraceValue(Pair<MessageTraceView, MessageTraceView> traceNodePair, Function<MessageTraceView, E> function) {
if (traceNodePair.getObject1() != null) {
return function.apply(traceNodePair.getObject1());
}
return function.apply(traceNodePair.getObject2());
}
private String buildGroupName(Pair<MessageTraceView, MessageTraceView> traceNodePair) {
String groupName = getTraceValue(traceNodePair, MessageTraceView::getGroupName);
if (StringUtils.isNoneBlank(groupName)) {
return groupName;
}
return UNKNOWN_GROUP_NAME;
}
private TraceNode buildConsumeMessageTraceNode(Pair<MessageTraceView, MessageTraceView> pair) {
MessageTraceView subBeforeTrace = pair.getObject1();
MessageTraceView subAfterTrace = pair.getObject2();
TraceNode consumeNode = new TraceNode();
consumeNode.setRequestId(getTraceValue(pair, MessageTraceView::getRequestId));
consumeNode.setStoreHost(getTraceValue(pair, MessageTraceView::getStoreHost));
consumeNode.setClientHost(getTraceValue(pair, MessageTraceView::getClientHost));
if (subBeforeTrace != null) {
consumeNode.setRetryTimes(subBeforeTrace.getRetryTimes());
consumeNode.setBeginTimestamp(subBeforeTrace.getTimeStamp());
} else {
consumeNode.setRetryTimes(MESSAGE_TRACE_MISSING_VALUE);
consumeNode.setBeginTimestamp(MESSAGE_TRACE_MISSING_VALUE);
}
if (subAfterTrace != null) {
consumeNode.setCostTime(subAfterTrace.getCostTime());
consumeNode.setStatus(subAfterTrace.getStatus());
if (subAfterTrace.getTimeStamp() > 0) {
consumeNode.setEndTimestamp(subAfterTrace.getTimeStamp());
} else {
if (subBeforeTrace != null) {
if (subAfterTrace.getCostTime() >= 0) {
consumeNode.setEndTimestamp(subBeforeTrace.getTimeStamp() + subAfterTrace.getCostTime());
} else {
consumeNode.setEndTimestamp(subBeforeTrace.getTimeStamp());
}
} else {
consumeNode.setEndTimestamp(MESSAGE_TRACE_MISSING_VALUE);
}
}
} else {
consumeNode.setCostTime(MESSAGE_TRACE_MISSING_VALUE);
consumeNode.setEndTimestamp(MESSAGE_TRACE_MISSING_VALUE);
consumeNode.setStatus(MessageTraceStatusEnum.UNKNOWN.getStatus());
}
return consumeNode;
}
private void putIntoMessageTraceViewGroupMap(MessageTraceView messageTraceView,
Map<String, Pair<MessageTraceView, MessageTraceView>> messageTraceViewGroupMap) {
Pair<MessageTraceView, MessageTraceView> messageTracePair = messageTraceViewGroupMap
.computeIfAbsent(messageTraceView.getRequestId(), (o) -> new Pair<>(null, null));
switch (TraceType.valueOf(messageTraceView.getTraceType())) {
case SubBefore:
messageTracePair.setObject1(messageTraceView);
break;
case SubAfter:
messageTracePair.setObject2(messageTraceView);
break;
default:
break;
}
}
private ProducerNode buildMessageRoot(MessageTraceView messageTraceView) {
ProducerNode root = new ProducerNode();
BeanUtils.copyProperties(messageTraceView, root);
root.setTraceNode(buildTraceNode(messageTraceView));
return root;
}
private TraceNode buildTraceNode(MessageTraceView messageTraceView) {
TraceNode traceNode = new TraceNode();
BeanUtils.copyProperties(messageTraceView, traceNode);
traceNode.setBeginTimestamp(messageTraceView.getTimeStamp());
traceNode.setEndTimestamp(messageTraceView.getTimeStamp() + messageTraceView.getCostTime());
return traceNode;
}
private List<TraceNode> sortTraceNodeListByBeginTimestamp(List<TraceNode> traceNodeList) {
traceNodeList.sort((o1, o2) -> -Long.compare(o1.getBeginTimestamp(), o2.getBeginTimestamp()));
return traceNodeList;
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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.dashboard.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;
import javax.annotation.Resource;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.model.ConsumerMonitorConfig;
import org.apache.rocketmq.dashboard.service.MonitorService;
import org.apache.rocketmq.dashboard.util.JsonUtil;
import org.springframework.stereotype.Service;
@Service
public class MonitorServiceImpl implements MonitorService {
@Resource
private RMQConfigure configure;
private Map<String, ConsumerMonitorConfig> configMap = new ConcurrentHashMap<>();
@Override
public boolean createOrUpdateConsumerMonitor(String name, ConsumerMonitorConfig config) {
configMap.put(name, config);// todo if write map success but write file fail
writeToFile(getConsumerMonitorConfigDataPath(), configMap);
return true;
}
@Override
public Map<String, ConsumerMonitorConfig> queryConsumerMonitorConfig() {
return configMap;
}
@Override
public ConsumerMonitorConfig queryConsumerMonitorConfigByGroupName(String consumeGroupName) {
return configMap.get(consumeGroupName);
}
@Override
public boolean deleteConsumerMonitor(String consumeGroupName) {
configMap.remove(consumeGroupName);
writeToFile(getConsumerMonitorConfigDataPath(), configMap);
return true;
}
//rocketmq.console.data.path/monitor/consumerMonitorConfig.json
private String getConsumerMonitorConfigDataPath() {
return configure.getRocketMqDashboardDataPath() + File.separatorChar + "monitor" + File.separatorChar + "consumerMonitorConfig.json";
}
private String getConsumerMonitorConfigDataPathBackUp() {
return getConsumerMonitorConfigDataPath() + ".bak";
}
private void writeToFile(String path, Object data) {
writeDataJsonToFile(path, JsonUtil.obj2String(data));
}
private void writeDataJsonToFile(String path, String dataStr) {
try {
MixAll.string2File(dataStr, path);
}
catch (Exception e) {
throw Throwables.propagate(e);
}
}
@PostConstruct
private void loadData() throws IOException {
String content = MixAll.file2String(getConsumerMonitorConfigDataPath());
if (content == null) {
content = MixAll.file2String(getConsumerMonitorConfigDataPathBackUp());
}
if (content == null) {
return;
}
configMap = JsonUtil.string2Obj(content, new TypeReference<ConcurrentHashMap<String, ConsumerMonitorConfig>>() {
});
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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.dashboard.service.impl;
import com.google.common.base.Splitter;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.service.AbstractCommonService;
import org.apache.rocketmq.dashboard.service.OpsService;
import org.apache.rocketmq.dashboard.service.checker.CheckerType;
import org.apache.rocketmq.dashboard.service.checker.RocketMqChecker;
import org.springframework.stereotype.Service;
@Service
public class OpsServiceImpl extends AbstractCommonService implements OpsService {
@Resource
private RMQConfigure configure;
@Resource
private List<RocketMqChecker> rocketMqCheckerList;
@Override
public Map<String, Object> homePageInfo() {
Map<String, Object> homePageInfoMap = Maps.newHashMap();
homePageInfoMap.put("namesvrAddrList", Splitter.on(";").splitToList(configure.getNamesrvAddr()));
homePageInfoMap.put("useVIPChannel", Boolean.valueOf(configure.getIsVIPChannel()));
homePageInfoMap.put("useTLS", configure.isUseTLS());
return homePageInfoMap;
}
@Override
public void updateNameSvrAddrList(String nameSvrAddrList) {
configure.setNamesrvAddr(nameSvrAddrList);
}
@Override
public String getNameSvrList() {
return configure.getNamesrvAddr();
}
@Override
public Map<CheckerType, Object> rocketMqStatusCheck() {
Map<CheckerType, Object> checkResultMap = Maps.newHashMap();
for (RocketMqChecker rocketMqChecker : rocketMqCheckerList) {
checkResultMap.put(rocketMqChecker.checkerType(), rocketMqChecker.doCheck());
}
return checkResultMap;
}
@Override public boolean updateIsVIPChannel(String useVIPChannel) {
configure.setIsVIPChannel(useVIPChannel);
return true;
}
@Override
public boolean updateUseTLS(boolean useTLS) {
configure.setUseTLS(useTLS);
return true;
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.dashboard.service.impl;
import com.google.common.base.Throwables;
import javax.annotation.Resource;
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
import org.apache.rocketmq.dashboard.service.ProducerService;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.springframework.stereotype.Service;
@Service
public class ProducerServiceImpl implements ProducerService {
@Resource
private MQAdminExt mqAdminExt;
@Override
public ProducerConnection getProducerConnection(String producerGroup, String topic) {
try {
return mqAdminExt.examineProducerConnectionInfo(producerGroup, topic);
}
catch (Exception e) {
throw Throwables.propagate(e);
}
}
}

View File

@@ -0,0 +1,285 @@
/*
* 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.dashboard.service.impl;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.acl.common.AclClientRPCHook;
import org.apache.rocketmq.acl.common.SessionCredentials;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.trace.TraceContext;
import org.apache.rocketmq.client.trace.TraceDispatcher;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.common.admin.TopicStatsTable;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
import org.apache.rocketmq.common.protocol.body.GroupList;
import org.apache.rocketmq.common.protocol.body.TopicList;
import org.apache.rocketmq.common.protocol.route.BrokerData;
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
import org.apache.rocketmq.dashboard.service.AbstractCommonService;
import org.apache.rocketmq.dashboard.service.TopicService;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.tools.command.CommandUtil;
import org.joor.Reflect;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
@Service
public class TopicServiceImpl extends AbstractCommonService implements TopicService {
@Autowired
private RMQConfigure configure;
@Override
public TopicList fetchAllTopicList(boolean skipSysProcess) {
try {
TopicList allTopics = mqAdminExt.fetchAllTopicList();
if (skipSysProcess) {
return allTopics;
}
TopicList sysTopics = getSystemTopicList();
Set<String> topics = new HashSet<>();
for (String topic : allTopics.getTopicList()) {
if (sysTopics.getTopicList().contains(topic)) {
topics.add(String.format("%s%s", "%SYS%", topic));
} else {
topics.add(topic);
}
}
allTopics.getTopicList().clear();
allTopics.getTopicList().addAll(topics);
return allTopics;
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
@Override
public TopicStatsTable stats(String topic) {
try {
return mqAdminExt.examineTopicStats(topic);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
@Override
public TopicRouteData route(String topic) {
try {
return mqAdminExt.examineTopicRouteInfo(topic);
} catch (Exception ex) {
throw Throwables.propagate(ex);
}
}
@Override
public GroupList queryTopicConsumerInfo(String topic) {
try {
return mqAdminExt.queryTopicConsumeByWho(topic);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
@Override
public void createOrUpdate(TopicConfigInfo topicCreateOrUpdateRequest) {
TopicConfig topicConfig = new TopicConfig();
BeanUtils.copyProperties(topicCreateOrUpdateRequest, topicConfig);
try {
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
for (String brokerName : changeToBrokerNameSet(clusterInfo.getClusterAddrTable(),
topicCreateOrUpdateRequest.getClusterNameList(), topicCreateOrUpdateRequest.getBrokerNameList())) {
mqAdminExt.createAndUpdateTopicConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), topicConfig);
}
} catch (Exception err) {
throw Throwables.propagate(err);
}
}
@Override
public TopicConfig examineTopicConfig(String topic, String brokerName) {
ClusterInfo clusterInfo = null;
try {
clusterInfo = mqAdminExt.examineBrokerClusterInfo();
} catch (Exception e) {
throw Throwables.propagate(e);
}
return mqAdminExt.examineTopicConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), topic);
}
@Override
public List<TopicConfigInfo> examineTopicConfig(String topic) {
List<TopicConfigInfo> topicConfigInfoList = Lists.newArrayList();
TopicRouteData topicRouteData = route(topic);
for (BrokerData brokerData : topicRouteData.getBrokerDatas()) {
TopicConfigInfo topicConfigInfo = new TopicConfigInfo();
TopicConfig topicConfig = examineTopicConfig(topic, brokerData.getBrokerName());
BeanUtils.copyProperties(topicConfig, topicConfigInfo);
topicConfigInfo.setBrokerNameList(Lists.newArrayList(brokerData.getBrokerName()));
topicConfigInfoList.add(topicConfigInfo);
}
return topicConfigInfoList;
}
@Override
public boolean deleteTopic(String topic, String clusterName) {
try {
if (StringUtils.isBlank(clusterName)) {
return deleteTopic(topic);
}
Set<String> masterSet = CommandUtil.fetchMasterAddrByClusterName(mqAdminExt, clusterName);
mqAdminExt.deleteTopicInBroker(masterSet, topic);
Set<String> nameServerSet = null;
if (StringUtils.isNotBlank(configure.getNamesrvAddr())) {
String[] ns = configure.getNamesrvAddr().split(";");
nameServerSet = new HashSet<String>(Arrays.asList(ns));
}
mqAdminExt.deleteTopicInNameServer(nameServerSet, topic);
} catch (Exception err) {
throw Throwables.propagate(err);
}
return true;
}
@Override
public boolean deleteTopic(String topic) {
ClusterInfo clusterInfo = null;
try {
clusterInfo = mqAdminExt.examineBrokerClusterInfo();
} catch (Exception err) {
throw Throwables.propagate(err);
}
for (String clusterName : clusterInfo.getClusterAddrTable().keySet()) {
deleteTopic(topic, clusterName);
}
return true;
}
@Override
public boolean deleteTopicInBroker(String brokerName, String topic) {
try {
ClusterInfo clusterInfo = null;
try {
clusterInfo = mqAdminExt.examineBrokerClusterInfo();
} catch (Exception e) {
throw Throwables.propagate(e);
}
mqAdminExt.deleteTopicInBroker(Sets.newHashSet(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr()), topic);
} catch (Exception e) {
throw Throwables.propagate(e);
}
return true;
}
public DefaultMQProducer buildDefaultMQProducer(String producerGroup, RPCHook rpcHook) {
return buildDefaultMQProducer(producerGroup, rpcHook, false);
}
public DefaultMQProducer buildDefaultMQProducer(String producerGroup, RPCHook rpcHook, boolean traceEnabled) {
DefaultMQProducer defaultMQProducer = new DefaultMQProducer(producerGroup, rpcHook, traceEnabled, configure.getMsgTrackTopicNameOrDefault());
defaultMQProducer.setUseTLS(configure.isUseTLS());
return defaultMQProducer;
}
private TopicList getSystemTopicList() {
RPCHook rpcHook = null;
boolean isEnableAcl = !StringUtils.isEmpty(configure.getAccessKey()) && !StringUtils.isEmpty(configure.getSecretKey());
if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
}
DefaultMQProducer producer = buildDefaultMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook);
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
producer.setNamesrvAddr(configure.getNamesrvAddr());
try {
producer.start();
return producer.getDefaultMQProducerImpl().getmQClientFactory().getMQClientAPIImpl().getSystemTopicList(20000L);
} catch (Exception e) {
throw Throwables.propagate(e);
} finally {
producer.shutdown();
}
}
@Override
public SendResult sendTopicMessageRequest(SendTopicMessageRequest sendTopicMessageRequest) {
DefaultMQProducer producer = null;
AclClientRPCHook rpcHook = null;
if (configure.isACLEnabled()) {
rpcHook = new AclClientRPCHook(new SessionCredentials(
configure.getAccessKey(),
configure.getSecretKey()
));
}
producer = buildDefaultMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook, sendTopicMessageRequest.isTraceEnabled());
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
producer.setNamesrvAddr(configure.getNamesrvAddr());
try {
producer.start();
Message msg = new Message(sendTopicMessageRequest.getTopic(),
sendTopicMessageRequest.getTag(),
sendTopicMessageRequest.getKey(),
sendTopicMessageRequest.getMessageBody().getBytes()
);
return producer.send(msg);
} catch (Exception e) {
throw Throwables.propagate(e);
} finally {
waitSendTraceFinish(producer, sendTopicMessageRequest.isTraceEnabled());
producer.shutdown();
}
}
private void waitSendTraceFinish(DefaultMQProducer producer, boolean traceEnabled) {
if (!traceEnabled) {
return;
}
try {
TraceDispatcher traceDispatcher = Reflect.on(producer).field("traceDispatcher").get();
if (traceDispatcher != null) {
ArrayBlockingQueue<TraceContext> traceContextQueue = Reflect.on(traceDispatcher).field("traceContextQueue").get();
while (traceContextQueue.size() > 0) {
Thread.sleep(1);
}
}
// wait another 150ms until async request send finish
// after new RocketMQ version released, this logic can be removed
// https://github.com/apache/rocketmq/pull/2989
Thread.sleep(150);
} catch (Exception ignore) {
}
}
}

View File

@@ -0,0 +1,165 @@
/*
* 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.dashboard.service.impl;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.exception.ServiceException;
import org.apache.rocketmq.dashboard.model.User;
import org.apache.rocketmq.dashboard.service.UserService;
import org.apache.rocketmq.srvutil.FileWatchService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class UserServiceImpl implements UserService, InitializingBean {
@Resource
RMQConfigure configure;
FileBasedUserInfoStore fileBasedUserInfoStore;
@Override
public User queryByName(String name) {
return fileBasedUserInfoStore.queryByName(name);
}
@Override
public User queryByUsernameAndPassword(String username, String password) {
return fileBasedUserInfoStore.queryByUsernameAndPassword(username, password);
}
@Override
public void afterPropertiesSet() throws Exception {
if (configure.isLoginRequired()) {
fileBasedUserInfoStore = new FileBasedUserInfoStore(configure);
}
}
public static class FileBasedUserInfoStore {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private static final String FILE_NAME = "users.properties";
private String filePath;
private final Map<String, User> userMap = new ConcurrentHashMap<>();
public FileBasedUserInfoStore(RMQConfigure configure) {
filePath = configure.getRocketMqDashboardDataPath() + File.separator + FILE_NAME;
if (!new File(filePath).exists()) {
//Use the default path
InputStream inputStream = getClass().getResourceAsStream("/" + FILE_NAME);
if (inputStream == null) {
log.error(String.format("Can not found the file %s in Spring Boot jar", FILE_NAME));
System.out.printf(String.format("Can not found file %s in Spring Boot jar or %s, stop the dashboard starting",
FILE_NAME, configure.getRocketMqDashboardDataPath()));
System.exit(1);
} else {
load(inputStream);
}
} else {
log.info(String.format("Login Users configure file is %s", filePath));
load();
watch();
}
}
private void load() {
load(null);
}
private void load(InputStream inputStream) {
Properties prop = new Properties();
try {
if (inputStream == null) {
prop.load(new FileReader(filePath));
} else {
prop.load(inputStream);
}
} catch (Exception e) {
log.error("load user.properties failed", e);
throw new ServiceException(0, String.format("Failed to load loginUserInfo property file: %s", filePath));
}
Map<String, User> loadUserMap = new HashMap<>();
String[] arrs;
int role;
for (String key : prop.stringPropertyNames()) {
String v = prop.getProperty(key);
if (v == null) continue;
arrs = v.split(",", 2);
if (arrs.length == 0) {
continue;
} else if (arrs.length == 1) {
role = 0;
} else {
role = Integer.parseInt(arrs[1].trim());
}
loadUserMap.put(key, new User(key, arrs[0].trim(), role));
}
userMap.clear();
userMap.putAll(loadUserMap);
}
private boolean watch() {
try {
FileWatchService fileWatchService = new FileWatchService(new String[]{filePath}, new FileWatchService.Listener() {
@Override
public void onChanged(String path) {
log.info("The loginUserInfo property file changed, reload the context");
load();
}
});
fileWatchService.start();
log.info("Succeed to start LoginUserWatcherService");
return true;
} catch (Exception e) {
log.error("Failed to start LoginUserWatcherService", e);
}
return false;
}
public User queryByName(String name) {
return userMap.get(name);
}
public User queryByUsernameAndPassword(@NotNull String username, @NotNull String password) {
User user = queryByName(username);
if (user != null && password.equals(user.getPassword())) {
return user.cloneOne();
}
return null;
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.dashboard.support;
import javax.servlet.http.HttpServletRequest;
import org.apache.rocketmq.dashboard.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice(basePackages = "org.apache.rocketmq.dashboard")
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public JsonResult<Object> jsonErrorHandler(HttpServletRequest req, Exception ex) throws Exception {
JsonResult<Object> value = null;
if (ex != null) {
logger.error("op=global_exception_handler_print_error", ex);
if (ex instanceof ServiceException) {
value = new JsonResult<Object>(((ServiceException) ex).getCode(), ex.getMessage());
}
else {
value = new JsonResult<Object>(-1, ex.getMessage() == null ? ex.toString() : ex.getMessage());
}
}
return value;
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.dashboard.support;
import java.lang.annotation.Annotation;
import org.apache.rocketmq.dashboard.aspect.admin.annotation.OriginalControllerReturnValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@ControllerAdvice(basePackages = "org.apache.rocketmq.dashboard")
public class GlobalRestfulResponseBodyAdvice implements ResponseBodyAdvice<Object> {
private Logger logger = LoggerFactory.getLogger(GlobalRestfulResponseBodyAdvice.class);
@Override
public Object beforeBodyWrite(
Object obj, MethodParameter methodParameter, MediaType mediaType,
Class<? extends HttpMessageConverter<?>> converterType,
ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
Annotation originalControllerReturnValue = methodParameter.getMethodAnnotation(OriginalControllerReturnValue.class);
if (originalControllerReturnValue != null) {
return obj;
}
JsonResult value;
if (obj instanceof JsonResult) {
value = (JsonResult)obj;
}
else {
value = new JsonResult(obj);
}
return value;
}
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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.dashboard.support;
public class JsonResult<T> {
private int status = 0;
private T data;
private String errMsg;
public JsonResult(T data) {
this.data = data;
}
public JsonResult(int status, String errMsg) {
this.status = status;
this.errMsg = errMsg;
}
public JsonResult(int status, T data, String errMsg) {
this.status = status;
this.data = data;
this.errMsg = errMsg;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
}

View File

@@ -0,0 +1,339 @@
/*
* 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.dashboard.task;
import com.google.common.base.Stopwatch;
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
import org.apache.rocketmq.common.protocol.body.GroupList;
import org.apache.rocketmq.common.protocol.body.KVTable;
import org.apache.rocketmq.common.protocol.body.TopicList;
import org.apache.rocketmq.common.protocol.route.BrokerData;
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
import org.apache.rocketmq.common.topic.TopicValidator;
import org.apache.rocketmq.dashboard.aspect.admin.annotation.MultiMQAdminCmdMethod;
import org.apache.rocketmq.store.stats.BrokerStatsManager;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.apache.rocketmq.tools.command.stats.StatsAllSubCommand;
import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import javax.annotation.Resource;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.protocol.body.BrokerStatsData;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.service.DashboardCollectService;
import org.apache.rocketmq.dashboard.util.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class DashboardCollectTask {
private Date currentDate = new Date();
@Resource
private MQAdminExt mqAdminExt;
@Resource
private RMQConfigure rmqConfigure;
@Resource
private DashboardCollectService dashboardCollectService;
private final static Logger log = LoggerFactory.getLogger(DashboardCollectTask.class);
@Scheduled(cron = "30 0/1 * * * ?")
@MultiMQAdminCmdMethod(timeoutMillis = 5000)
public void collectTopic() {
if (!rmqConfigure.isEnableDashBoardCollect()) {
return;
}
Date date = new Date();
Stopwatch stopwatch = Stopwatch.createUnstarted();
try {
TopicList topicList = mqAdminExt.fetchAllTopicList();
Set<String> topicSet = topicList.getTopicList();
this.addSystemTopic();
for (String topic : topicSet) {
if (topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)
|| topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX)
|| TopicValidator.isSystemTopic(topic)) {
continue;
}
TopicRouteData topicRouteData = mqAdminExt.examineTopicRouteInfo(topic);
GroupList groupList = mqAdminExt.queryTopicConsumeByWho(topic);
double inTPS = 0;
long inMsgCntToday = 0;
double outTPS = 0;
long outMsgCntToday = 0;
for (BrokerData bd : topicRouteData.getBrokerDatas()) {
String masterAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
if (masterAddr != null) {
try {
stopwatch.start();
log.info("start time: {}", stopwatch.toString());
BrokerStatsData bsd = mqAdminExt.viewBrokerStatsData(masterAddr, BrokerStatsManager.TOPIC_PUT_NUMS, topic);
stopwatch.stop();
log.info("stop time : {}", stopwatch.toString());
inTPS += bsd.getStatsMinute().getTps();
inMsgCntToday += StatsAllSubCommand.compute24HourSum(bsd);
}
catch (Exception e) {
stopwatch.reset();
log.warn("Exception caught: mqAdminExt get broker stats data TOPIC_PUT_NUMS failed");
log.warn("Response [{}] ", e.getMessage());
}
}
}
if (groupList != null && !groupList.getGroupList().isEmpty()) {
for (String group : groupList.getGroupList()) {
for (BrokerData bd : topicRouteData.getBrokerDatas()) {
String masterAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
if (masterAddr != null) {
try {
String statsKey = String.format("%s@%s", topic, group);
BrokerStatsData bsd = mqAdminExt.viewBrokerStatsData(masterAddr, BrokerStatsManager.GROUP_GET_NUMS, statsKey);
outTPS += bsd.getStatsMinute().getTps();
outMsgCntToday += StatsAllSubCommand.compute24HourSum(bsd);
}
catch (Exception e) {
log.warn("Exception caught: mqAdminExt get broker stats data GROUP_GET_NUMS failed");
log.warn("Response [{}] ", e.getMessage());
}
}
}
}
}
List<String> list;
try {
list = dashboardCollectService.getTopicMap().get(topic);
}
catch (ExecutionException e) {
throw Throwables.propagate(e);
}
if (null == list) {
list = Lists.newArrayList();
}
list.add(date.getTime() + "," + new BigDecimal(inTPS).setScale(5, BigDecimal.ROUND_HALF_UP) + "," + inMsgCntToday + "," + new BigDecimal(outTPS).setScale(5, BigDecimal.ROUND_HALF_UP) + "," + outMsgCntToday);
dashboardCollectService.getTopicMap().put(topic, list);
}
log.debug("Topic Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getTopicMap().asMap()));
}
catch (Exception err) {
throw Throwables.propagate(err);
}
}
@Scheduled(cron = "0 0/1 * * * ?")
public void collectBroker() {
if (!rmqConfigure.isEnableDashBoardCollect()) {
return;
}
try {
Date date = new Date();
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
Set<Map.Entry<String, BrokerData>> clusterEntries = clusterInfo.getBrokerAddrTable().entrySet();
Map<String, String> addresses = Maps.newHashMap();
for (Map.Entry<String, BrokerData> clusterEntry : clusterEntries) {
HashMap<Long, String> addrs = clusterEntry.getValue().getBrokerAddrs();
Set<Map.Entry<Long, String>> addrsEntries = addrs.entrySet();
for (Map.Entry<Long, String> addrEntry : addrsEntries) {
addresses.put(addrEntry.getValue(), clusterEntry.getKey() + ":" + addrEntry.getKey());
}
}
Set<Map.Entry<String, String>> entries = addresses.entrySet();
for (Map.Entry<String, String> entry : entries) {
List<String> list = dashboardCollectService.getBrokerMap().get(entry.getValue());
if (null == list) {
list = Lists.newArrayList();
}
KVTable kvTable = fetchBrokerRuntimeStats(entry.getKey(), 3);
if (kvTable == null) {
continue;
}
String[] tpsArray = kvTable.getTable().get("getTotalTps").split(" ");
BigDecimal totalTps = new BigDecimal(0);
for (String tps : tpsArray) {
totalTps = totalTps.add(new BigDecimal(tps));
}
BigDecimal averageTps = totalTps.divide(new BigDecimal(tpsArray.length), 5, BigDecimal.ROUND_HALF_UP);
list.add(date.getTime() + "," + averageTps.toString());
dashboardCollectService.getBrokerMap().put(entry.getValue(), list);
}
log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap()));
}
catch (Exception e) {
throw Throwables.propagate(e);
}
}
private KVTable fetchBrokerRuntimeStats(String brokerAddr, Integer retryTime) {
if (retryTime == 0) {
return null;
}
try {
return mqAdminExt.fetchBrokerRuntimeStats(brokerAddr);
}
catch (Exception e) {
try {
Thread.sleep(1000);
}
catch (InterruptedException e1) {
throw Throwables.propagate(e1);
}
fetchBrokerRuntimeStats(brokerAddr, retryTime - 1);
throw Throwables.propagate(e);
}
}
@Scheduled(cron = "0/5 * * * * ?")
public void saveData() {
if (!rmqConfigure.isEnableDashBoardCollect()) {
return;
}
//one day refresh cache one time
String dataLocationPath = rmqConfigure.getDashboardCollectData();
DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String nowDateStr = format.format(new Date());
String currentDateStr = format.format(currentDate);
if (!currentDateStr.equals(nowDateStr)) {
dashboardCollectService.getBrokerMap().invalidateAll();
dashboardCollectService.getTopicMap().invalidateAll();
currentDate = new Date();
}
File brokerFile = new File(dataLocationPath + nowDateStr + ".json");
File topicFile = new File(dataLocationPath + nowDateStr + "_topic" + ".json");
try {
Map<String, List<String>> brokerFileMap;
Map<String, List<String>> topicFileMap;
if (brokerFile.exists()) {
brokerFileMap = dashboardCollectService.jsonDataFile2map(brokerFile);
}
else {
brokerFileMap = Maps.newHashMap();
Files.createParentDirs(brokerFile);
}
if (topicFile.exists()) {
topicFileMap = dashboardCollectService.jsonDataFile2map(topicFile);
}
else {
topicFileMap = Maps.newHashMap();
Files.createParentDirs(topicFile);
}
brokerFile.createNewFile();
topicFile.createNewFile();
writeFile(dashboardCollectService.getBrokerMap(), brokerFileMap, brokerFile);
writeFile(dashboardCollectService.getTopicMap(), topicFileMap, topicFile);
log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap()));
log.debug("Topic Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getTopicMap().asMap()));
}
catch (IOException e) {
throw Throwables.propagate(e);
}
}
private void writeFile(LoadingCache<String, List<String>> map, Map<String, List<String>> fileMap,
File file) throws IOException {
Map<String, List<String>> newMap = map.asMap();
Map<String, List<String>> resultMap = Maps.newHashMap();
if (fileMap.size() == 0) {
resultMap = newMap;
}
else {
for (Map.Entry<String, List<String>> entry : fileMap.entrySet()) {
List<String> oldList = entry.getValue();
List<String> newList = newMap.get(entry.getKey());
resultMap.put(entry.getKey(), appendData(newList, oldList));
if (newList == null || newList.size() == 0) {
map.put(entry.getKey(), appendData(newList, oldList));
}
}
for (Map.Entry<String, List<String>> entry : newMap.entrySet()) {
List<String> oldList = fileMap.get(entry.getKey());
if (oldList == null || oldList.size() == 0) {
resultMap.put(entry.getKey(), entry.getValue());
}
}
}
Files.write(JsonUtil.obj2String(resultMap).getBytes(), file);
}
private List<String> appendData(List<String> newTpsList, List<String> oldTpsList) {
List<String> result = Lists.newArrayList();
if (newTpsList == null || newTpsList.size() == 0) {
return oldTpsList;
}
if (oldTpsList == null || oldTpsList.size() == 0) {
return newTpsList;
}
String oldLastTps = oldTpsList.get(oldTpsList.size() - 1);
Long oldLastTimestamp = Long.parseLong(oldLastTps.split(",")[0]);
String newFirstTps = newTpsList.get(0);
Long newFirstTimestamp = Long.parseLong(newFirstTps.split(",")[0]);
if (oldLastTimestamp.longValue() < newFirstTimestamp.longValue()) {
result.addAll(oldTpsList);
result.addAll(newTpsList);
return result;
}
return newTpsList;
}
private void addSystemTopic() throws Exception {
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
HashMap<String, Set<String>> clusterTable = clusterInfo.getClusterAddrTable();
for (Map.Entry<String, Set<String>> entry : clusterTable.entrySet()) {
String clusterName = entry.getKey();
TopicValidator.addSystemTopic(clusterName);
Set<String> brokerNames = entry.getValue();
for (String brokerName : brokerNames) {
TopicValidator.addSystemTopic(brokerName);
}
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.dashboard.task;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.rocketmq.dashboard.model.ConsumerMonitorConfig;
import org.apache.rocketmq.dashboard.model.GroupConsumeInfo;
import org.apache.rocketmq.dashboard.service.ConsumerService;
import org.apache.rocketmq.dashboard.service.MonitorService;
import org.apache.rocketmq.dashboard.util.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class MonitorTask {
private Logger logger = LoggerFactory.getLogger(MonitorTask.class);
@Resource
private MonitorService monitorService;
@Resource
private ConsumerService consumerService;
// @Scheduled(cron = "* * * * * ?")
public void scanProblemConsumeGroup() {
for (Map.Entry<String, ConsumerMonitorConfig> configEntry : monitorService.queryConsumerMonitorConfig().entrySet()) {
GroupConsumeInfo consumeInfo = consumerService.queryGroup(configEntry.getKey());
if (consumeInfo.getCount() < configEntry.getValue().getMinCount() || consumeInfo.getDiffTotal() > configEntry.getValue().getMaxDiffTotal()) {
logger.info("op=look consumeInfo {}", JsonUtil.obj2String(consumeInfo)); // notify the alert system
}
}
}
}

View File

@@ -0,0 +1,156 @@
/*
* 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.dashboard.util;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("unchecked")
public class JsonUtil {
private static Logger logger = LoggerFactory.getLogger(JsonUtil.class);
private static ObjectMapper objectMapper = new ObjectMapper();
private JsonUtil() {
}
static {
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.setFilters(new SimpleFilterProvider().setFailOnUnknownId(false));
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}
public static void writeValue(Writer writer, Object obj) {
try {
objectMapper.writeValue(writer, obj);
}
catch (IOException e) {
Throwables.propagateIfPossible(e);
}
}
public static <T> String obj2String(T src) {
if (src == null) {
return null;
}
try {
return src instanceof String ? (String)src : objectMapper.writeValueAsString(src);
}
catch (Exception e) {
logger.error("Parse Object to String error src=" + src, e);
return null;
}
}
public static <T> byte[] obj2Byte(T src) {
if (src == null) {
return null;
}
try {
return src instanceof byte[] ? (byte[])src : objectMapper.writeValueAsBytes(src);
}
catch (Exception e) {
logger.error("Parse Object to byte[] error", e);
return null;
}
}
public static <T> T string2Obj(String str, Class<T> clazz) {
if (Strings.isNullOrEmpty(str) || clazz == null) {
return null;
}
str = escapesSpecialChar(str);
try {
return clazz.equals(String.class) ? (T)str : objectMapper.readValue(str, clazz);
}
catch (Exception e) {
logger.error("Parse String to Object error\nString: {}\nClass<T>: {}\nError: {}", str, clazz.getName(), e);
return null;
}
}
public static <T> T byte2Obj(byte[] bytes, Class<T> clazz) {
if (bytes == null || clazz == null) {
return null;
}
try {
return clazz.equals(byte[].class) ? (T)bytes : objectMapper.readValue(bytes, clazz);
}
catch (Exception e) {
logger.error("Parse byte[] to Object error\nbyte[]: {}\nClass<T>: {}\nError: {}", bytes, clazz.getName(), e);
return null;
}
}
public static <T> T string2Obj(String str, TypeReference<T> typeReference) {
if (Strings.isNullOrEmpty(str) || typeReference == null) {
return null;
}
str = escapesSpecialChar(str);
try {
return (T)(typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));
}
catch (Exception e) {
logger.error("Parse String to Object error\nString: {}\nTypeReference<T>: {}\nError: {}", str,
typeReference.getType(), e);
return null;
}
}
public static <T> T byte2Obj(byte[] bytes, TypeReference<T> typeReference) {
if (bytes == null || typeReference == null) {
return null;
}
try {
return (T)(typeReference.getType().equals(byte[].class) ? bytes : objectMapper.readValue(bytes,
typeReference));
}
catch (Exception e) {
logger.error("Parse byte[] to Object error\nbyte[]: {}\nTypeReference<T>: {}\nError: {}", bytes,
typeReference.getType(), e);
return null;
}
}
public static <T> T map2Obj(Map<String, String> map, Class<T> clazz) {
String str = obj2String(map);
return string2Obj(str, clazz);
}
private static String escapesSpecialChar(String str) {
return str.replace("\n", "\\n").replace("\r", "\\r");
}
}

View File

@@ -0,0 +1,172 @@
/*
* 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.dashboard.util;
import java.util.ArrayList;
import java.util.List;
import org.apache.rocketmq.client.producer.LocalTransactionState;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.rocketmq.client.trace.TraceType.Pub;
public class MsgTraceDecodeUtil {
private final static Logger log = LoggerFactory.getLogger(MsgTraceDecodeUtil.class);
private static final int TRACE_MSG_PUB_V1_LEN = 12;
private static final int TRACE_MSG_PUB_V2_LEN = 13;
private static final int TRACE_MSG_PUB_V3_LEN = 14;
private static final int TRACE_MSG_PUB_V4_LEN = 15;
private static final int TRACE_MSG_SUBAFTER_V1_LEN = 6;
private static final int TRACE_MSG_SUBAFTER_V2_LEN = 7;
private static final int TRACE_MSG_SUBAFTER_V3_LEN = 9;
public static List<TraceContext> decoderFromTraceDataString(String traceData) {
List<TraceContext> resList = new ArrayList<TraceContext>();
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 = initTraceContext();
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])]);
// compatible with different version
switch (line.length) {
case TRACE_MSG_PUB_V1_LEN:
break;
case TRACE_MSG_PUB_V2_LEN:
pubContext.setSuccess(Boolean.parseBoolean(line[12]));
break;
case TRACE_MSG_PUB_V3_LEN:
bean.setOffsetMsgId(line[12]);
pubContext.setSuccess(Boolean.parseBoolean(line[13]));
break;
case TRACE_MSG_PUB_V4_LEN:
bean.setOffsetMsgId(line[12]);
pubContext.setSuccess(Boolean.parseBoolean(line[13]));
bean.setClientHost(line[14]);
break;
default:
bean.setOffsetMsgId(line[12]);
pubContext.setSuccess(Boolean.parseBoolean(line[13]));
bean.setClientHost(line[14]);
log.warn("Detect new version trace msg of {} type", Pub.name());
break;
}
pubContext.setTraceBeans(new ArrayList<TraceBean>(1));
pubContext.getTraceBeans().add(bean);
resList.add(pubContext);
} else if (line[0].equals(TraceType.SubBefore.name())) {
TraceContext subBeforeContext = initTraceContext();
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<TraceBean>(1));
subBeforeContext.getTraceBeans().add(bean);
resList.add(subBeforeContext);
} else if (line[0].equals(TraceType.SubAfter.name())) {
TraceContext subAfterContext = initTraceContext();
subAfterContext.setTraceType(TraceType.SubAfter);
subAfterContext.setRequestId(line[1]);
TraceBean bean = new TraceBean();
bean.setMsgId(line[2]);
bean.setKeys(line[5]);
subAfterContext.setTraceBeans(new ArrayList<TraceBean>(1));
subAfterContext.getTraceBeans().add(bean);
subAfterContext.setCostTime(Integer.parseInt(line[3]));
subAfterContext.setSuccess(Boolean.parseBoolean(line[4]));
// compatible with different version
switch (line.length) {
case TRACE_MSG_SUBAFTER_V1_LEN:
break;
case TRACE_MSG_SUBAFTER_V2_LEN:
subAfterContext.setContextCode(Integer.parseInt(line[6]));
break;
case TRACE_MSG_SUBAFTER_V3_LEN:
subAfterContext.setContextCode(Integer.parseInt(line[6]));
subAfterContext.setTimeStamp(Long.parseLong(line[7]));
subAfterContext.setGroupName(line[8]);
break;
default:
subAfterContext.setContextCode(Integer.parseInt(line[6]));
subAfterContext.setTimeStamp(Long.parseLong(line[7]));
subAfterContext.setGroupName(line[8]);
log.warn("Detect new version trace msg of {} type", TraceType.SubAfter.name());
break;
}
resList.add(subAfterContext);
} else if (line[0].equals(TraceType.EndTransaction.name())) {
TraceContext endTransactionContext = initTraceContext();
endTransactionContext.setTraceType(TraceType.EndTransaction);
endTransactionContext.setTimeStamp(Long.parseLong(line[1]));
endTransactionContext.setRegionId(line[2]);
endTransactionContext.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.setMsgType(MessageType.values()[Integer.parseInt(line[9])]);
bean.setTransactionId(line[10]);
bean.setTransactionState(LocalTransactionState.valueOf(line[11]));
bean.setFromTransactionCheck(Boolean.parseBoolean(line[12]));
endTransactionContext.setTraceBeans(new ArrayList<TraceBean>(1));
endTransactionContext.getTraceBeans().add(bean);
resList.add(endTransactionContext);
}
}
return resList;
}
private static TraceContext initTraceContext() {
TraceContext traceContext = new TraceContext();
traceContext.setTimeStamp(0L);
traceContext.setCostTime(-1);
traceContext.setRequestId(null);
return traceContext;
}
}

View File

@@ -0,0 +1,140 @@
/*
* 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.dashboard.util;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.dashboard.model.User;
import org.apache.rocketmq.dashboard.model.UserInfo;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
public class WebUtil {
public static final String USER_INFO = "userInfo";
public static final String USER_NAME = "username";
public static final String NEED_LOGIN = "needLogin";
/**
* Obtain ServletRequest header value
*
* @param request
* @param name
* @return
*/
public static String getHeaderValue(HttpServletRequest request, String name) {
String v = request.getHeader(name);
if (v == null) {
return null;
}
return v.trim();
}
/**
* Fetch request ip address
*
* @param request
* @return
*/
public static String getIp(ServletRequest request) {
HttpServletRequest req = (HttpServletRequest) request;
String addr = getHeaderValue(req, "X-Forwarded-For");
if (StringUtils.isNotEmpty(addr) && addr.contains(",")) {
addr = addr.split(",")[0];
}
if (StringUtils.isEmpty(addr)) {
addr = getHeaderValue(req, "X-Real-IP");
}
if (StringUtils.isEmpty(addr)) {
addr = req.getRemoteAddr();
}
return addr;
}
public static void redirect(HttpServletResponse response, HttpServletRequest request, String path) throws IOException {
response.sendRedirect(request.getContextPath() + path);
}
/**
* Obtain the full url path
*
* @param request
* @return
*/
public static String getUrl(HttpServletRequest request) {
String url = request.getRequestURL().toString();
String queryString = request.getQueryString();
if (queryString != null) {
url += "?" + request.getQueryString();
}
return url;
}
/**
* Write content to front-page/response
*
* @param response
* @param result
* @throws IOException
*/
public static void print(HttpServletResponse response, String result) throws IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print(result);
out.flush();
out.close();
}
public static Object getValueFromSession(HttpServletRequest request, String key) {
HttpSession session = request.getSession(false);
if (session != null) {
return session.getAttribute(key);
}
return null;
}
public static UserInfo setLoginInfo(HttpServletRequest request, HttpServletResponse response, User user) {
String ip = WebUtil.getIp(request);
UserInfo userInfo = new UserInfo();
userInfo.setIp(ip);
userInfo.setLoginTime(System.currentTimeMillis());
userInfo.setUser(user);
return userInfo;
}
public static void removeSession(HttpServletRequest request) {
HttpSession session = request.getSession();
session.invalidate();
}
public static void setSessionValue(HttpServletRequest request, String key, Object value) {
HttpSession session = request.getSession();
session.setAttribute(key, value);
}
public static String getSessionId(HttpServletRequest request) {
return request.getSession().getId();
}
}