mirror of
https://github.com/apache/rocketmq-dashboard.git
synced 2026-02-21 04:45:41 +08:00
Use rocketmq-dashboard instead of rocketmq-console
This commit is contained in:
33
src/main/java/org/apache/rocketmq/dashboard/App.java
Normal file
33
src/main/java/org/apache/rocketmq/dashboard/App.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
83
src/main/java/org/apache/rocketmq/dashboard/model/User.java
Normal file
83
src/main/java/org/apache/rocketmq/dashboard/model/User.java
Normal 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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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>>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
156
src/main/java/org/apache/rocketmq/dashboard/util/JsonUtil.java
Normal file
156
src/main/java/org/apache/rocketmq/dashboard/util/JsonUtil.java
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
140
src/main/java/org/apache/rocketmq/dashboard/util/WebUtil.java
Normal file
140
src/main/java/org/apache/rocketmq/dashboard/util/WebUtil.java
Normal 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user