优化单次解析日志显示页面
1. 去除 DeviceStatusChecker 中有关告警日志生成的残留代码 2. 优化 gnss_single_data.html 前端页面显示 3. 优化告警日志文件收集代码
This commit is contained in:
parent
e3cb89c673
commit
e1e67b11a2
@ -268,7 +268,8 @@ public class WarningServiceImpl implements WarningService {
|
||||
}
|
||||
|
||||
public void generate_warning_logs(String device_id,int warning_type,String warning_type_name){
|
||||
if (warning_type == WarningCfg.TYPE_LOW_VOLTAGE) {
|
||||
// 连续无固定解 和 掉电 警告
|
||||
if (warning_type == WarningCfg.TYPE_NO_FIXED_RESULT || warning_type == WarningCfg.TYPE_LOW_VOLTAGE) {
|
||||
WarningLogExecutor warningLogExecutor = new WarningLogExecutor(logDirectory);
|
||||
warningLogExecutor.generateWarningLogs(device_id, warning_type_name);
|
||||
}
|
||||
|
||||
@ -43,15 +43,14 @@ public class GnssSingleDataController extends BasicController implements CommonE
|
||||
JSONObject search = null;
|
||||
if (searchParams != null) {
|
||||
search = (JSONObject) JSONObject.parse(searchParams);
|
||||
System.out.println(search);
|
||||
String deviceId = search.getString("deviceid");
|
||||
|
||||
String deviceId = search.getString("sl_deviceid"); // sql where like deviceid
|
||||
Integer freqency = search.getInteger("freqency");
|
||||
String begin = search.getString("dgt_.createtime");
|
||||
String end = search.getString("dlt_.createtime");
|
||||
|
||||
if(deviceId != null && !deviceId.isEmpty() && freqency!=0){
|
||||
Page pageable = new Page<>(page == null ? 1 : page, limit == null ? 10 : limit);
|
||||
|
||||
// 缺省按1小时采样,如果时间跨度较大,则按最多300条记录的采样率采样
|
||||
int sample = 6;
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@ import com.imdroid.beidou.service.NotificationService;
|
||||
import com.imdroid.secapi.dto.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@ -44,9 +43,6 @@ public class DeviceStatusChecker {
|
||||
@Autowired
|
||||
GnssDeviceMapper deviceMapper;
|
||||
|
||||
@Value("${warning.log.directory}")
|
||||
private String logDirectory;
|
||||
|
||||
static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Scheduled(cron = "0 18,48 * * * ?") // 每半时执行一次
|
||||
@ -157,11 +153,6 @@ public class DeviceStatusChecker {
|
||||
status.setWarning(WarningCfg.LEVEL_2);
|
||||
deviceIds.add(status.getDeviceid());
|
||||
|
||||
// 生成 Warning 日志
|
||||
WarningLogExecutor warningLogExecutor = new WarningLogExecutor(logDirectory);
|
||||
warningLogExecutor.generateWarningLogs(status.getDeviceid(),WarningCfg.TYPE_NAME_NO_FIXED_RESULT);
|
||||
|
||||
|
||||
}
|
||||
gnssStatusMapper.updateById(status);
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
"target": "_self"
|
||||
},
|
||||
{
|
||||
"title": "Log",
|
||||
"title": "日志",
|
||||
"href": "page/gnss_single_data",
|
||||
"icon": "fa fa-clipboard",
|
||||
"target": "_self"
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">设备号</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="deviceid" id="input_deviceid" class="layui-input" style="position:absolute;z-index:2;width:85%;" value="" autocomplete="off">
|
||||
<input type="text" name="sl_deviceid" id="input_deviceid" class="layui-input" style="position:absolute;z-index:2;width:85%;" value="" autocomplete="off">
|
||||
<select id="deviceid" lay-search="" lay-filter="device" >
|
||||
<option value="">全部</option>
|
||||
</select>
|
||||
@ -88,11 +88,12 @@
|
||||
var echartsDevice = echarts.init(document.getElementById('echarts-gnss'), 'walden');
|
||||
var data_cols = [
|
||||
{field: 'deviceid', title: '设备号'},
|
||||
{field: 'model', title: '模块', templet: '#model'},
|
||||
{field: 'createtime', title: '产生时间', width:'18%', templet: "<div>{{layui.util.toDateString(d.createtime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
||||
{field: 'x', title: '东'},
|
||||
{field: 'y', title: '北'},
|
||||
{field: 'z', title: '天'},
|
||||
{field: 'status', title: '状态'}
|
||||
{field: 'status', title: '状态', templet: '#status'}
|
||||
];
|
||||
/**
|
||||
* 初始化表单,要加上,不然刷新部分组件可能会不加载
|
||||
@ -122,7 +123,7 @@
|
||||
skin: 'line',
|
||||
done: function (result, curr, count) {
|
||||
if(searchDeviceId){
|
||||
console.log(result.data);
|
||||
// console.log(result.data);
|
||||
showChart(result.data)
|
||||
}
|
||||
}
|
||||
@ -245,5 +246,50 @@
|
||||
});
|
||||
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
const STATUS_CONFIG_F9P = {
|
||||
0: { text: '无B562', color: 'layui-bg-gray' },
|
||||
1: { text: '浮点解', color: 'layui-bg-gray' },
|
||||
2: { text: '固定解', color: 'layui-bg-green' },
|
||||
default: { text: '其他', color: 'layui-bg-gray' }
|
||||
};
|
||||
const STATUS_CONFIG_GGA = {
|
||||
4: { text: '固定解', color: 'layui-bg-green' },
|
||||
5: { text: '浮点解', color: 'layui-bg-gray' },
|
||||
default: { text: '其他', color: 'layui-bg-gray' }
|
||||
};
|
||||
|
||||
function renderStatus(model,status) {
|
||||
if(model === 0){
|
||||
const config = STATUS_CONFIG_F9P[status] || STATUS_CONFIG_F9P.default;
|
||||
return `<span class="layui-badge ${config.color}">${config.text}</span>`;
|
||||
}
|
||||
else if(model === 1){
|
||||
const config = STATUS_CONFIG_GGA[status] || STATUS_CONFIG_GGA.default;
|
||||
return `<span class="layui-badge ${config.color}">${config.text}</span>`;
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
<script type="text/html" id="status">
|
||||
{{ renderStatus(d.model,d.status) }}
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
const MODEL_CONFIG = {
|
||||
0: { text: 'ECEF - F9P', color: 'layui-bg-orange' },
|
||||
1: { text: 'GGA - 博通', color: 'layui-bg-green' }
|
||||
};
|
||||
|
||||
function renderModel(model) {
|
||||
const config = MODEL_CONFIG[model] || MODEL_CONFIG[0];
|
||||
return `<span class="layui-badge ${config.color}">${config.text}</span>`;
|
||||
}
|
||||
</script>
|
||||
<script type="text/html" id="model">
|
||||
{{ renderModel(d.model) }}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -1,21 +1,15 @@
|
||||
package com.imdroid.common.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import java.io.*;
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class WarningLogExecutor {
|
||||
|
||||
private final String logDirectory;
|
||||
private final ExecutorService executor;
|
||||
// 记录已初始化的文件
|
||||
private final ConcurrentHashMap<String, Boolean> initializedFiles = new ConcurrentHashMap<>();
|
||||
|
||||
public WarningLogExecutor(String logDirectory) {
|
||||
this.logDirectory = logDirectory;
|
||||
@ -23,68 +17,69 @@ public class WarningLogExecutor {
|
||||
}
|
||||
|
||||
public void generateWarningLogs(String keyword, String warningTypeName) {
|
||||
// 单线程处理,防止数据写入混乱
|
||||
executor.submit(() -> searchLogsForDeviceID(this.logDirectory, keyword, warningTypeName));
|
||||
}
|
||||
|
||||
public static void searchLogsForDeviceID(String dirPath, String deviceId, String warningType) {
|
||||
try {
|
||||
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
|
||||
String warningFileName = "Warning-" + keyword + "-" + date + ".log";
|
||||
Path warningFile = Paths.get(logDirectory, warningFileName);
|
||||
|
||||
// 如果是新文件,先写入初始化信息
|
||||
if (initializedFiles.putIfAbsent(warningFileName, true) == null) {
|
||||
initializeWarningFile(warningFile, keyword, warningTypeName);
|
||||
// 判断目录是否存在,一般写在 application.properties 中
|
||||
File dir = new File(dirPath);
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (Stream<Path> logFilesStream = Files.list(Paths.get(logDirectory))) {
|
||||
List<Path> logFiles = logFilesStream
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(path -> path.getFileName().toString().matches("sideslopertcm(\\.\\d{4}-\\d{2}-\\d{2}\\.\\d+)?\\.log"))
|
||||
.collect(Collectors.toList());
|
||||
// 只收集一小时内的日志,否则太影响性能
|
||||
long oneHourAgo = System.currentTimeMillis() - 3600000;
|
||||
File[] files = dir.listFiles((d, name) -> name.startsWith("sideslopertcm"));
|
||||
|
||||
for (Path logFile : logFiles) {
|
||||
executor.submit(() -> processFile(logFile, keyword, warningFile));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
executor.shutdown();
|
||||
|
||||
if (files != null && files.length > 0) {
|
||||
Arrays.sort(files, (f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified()));
|
||||
|
||||
StringBuilder processedFiles = new StringBuilder();
|
||||
for (File file : files) {
|
||||
if (file.lastModified() >= oneHourAgo) {
|
||||
processedFiles.append(String.format("%s\n", file.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeWarningFile(Path warningFile, String keyword, String warningTypeName) {
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(warningFile,
|
||||
StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
|
||||
writer.write("=== Warning Log File ===");
|
||||
writer.newLine();
|
||||
writer.write("Created Time: " + LocalDateTime.now());
|
||||
writer.newLine();
|
||||
writer.write("Warning Type Name: " + warningTypeName);
|
||||
writer.newLine();
|
||||
writer.write("Keyword: " + keyword);
|
||||
writer.newLine();
|
||||
writer.write("==============================");
|
||||
writer.newLine();
|
||||
writer.newLine();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (processedFiles.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
private void processFile(Path logFile, String keyword, Path warningFile) {
|
||||
try (BufferedReader reader = Files.newBufferedReader(logFile);
|
||||
BufferedWriter writer = Files.newBufferedWriter(warningFile,
|
||||
StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
|
||||
// 文件名的日期只保存年月日,当天重复触发会新的覆盖旧的
|
||||
String date = DateTimeFormatter.ofPattern("yyyyMMdd")
|
||||
.format(LocalDateTime.now());
|
||||
String outputFileName = String.format("%s/Warning_%s_%s_%s.log", dirPath,deviceId,date, warningType);
|
||||
|
||||
writer.write("Processing source file: " + logFile.getFileName());
|
||||
writer.newLine();
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFileName))) {
|
||||
writer.write("=== 搜索信息 ===\n");
|
||||
writer.write("处理时间: " + LocalDateTime.now() + "\n");
|
||||
writer.write("搜索目录: " + dirPath + "\n");
|
||||
writer.write("设备ID: " + deviceId + "\n");
|
||||
writer.write("警告类型: " + warningType + "\n\n");
|
||||
|
||||
writer.write("=== 处理文件列表 ===\n");
|
||||
writer.write(processedFiles.toString());
|
||||
writer.write("\n=== 匹配结果 ===\n");
|
||||
|
||||
for (File file : files) {
|
||||
if (file.lastModified() >= oneHourAgo) {
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains(keyword)) {
|
||||
writer.write(line);
|
||||
writer.newLine();
|
||||
if (line.contains(deviceId)) {
|
||||
writer.write(String.format("[%s] %s\n",
|
||||
file.getName(), line));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user