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

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){ 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 warningLogExecutor = new WarningLogExecutor(logDirectory);
warningLogExecutor.generateWarningLogs(device_id, warning_type_name); warningLogExecutor.generateWarningLogs(device_id, warning_type_name);
} }

View File

@ -43,15 +43,14 @@ public class GnssSingleDataController extends BasicController implements CommonE
JSONObject search = null; JSONObject search = null;
if (searchParams != null) { if (searchParams != null) {
search = (JSONObject) JSONObject.parse(searchParams); 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"); Integer freqency = search.getInteger("freqency");
String begin = search.getString("dgt_.createtime"); String begin = search.getString("dgt_.createtime");
String end = search.getString("dlt_.createtime"); String end = search.getString("dlt_.createtime");
if(deviceId != null && !deviceId.isEmpty() && freqency!=0){ if(deviceId != null && !deviceId.isEmpty() && freqency!=0){
Page pageable = new Page<>(page == null ? 1 : page, limit == null ? 10 : limit); Page pageable = new Page<>(page == null ? 1 : page, limit == null ? 10 : limit);
// 缺省按1小时采样如果时间跨度较大则按最多300条记录的采样率采样 // 缺省按1小时采样如果时间跨度较大则按最多300条记录的采样率采样
int sample = 6; int sample = 6;

View File

@ -4,7 +4,6 @@ import com.imdroid.beidou.service.NotificationService;
import com.imdroid.secapi.dto.*; import com.imdroid.secapi.dto.*;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
@ -44,9 +43,6 @@ public class DeviceStatusChecker {
@Autowired @Autowired
GnssDeviceMapper deviceMapper; GnssDeviceMapper deviceMapper;
@Value("${warning.log.directory}")
private String logDirectory;
static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Scheduled(cron = "0 18,48 * * * ?") // 每半时执行一次 @Scheduled(cron = "0 18,48 * * * ?") // 每半时执行一次
@ -157,11 +153,6 @@ public class DeviceStatusChecker {
status.setWarning(WarningCfg.LEVEL_2); status.setWarning(WarningCfg.LEVEL_2);
deviceIds.add(status.getDeviceid()); deviceIds.add(status.getDeviceid());
// 生成 Warning 日志
WarningLogExecutor warningLogExecutor = new WarningLogExecutor(logDirectory);
warningLogExecutor.generateWarningLogs(status.getDeviceid(),WarningCfg.TYPE_NAME_NO_FIXED_RESULT);
} }
gnssStatusMapper.updateById(status); gnssStatusMapper.updateById(status);
} }

View File

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

View File

@ -20,7 +20,7 @@
<div class="layui-inline"> <div class="layui-inline">
<label class="layui-form-label">设备号</label> <label class="layui-form-label">设备号</label>
<div class="layui-input-inline"> <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" > <select id="deviceid" lay-search="" lay-filter="device" >
<option value="">全部</option> <option value="">全部</option>
</select> </select>
@ -88,11 +88,12 @@
var echartsDevice = echarts.init(document.getElementById('echarts-gnss'), 'walden'); var echartsDevice = echarts.init(document.getElementById('echarts-gnss'), 'walden');
var data_cols = [ var data_cols = [
{field: 'deviceid', title: '设备号'}, {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: 'createtime', title: '产生时间', width:'18%', templet: "<div>{{layui.util.toDateString(d.createtime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
{field: 'x', title: '东'}, {field: 'x', title: '东'},
{field: 'y', title: '北'}, {field: 'y', title: '北'},
{field: 'z', title: '天'}, {field: 'z', title: '天'},
{field: 'status', title: '状态'} {field: 'status', title: '状态', templet: '#status'}
]; ];
/** /**
* 初始化表单,要加上,不然刷新部分组件可能会不加载 * 初始化表单,要加上,不然刷新部分组件可能会不加载
@ -122,7 +123,7 @@
skin: 'line', skin: 'line',
done: function (result, curr, count) { done: function (result, curr, count) {
if(searchDeviceId){ if(searchDeviceId){
console.log(result.data); // console.log(result.data);
showChart(result.data) showChart(result.data)
} }
} }
@ -245,5 +246,50 @@
}); });
</script> </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> </body>
</html> </html>

View File

@ -1,21 +1,15 @@
package com.imdroid.common.util; 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.ExecutorService;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.io.*;
import java.util.stream.Stream; import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
public class WarningLogExecutor { public class WarningLogExecutor {
private final String logDirectory; private final String logDirectory;
private final ExecutorService executor; private final ExecutorService executor;
// 记录已初始化的文件
private final ConcurrentHashMap<String, Boolean> initializedFiles = new ConcurrentHashMap<>();
public WarningLogExecutor(String logDirectory) { public WarningLogExecutor(String logDirectory) {
this.logDirectory = logDirectory; this.logDirectory = logDirectory;
@ -23,68 +17,69 @@ public class WarningLogExecutor {
} }
public void generateWarningLogs(String keyword, String warningTypeName) { 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 { try {
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")); // 判断目录是否存在一般写在 application.properties
String warningFileName = "Warning-" + keyword + "-" + date + ".log"; File dir = new File(dirPath);
Path warningFile = Paths.get(logDirectory, warningFileName); if (!dir.exists() || !dir.isDirectory()) {
return;
// 如果是新文件先写入初始化信息
if (initializedFiles.putIfAbsent(warningFileName, true) == null) {
initializeWarningFile(warningFile, keyword, warningTypeName);
} }
try (Stream<Path> logFilesStream = Files.list(Paths.get(logDirectory))) { // 只收集一小时内的日志否则太影响性能
List<Path> logFiles = logFilesStream long oneHourAgo = System.currentTimeMillis() - 3600000;
.filter(Files::isRegularFile) File[] files = dir.listFiles((d, name) -> name.startsWith("sideslopertcm"));
.filter(path -> path.getFileName().toString().matches("sideslopertcm(\\.\\d{4}-\\d{2}-\\d{2}\\.\\d+)?\\.log"))
.collect(Collectors.toList());
for (Path logFile : logFiles) {
executor.submit(() -> processFile(logFile, keyword, warningFile)); 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()));
}
}
if (processedFiles.length() == 0) {
return;
}
// 文件名的日期只保存年月日当天重复触发会新的覆盖旧的
String date = DateTimeFormatter.ofPattern("yyyyMMdd")
.format(LocalDateTime.now());
String outputFileName = String.format("%s/Warning_%s_%s_%s.log", dirPath,deviceId,date, warningType);
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(deviceId)) {
writer.write(String.format("[%s] %s\n",
file.getName(), line));
}
}
}
}
}
} }
} }
} catch (IOException e) { } catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
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();
}
}
private void processFile(Path logFile, String keyword, Path warningFile) {
try (BufferedReader reader = Files.newBufferedReader(logFile);
BufferedWriter writer = Files.newBufferedWriter(warningFile,
StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
writer.write("Processing source file: " + logFile.getFileName());
writer.newLine();
String line;
while ((line = reader.readLine()) != null) {
if (line.contains(keyword)) {
writer.write(line);
writer.newLine();
}
}
} catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }