优化单次解析日志显示页面

1. 去除 DeviceStatusChecker 中有关告警日志生成的残留代码
2. 优化 gnss_single_data.html 前端页面显示
3. 优化告警日志文件收集代码
This commit is contained in:
fengyarnom 2025-01-16 11:53:52 +08:00
parent e3cb89c673
commit e1e67b11a2
6 changed files with 116 additions and 84 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -54,7 +54,7 @@
"target": "_self"
},
{
"title": "Log",
"title": "日志",
"href": "page/gnss_single_data",
"icon": "fa fa-clipboard",
"target": "_self"

View File

@ -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>

View File

@ -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();
}
}