fix(syslog-consumer-rule): 修复现场日志解析并补充升级工具

- 支持设备头字段值包含空格,避免 WAF 等名称被误拆为无效键值对
- 将空字符串 cropper offset 按未配置处理,兼容历史标准化规则
- 增加设备头解析和空 offset 回归测试
- 增加统计物化 Topic 创建脚本
- 增加容器内 JAR 热替换脚本及操作说明
This commit is contained in:
王绍宏
2026-09-12 11:40:57 +08:00
parent c1472b9a95
commit 3b6c9e4714
10 changed files with 321 additions and 66 deletions
@@ -23,6 +23,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.mock;
class CompiledRuleExecutionEquivalenceTest {
@@ -61,6 +62,21 @@ class CompiledRuleExecutionEquivalenceTest {
}
}
@Test
void blankCropperOffsetsAreTreatedAsNoCropperConfiguration() {
RuleSource source = new RuleSource(9L, "blank-offset", "blank-offset", "json", "{"
+ "\"cropper_params\":{\"head_key\":\"{\",\"head_offset\":\"\","
+ "\"tail_key\":\"\",\"tail_offset\":\"\"},\"mappers\":[]}", true, "0");
String message = "<14> host {\"status\":\"ok\"}";
assertNull(legacy.getCropperParams(source.asLegacyMap()));
assertEquals("ok", legacy.getMessageToMap(source.asLegacyMap(), message, "json").get("status"));
CompiledRule compiled = compiler.compile(source);
assertNull(compiled.getCropper());
assertEquals("ok", compiled.parse(message).getFields().get("status"));
}
private static final class Fixture {
private final String type;
private final String message;
@@ -0,0 +1,54 @@
package com.common.util;
import org.junit.jupiter.api.Test;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class SyslogParserHeaderTest {
@Test
void shouldKeepSpacesInsideDeviceHeaderValues() {
String message = "[receive_time=20260911221200000 event_time=20260911221159000 "
+ "device_id=12 device_name=边界防护 WAF vendor=某某 安全厂商 "
+ "data_type=json device_collect_id=2]{\"message\":\"ok\"}";
Map<String, String> result = SyslogParser.parseKeyValuePairs(message);
assertEquals("20260911221200000", result.get("receive_time"));
assertEquals("20260911221159000", result.get("event_time"));
assertEquals("12", result.get("device_id"));
assertEquals("边界防护 WAF", result.get("device_name"));
assertEquals("某某 安全厂商", result.get("vendor"));
assertEquals("json", result.get("data_type"));
assertEquals("2", result.get("device_collect_id"));
}
@Test
void shouldKeepEmptyAndEqualsContainingValues() {
Map<String, String> result = SyslogParser.parseKeyValuePairs(
"[device_id=12 device_name= vendor=WAF=主节点 data_type=json]");
assertEquals("", result.get("device_name"));
assertEquals("WAF=主节点", result.get("vendor"));
}
@Test
void shouldStillParseLegacySingleWordValues() {
Map<String, String> result = SyslogParser.parseKeyValuePairs(
"[device_id=1 device_name=honeypot vendor=changting data_type=json]");
assertEquals("honeypot", result.get("device_name"));
assertEquals("changting", result.get("vendor"));
}
@Test
void shouldRejectHeaderWithoutKeyValuePair() {
assertThrows(IllegalArgumentException.class,
() -> SyslogParser.parseKeyValuePairs("[WAF]"));
assertThrows(IllegalArgumentException.class,
() -> SyslogParser.parseKeyValuePairs("[WAF device_id=12]"));
}
}