分区信息里展示当前分区的有效时间范围
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# kafka可视化管理平台
|
# kafka可视化管理平台
|
||||||
一款轻量级的kafka可视化管理平台,安装配置快捷、简单易用。
|
一款轻量级的kafka可视化管理平台,安装配置快捷、简单易用。
|
||||||
为了开发的省事,没有多语言支持,只支持中文展示。
|
为了开发的省事,没有国际化支持,只支持中文展示。
|
||||||
用过rocketmq-console吧,对,前端展示风格跟那个有点类似。
|
用过rocketmq-console吧,对,前端展示风格跟那个有点类似。
|
||||||
## 安装包下载
|
## 安装包下载
|
||||||
以下两种方式2选一,直接下载安装包或下载源码,手动打包
|
以下两种方式2选一,直接下载安装包或下载源码,手动打包
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 492 KiB |
2
pom.xml
2
pom.xml
@@ -10,7 +10,7 @@
|
|||||||
</parent>
|
</parent>
|
||||||
<groupId>com.xuxd</groupId>
|
<groupId>com.xuxd</groupId>
|
||||||
<artifactId>kafka-console-ui</artifactId>
|
<artifactId>kafka-console-ui</artifactId>
|
||||||
<version>1.0.1</version>
|
<version>1.0.2</version>
|
||||||
<name>kafka-console-ui</name>
|
<name>kafka-console-ui</name>
|
||||||
<description>Kafka console manage ui</description>
|
<description>Kafka console manage ui</description>
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ public class TopicPartitionVO {
|
|||||||
|
|
||||||
private long diff;
|
private long diff;
|
||||||
|
|
||||||
|
private long beginTime;
|
||||||
|
|
||||||
|
private long endTime;
|
||||||
|
|
||||||
public static TopicPartitionVO from(TopicPartitionInfo partitionInfo) {
|
public static TopicPartitionVO from(TopicPartitionInfo partitionInfo) {
|
||||||
TopicPartitionVO partitionVO = new TopicPartitionVO();
|
TopicPartitionVO partitionVO = new TopicPartitionVO();
|
||||||
partitionVO.setPartition(partitionInfo.partition());
|
partitionVO.setPartition(partitionInfo.partition());
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import kafka.console.MessageConsole;
|
||||||
import kafka.console.TopicConsole;
|
import kafka.console.TopicConsole;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.kafka.clients.admin.NewPartitions;
|
import org.apache.kafka.clients.admin.NewPartitions;
|
||||||
import org.apache.kafka.clients.admin.NewTopic;
|
import org.apache.kafka.clients.admin.NewTopic;
|
||||||
import org.apache.kafka.clients.admin.TopicDescription;
|
import org.apache.kafka.clients.admin.TopicDescription;
|
||||||
|
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||||
import org.apache.kafka.common.TopicPartition;
|
import org.apache.kafka.common.TopicPartition;
|
||||||
import org.apache.kafka.common.TopicPartitionInfo;
|
import org.apache.kafka.common.TopicPartitionInfo;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -44,6 +46,9 @@ public class TopicServiceImpl implements TopicService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TopicConsole topicConsole;
|
private TopicConsole topicConsole;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MessageConsole messageConsole;
|
||||||
|
|
||||||
private Gson gson = GsonUtil.INSTANCE.get();
|
private Gson gson = GsonUtil.INSTANCE.get();
|
||||||
|
|
||||||
@Override public ResponseData getTopicNameList(boolean internal) {
|
@Override public ResponseData getTopicNameList(boolean internal) {
|
||||||
@@ -106,6 +111,10 @@ public class TopicServiceImpl implements TopicService {
|
|||||||
mapTuple2._2().forEach((k, v) -> {
|
mapTuple2._2().forEach((k, v) -> {
|
||||||
endTable.put(k.partition(), (Long) v);
|
endTable.put(k.partition(), (Long) v);
|
||||||
});
|
});
|
||||||
|
// computer the valid time range.
|
||||||
|
Map<TopicPartition, Object> beginOffsetTable = new HashMap<>();
|
||||||
|
Map<TopicPartition, Object> endOffsetTable = new HashMap<>();
|
||||||
|
Map<Integer, TopicPartition> partitionCache = new HashMap<>();
|
||||||
|
|
||||||
for (TopicPartitionVO partitionVO : voList) {
|
for (TopicPartitionVO partitionVO : voList) {
|
||||||
long begin = beginTable.get(partitionVO.getPartition());
|
long begin = beginTable.get(partitionVO.getPartition());
|
||||||
@@ -113,7 +122,29 @@ public class TopicServiceImpl implements TopicService {
|
|||||||
partitionVO.setBeginOffset(begin);
|
partitionVO.setBeginOffset(begin);
|
||||||
partitionVO.setEndOffset(end);
|
partitionVO.setEndOffset(end);
|
||||||
partitionVO.setDiff(end - begin);
|
partitionVO.setDiff(end - begin);
|
||||||
|
|
||||||
|
if (begin != end) {
|
||||||
|
TopicPartition partition = new TopicPartition(topic, partitionVO.getPartition());
|
||||||
|
partitionCache.put(partitionVO.getPartition(), partition);
|
||||||
|
beginOffsetTable.put(partition, begin);
|
||||||
|
endOffsetTable.put(partition, end - 1); // end must < endOff
|
||||||
|
} else {
|
||||||
|
partitionVO.setBeginTime(-1L);
|
||||||
|
partitionVO.setEndTime(-1L);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<TopicPartition, ConsumerRecord<byte[], byte[]>> beginRecordMap = messageConsole.searchBy(beginOffsetTable);
|
||||||
|
Map<TopicPartition, ConsumerRecord<byte[], byte[]>> endRecordMap = messageConsole.searchBy(endOffsetTable);
|
||||||
|
|
||||||
|
for (TopicPartitionVO partitionVO : voList) {
|
||||||
|
if (partitionVO.getBeginTime() != -1L) {
|
||||||
|
TopicPartition partition = partitionCache.get(partitionVO.getPartition());
|
||||||
|
partitionVO.setBeginTime(beginRecordMap.containsKey(partition) ? beginRecordMap.get(partition).timestamp() : -1L);
|
||||||
|
partitionVO.setEndTime(endRecordMap.containsKey(partition) ? endRecordMap.get(partition).timestamp() : -1L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ResponseData.create().data(voList).success();
|
return ResponseData.create().data(voList).success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,15 @@
|
|||||||
</a-button>
|
</a-button>
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
</div>
|
</div>
|
||||||
|
<p slot="expandedRowRender" slot-scope="record" style="margin: 0">
|
||||||
|
有效消息的时间范围:<span class="red-font">{{
|
||||||
|
formatTime(record.beginTime)
|
||||||
|
}}</span>
|
||||||
|
~
|
||||||
|
<span class="red-font">{{ formatTime(record.endTime) }}</span>
|
||||||
|
</p>
|
||||||
</a-table>
|
</a-table>
|
||||||
|
<p>友情提示:点击+号展开,可以查看当前分区的有效消息的时间范围</p>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
@@ -59,6 +67,7 @@
|
|||||||
import request from "@/utils/request";
|
import request from "@/utils/request";
|
||||||
import { KafkaOpApi, KafkaTopicApi } from "@/utils/api";
|
import { KafkaOpApi, KafkaTopicApi } from "@/utils/api";
|
||||||
import notification from "ant-design-vue/es/notification";
|
import notification from "ant-design-vue/es/notification";
|
||||||
|
import moment from "moment";
|
||||||
export default {
|
export default {
|
||||||
name: "PartitionInfo",
|
name: "PartitionInfo",
|
||||||
props: {
|
props: {
|
||||||
@@ -128,6 +137,11 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
formatTime(timestamp) {
|
||||||
|
return timestamp != -1
|
||||||
|
? moment(timestamp).format("YYYY-MM-DD HH:mm:ss:SSS")
|
||||||
|
: timestamp;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -169,6 +183,26 @@ const columns = [
|
|||||||
dataIndex: "diff",
|
dataIndex: "diff",
|
||||||
key: "diff",
|
key: "diff",
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// title: "有效消息起始时间",
|
||||||
|
// dataIndex: "beginTime",
|
||||||
|
// key: "beginTime",
|
||||||
|
// slots: { title: "beginTime" },
|
||||||
|
// scopedSlots: { customRender: "internal" },
|
||||||
|
// customRender: (text) => {
|
||||||
|
// return text != -1 ? moment(text).format("YYYY-MM-DD HH:mm:ss:SSS") : text;
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: "有效消息结束时间",
|
||||||
|
// dataIndex: "endTime",
|
||||||
|
// key: "endTime",
|
||||||
|
// slots: { title: "endTime" },
|
||||||
|
// scopedSlots: { customRender: "internal" },
|
||||||
|
// customRender: (text) => {
|
||||||
|
// return text != -1 ? moment(text).format("YYYY-MM-DD HH:mm:ss:SSS") : text;
|
||||||
|
// },
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
title: "操作",
|
title: "操作",
|
||||||
key: "operation",
|
key: "operation",
|
||||||
@@ -177,4 +211,8 @@ const columns = [
|
|||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
.red-font {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user