提交 de5e5bca 编写于 作者: zlt2000's avatar zlt2000

增加日志链路页面

上级 e9004eb8
......@@ -2,8 +2,6 @@ package com.central.search.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
......@@ -31,6 +29,10 @@ public class SearchDto implements Serializable {
* 排序字段
*/
private String sortCol;
/**
* 排序顺序
*/
private String sortOrder = "DESC";
/**
* 是否显示高亮
*/
......
......@@ -35,7 +35,7 @@ public class SearchServiceImpl implements ISearchService {
public PageResult<JsonNode> strQuery(String indexName, SearchDto searchDto) throws IOException {
return SearchBuilder.builder(client, indexName)
.setStringQuery(searchDto.getQueryStr())
.addSort(searchDto.getSortCol(), SortOrder.DESC)
.addSort(searchDto.getSortCol(), searchDto.getSortOrder())
.setIsHighlight(searchDto.getIsHighlighter())
.getPage(searchDto.getPage(), searchDto.getLimit());
}
......
......@@ -51,6 +51,10 @@ public class SearchBuilder {
* 高亮后缀
*/
private static final String HIGHLIGHTER_POST_TAGS = "</mark>";
/**
* 排序顺序
*/
private static final String SORT_ORDER_ASC = "ASC";
private SearchRequest searchRequest;
private SearchSourceBuilder searchBuilder;
......@@ -144,9 +148,15 @@ public class SearchBuilder {
* @param field 排序字段
* @param order 顺序方向
*/
public SearchBuilder addSort(String field, SortOrder order) {
public SearchBuilder addSort(String field, String order) {
if (StrUtil.isNotEmpty(field) && order != null) {
searchBuilder.sort(field, order);
SortOrder so;
if (SORT_ORDER_ASC.equals(order)) {
so = SortOrder.ASC;
} else {
so = SortOrder.DESC;
}
searchBuilder.sort(field, so);
}
return this;
}
......
......@@ -25,10 +25,6 @@ public class MDCTraceUtils {
* 块id的名称
*/
public static final String KEY_SPAN_ID = "spanId";
/**
* 父块id的名称
*/
public static final String KEY_PARENT_ID = "parentId";
/**
* 日志链路追踪id信息头
......@@ -38,10 +34,6 @@ public class MDCTraceUtils {
* 日志链路块id信息头
*/
public static final String SPAN_ID_HEADER = "x-spanId-header";
/**
* 日志链路父块id信息头
*/
public static final String PARENT_ID_HEADER = "x-parentId-header";
/**
* filter的优先级,值越低越优先
......
package com.central.log.controller;
import com.central.common.model.PageResult;
import com.central.log.model.TraceLog;
import com.central.log.service.TraceLogService;
import com.central.search.client.service.IQueryService;
import com.central.search.model.SearchDto;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
/**
* 系统日志
*
......@@ -18,19 +22,43 @@ import org.springframework.web.bind.annotation.RestController;
*/
@RestController
public class SysLogController {
@Autowired
/**
* 系统日志索引名
*/
private static final String SYS_LOG_INDEXNAME = "sys-log-*";
@Resource
private IQueryService queryService;
@Resource
private TraceLogService traceLogService;
@ApiOperation(value = "系统日志全文搜索列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "分页起始位置", required = true, dataType = "Integer"),
@ApiImplicitParam(name = "limit", value = "分页结束位置", required = true, dataType = "Integer"),
@ApiImplicitParam(name = "queryStr", value = "搜索关键字", dataType = "String")
@ApiImplicitParam(name = "queryStr", value = "搜索关键字", dataType = "String"),
@ApiImplicitParam(name = "sortCol", value = "排序字段", dataType = "String"),
@ApiImplicitParam(name = "sortOrder", value = "排序顺序", dataType = "String"),
@ApiImplicitParam(name = "isHighlighter", value = "是否显示高亮", dataType = "String")
})
@GetMapping(value = "/sysLog")
public PageResult<JsonNode> getPage(SearchDto searchDto) {
searchDto.setIsHighlighter(true);
searchDto.setSortCol("timestamp");
return queryService.strQuery("sys-log-*", searchDto);
public PageResult<JsonNode> sysLog(SearchDto searchDto) {
return queryService.strQuery(SYS_LOG_INDEXNAME, searchDto);
}
@ApiOperation(value = "系统日志链路列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "queryStr", value = "搜索关键字", dataType = "String"),
@ApiImplicitParam(name = "sortCol", value = "排序字段", dataType = "String"),
@ApiImplicitParam(name = "sortOrder", value = "排序顺序", dataType = "String"),
@ApiImplicitParam(name = "isHighlighter", value = "是否显示高亮", dataType = "String")
})
@GetMapping(value = "/traceLog")
public PageResult<TraceLog> traceLog(SearchDto searchDto) {
PageResult<JsonNode> pageResult = queryService.strQuery(SYS_LOG_INDEXNAME, searchDto);
List<JsonNode> jsonNodeList = pageResult.getData();
List<TraceLog> logList = traceLogService.transTraceLog(jsonNodeList);
return PageResult.<TraceLog>builder().data(logList).code(0).count((long) logList.size()).build();
}
}
package com.central.log.model;
import lombok.Getter;
import lombok.Setter;
/**
* 日志链路对象
*
* @author zlt
* @version 1.0
* @date 2022/1/27
* <p>
* Blog: https://zlt2000.gitee.io
* Github: https://github.com/zlt2000
*/
@Setter
@Getter
public class TraceLog {
private String spanId;
private String parentId;
private String appName;
private String serverIp;
private String serverPort;
}
package com.central.log.service;
import cn.hutool.core.util.StrUtil;
import com.central.common.utils.JsonUtil;
import com.central.log.model.TraceLog;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 日志链路service
*
* @author zlt
* @version 1.0
* @date 2022/1/27
* <p>
* Blog: https://zlt2000.gitee.io
* Github: https://github.com/zlt2000
*/
@Service
public class TraceLogService {
public List<TraceLog> transTraceLog(List<JsonNode> jsonNodeList) {
List<TraceLog> logList = new ArrayList<>();
Set<String> logSet = new HashSet<>();
jsonNodeList.forEach(e -> {
TraceLog log = JsonUtil.toObject(e, TraceLog.class);
String spanId = log.getSpanId();
if (StrUtil.isNotEmpty(spanId)) {
if (spanId.length() == 1) {
log.setParentId("-1");
} else {
log.setParentId(spanId.substring(0, spanId.length() - 2));
}
if (checkLog(genLogKey(log), logSet)) {
logList.add(log);
}
}
});
return logList;
}
/**
* 通过集合来去重
*/
private boolean checkLog(String logKey, Set<String> logSet) {
if (logSet.contains(logKey)) {
return false;
} else {
logSet.add(logKey);
return true;
}
}
private String genLogKey(TraceLog log) {
return StrUtil.format("{}_{}_{}_{}", log.getAppName(), log.getSpanId(), log.getServerIp(), log.getServerPort());
}
}
......@@ -29,33 +29,66 @@
layui.use(['form', 'table', 'util', 'config', 'admin', 'upload'], function () {
let table = layui.table;
let config = layui.config;
let util = layui.util;
let admin = layui.admin;
// 渲染表格
table.render({
elem: '#sysLog-table',
url: config.base_server + 'api-log/sysLog',
url: config.base_server + 'api-log/sysLog?sortCol=timestamp&isHighlighter=true',
method: 'GET',
headers:{'Authorization': 'Bearer ' + config.getToken().access_token},
page: true,
cols: [[
{type: 'numbers'},
{
field: 'timestamp', width: 200, sort: true, templet: function (d) {
return util.toDateString(d.timestamp, 'yyyy-MM-dd HH:mm:ss');
}, title: '日志时间'
field: 'timestamp', width: 180, sort: true, templet: function (d) {
let newDate = Date.parse(d.timestamp);
newDate = new Date(newDate);
let yyyy = newDate.getFullYear();
let MM = (newDate.getMonth()+1);
let dd = newDate.getDate();
let hh = newDate.getHours()<10 ? "0"+newDate.getHours() : newDate.getHours();
let mm = newDate.getMinutes()<10 ? "0"+newDate.getMinutes() : newDate.getMinutes();
let ss = newDate.getSeconds()<10 ? "0"+newDate.getSeconds() : newDate.getSeconds();
let SSS = newDate.getMilliseconds();
return yyyy+"-"+MM+"-"+dd+" "+hh+":"+mm+":"+ss+"."+SSS;
}, title: '时间'
},
{field: 'message', sort: true, title: '日志信息', width: 350},
{field: 'logLevel', sort: true, title: '日志级别', width: 100},
{field: 'logLevel', sort: true, title: '日志级别', width: 110},
{field: 'appName', sort: true, title: '应用名', width: 120},
{field: 'serverIp', sort: true, title: '服务ip', width: 130},
{field: 'serverPort', sort: true, title: '服务端口', width: 100},
{field: 'threadName', sort: true, title: '线程名', width: 150},
{field: 'traceId', sort: false, title: '追踪id', width: 180, templet: function (d) {
if (d.traceId){
return '<a class="layui-table-link" href="javascript:void(0);" lay-event="traceLog">'+d.traceId+'</a>';
} else {
return '';
}
}},
{field: 'spanId', sort: false, title: 'spanId', width: 80},
{field: 'classname', sort: true, title: '类名', width: 250},
{field: 'traceId', sort: true, title: '链路追踪id', width: 200}
{field: 'threadName', sort: true, title: '线程名', width: 150},
{field: 'serverIp', sort: true, title: '服务ip', width: 130},
{field: 'serverPort', sort: true, title: '服务端口', width: 110}
]]
});
// 工具条点击事件
table.on('tool(sysLog-table)', function (obj) {
if (obj.event === 'traceLog') {
showTraceLog(obj.data.traceId);
}
});
//显示表单弹窗
let showTraceLog = function (traceId) {
admin.putTempData('traceId', traceId);
admin.popupCenter({
title: '日志链路',
area: '670px',
path: 'pages/log/traceLog.html'
});
};
// 搜索按钮点击事件
$('#sysLog-btn-search').click(function () {
let key = $('#sysLog-search-key').val();
......@@ -63,7 +96,9 @@
if (key != '_all' && value) {
value = key + ':' + value;
}
table.reload('sysLog-table', {where: {queryStr: value}});
table.reload('sysLog-table', {
where: {queryStr: value}
});
});
});
</script>
\ No newline at end of file
<!-- 数据表格 -->
<table class="layui-table" id="trace-table" lay-filter="trace-table"></table>
<script>
layui.use(['config', 'admin', 'table', 'treetable'],function () {
let layer = layui.layer;
let treetable = layui.treetable;
let config = layui.config;
let admin = layui.admin;
let traceId = admin.getTempData('traceId');
// 渲染表格
let renderTable = function () {
layer.load(2);
treetable.render({
treeColIndex: 1,
treeSpid: '-1',
treeIdName: 'spanId',
treePidName: 'parentId',
elem: '#trace-table',
url: config.base_server + 'api-log/traceLog',
where: {
access_token: config.getToken().access_token,
queryStr: 'traceId:'+traceId,
sortCol: 'timestamp',
sortOrder: 'ASC'
},
page: false,
cols: [[
{type: 'numbers'},
{field: 'appName', sort: true, title: '应用名', width: 220},
{field: 'spanId', sort: false, title: 'spanId', width: 130},
{field: 'serverIp', sort: true, title: '服务ip', width: 150},
{field: 'serverPort', sort: true, title: '服务端口', width: 120}
]],
done: function() {
layer.closeAll('loading');
}
});
};
if (traceId) {
renderTable();
}
});
</script>
\ No newline at end of file
......@@ -39,14 +39,7 @@
let form = layui.form;
// 渲染表格
var renderTable = function (param) {
if (param) {
param.access_token = config.getToken().access_token;
} else {
param = {
access_token: config.getToken().access_token
};
}
var renderTable = function (tenantId) {
treetable.render({
treeColIndex: 1,
treeSpid: -1,
......@@ -54,7 +47,10 @@
treePidName: 'parentId',
elem: '#menus-table',
url: config.base_server + 'api-user/menus/findAlls',
where: param,
where: {
access_token: config.getToken().access_token,
tenantId: tenantId
},
page: false,
cols: [[
{type: 'numbers'},
......@@ -79,7 +75,7 @@
]]
});
};
renderTable({tenantId: config.clientId});
renderTable(config.clientId);
// 获取应用列表
layer.load(2);
......@@ -117,7 +113,7 @@
layer.closeAll('loading');
if (0 === data.resp_code) {
layer.msg(data.resp_msg, {icon: 1, time: 500});
renderTable({tenantId: tenantId});
renderTable(tenantId);
} else {
layer.msg(data.resp_msg, {icon: 2, time: 500});
}
......@@ -143,7 +139,7 @@
title: title,
path: 'pages/system/menus_form.html',
finish: function () {
renderTable({tenantId: tenantId});
renderTable(tenantId);
}
});
};
......@@ -186,7 +182,7 @@
// 应用下来框点击事件
form.on('select(menu_clients)', function(data){
renderTable({tenantId: data.value});
renderTable(data.value);
});
});
</script>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册