package com.common.util; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.common.entity.SyslogMessage; import com.common.entity.RFC3164Message; import com.common.entity.RFC5424Message; import com.influx.SyslogToInfluxApp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.core.JsonProcessingException; import java.util.Locale; public class SyslogParser { private static final Logger logger = LoggerFactory.getLogger(SyslogToInfluxApp.class); // RFC 5424 正则表达式 private static final Pattern RFC5424_PATTERN = Pattern.compile( "^<(?\\d{1,3})>(?\\d+) " + "(?\\S+) " + "(?\\S+) " + "(?\\S+) " + "(?\\S+) " + "(?\\S+) " + "(?(?:-|\\[.*\\]))" + "(?: (?.+))?$" ); // RFC 3164 正则表达式 private static final Pattern RFC3164_PATTERN = Pattern.compile( "^<(?\\d{1,3})>" + "(?[A-Z][a-z]{2}\\s+\\d{1,2}\\s+\\d{2}:\\d{2}:\\d{2}) " + "(?\\S+) " + "(?.+)$" ); // RFC 3164 时间戳格式 private static final DateTimeFormatter RFC3164_FORMATTER = DateTimeFormatter.ofPattern("MMM dd HH:mm:ss"); /** * 解析 Syslog 消息,自动检测格式 */ public static SyslogMessage parse(String logLine) { if (logLine == null || logLine.trim().isEmpty()) { throw new IllegalArgumentException("Log line cannot be null or empty"); } // 尝试解析为 RFC 5424 格式 try { RFC5424Message msg5424 = parseRFC5424(logLine); if (msg5424 != null) { return msg5424; } } catch (Exception e) { // 继续尝试 RFC 3164 } // 尝试解析为 RFC 3164 格式 try { RFC3164Message msg3164 = parseRFC3164(logLine); if (msg3164 != null) { return msg3164; } } catch (Exception e) { // 解析失败 } // 解析非标数据格式,提取字符【{】自后的内容 try { String content = extractJsonStringNew(logLine); RFC5424Message msgClass =new RFC5424Message(); if (content != null) { msgClass.setMessage(content.toString()); return msgClass; } } catch (Exception e) { // 解析失败 } throw new IllegalArgumentException("Unable to parse syslog message: " + logLine); } /** * 解析 RFC 5424 格式 */ public static RFC5424Message parseRFC5424(String logLine) { Matcher matcher = RFC5424_PATTERN.matcher(logLine); if (!matcher.find()) { return null; } RFC5424Message message = new RFC5424Message(); // 解析优先级 int pri = Integer.parseInt(matcher.group("pri")); message.setPriority(pri); // 解析版本 message.setVersion(Integer.parseInt(matcher.group("version"))); // 解析时间戳 (RFC 3339 格式) String timestampStr = matcher.group("timestamp"); try { message.setTimestamp(OffsetDateTime.parse(timestampStr)); } catch (DateTimeParseException e) { throw new IllegalArgumentException("Invalid RFC5424 timestamp: " + timestampStr, e); } // 解析其他字段 message.setHostname(matcher.group("host")); message.setAppName(matcher.group("app")); message.setProcId(matcher.group("pid")); message.setMsgId(matcher.group("msgid")); // 解析结构化数据 String sd = matcher.group("sd"); if (!"-".equals(sd)) { message.setStructuredData(parseStructuredData(sd)); } // 解析消息内容 String msg = matcher.group("message"); if (msg != null) { message.setMessage(msg.trim()); } return message; } /** * 解析 RFC 3164 格式 */ public static RFC3164Message parseRFC3164(String logLine) { Matcher matcher = RFC3164_PATTERN.matcher(logLine); if (!matcher.find()) { return null; } RFC3164Message message = new RFC3164Message(); // 解析优先级 int pri = Integer.parseInt(matcher.group("pri")); message.setPriority(pri); // 解析时间戳 (需要特殊处理,因为没有年份) String timestampStr = matcher.group("timestamp"); message.setTimestamp(parseRFC3164Timestamp(timestampStr)); // 解析主机名 message.setHostname(matcher.group("host")); // 解析内容和标签 String content = matcher.group("content"); parseRFC3164Content(content, message); return message; } /** * 解析 RFC 3164 时间戳 */ private static OffsetDateTime parseRFC3164Timestamp(String timestampStr) { try { // 添加当前年份,因为 RFC3164 时间戳不包含年份 String currentYear = String.valueOf(java.time.Year.now().getValue()); String fullTimestamp = currentYear + " " + timestampStr; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MMM dd HH:mm:ss", Locale.US); LocalDateTime localDateTime = LocalDateTime.parse(fullTimestamp, formatter); // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MMM dd HH:mm:ss", Locale.US); // 假设为系统默认时区 return localDateTime.atOffset(ZoneOffset.systemDefault().getRules().getOffset(localDateTime)); } catch (DateTimeParseException e) { throw new IllegalArgumentException("Invalid RFC3164 timestamp: " + timestampStr, e); } } /** * 解析 RFC 3164 内容部分 */ private static void parseRFC3164Content(String content, RFC3164Message message) { // 尝试匹配标签格式: app[pid]: Pattern tagPattern = Pattern.compile("^(?\\S+?)(?:\\[(?\\d+)\\])?:\\s*(?.*)$"); Matcher tagMatcher = tagPattern.matcher(content); if (tagMatcher.find()) { message.setTag(tagMatcher.group("tag")); String pid = tagMatcher.group("pid"); if (pid != null) { message.setProcId(pid); } message.setMessage(tagMatcher.group("message").trim()); } else { // 如果没有标签格式,整个内容作为消息 message.setTag(""); message.setMessage(content.trim()); } // 对于 RFC3164,appName 通常与 tag 相同 message.setAppName(message.getTag()); } /** * 解析结构化数据 */ private static Map> parseStructuredData(String sd) { Map> structuredData = new HashMap<>(); // 简单的结构化数据解析,实际应用可能需要更复杂的解析 Pattern sdPattern = Pattern.compile("\\[(?[^\\]]+)\\]"); Pattern paramPattern = Pattern.compile("(?[^=\\s]+)=\"(?[^\"]*)\""); Matcher sdMatcher = sdPattern.matcher(sd); while (sdMatcher.find()) { String sdElement = sdMatcher.group("id"); Map params = new HashMap<>(); Matcher paramMatcher = paramPattern.matcher(sdElement); while (paramMatcher.find()) { params.put(paramMatcher.group("key"), paramMatcher.group("value")); } // 使用第一个参数作为键,或者生成一个键 String key = params.containsKey("sdId") ? params.get("sdId") : "element" + structuredData.size(); structuredData.put(key, params); } return structuredData; } /** * 提取 JSON 字符串(不解析) */ public static Optional extractJsonString(String syslogMessage) { try { if (syslogMessage == null) return Optional.empty(); int jsonStart = syslogMessage.indexOf('{'); if (jsonStart == -1) return Optional.empty(); return Optional.of(syslogMessage.substring(jsonStart)); } catch (Exception e) { return Optional.empty(); } } /** * 提取 JSON 字符串(不解析) */ public static String extractJsonStringNew (String syslogMessage) { try { if (syslogMessage == null) return ""; int jsonStart = syslogMessage.indexOf('{'); if (jsonStart == -1) return ""; return syslogMessage.substring(jsonStart); } catch (Exception e) { return ""; } } /** * 截取字符串中第一个 ']' 之后的所有内容 * * @param text 原始字符串 * @return 第一个 ']' 之后的内容,如果没有 ']' 则返回空字符串 */ public static String substringAfterFirstCloseBracket(String text) { if (text == null) { return ""; } int closeBracketIndex = text.indexOf(']'); if (closeBracketIndex == -1) { return ""; // 没有找到 ']',返回空字符串 } // 返回 ']' 之后的内容(+1 是为了跳过 ']' 本身) return text.substring(closeBracketIndex + 1); } /** * 截取字符串中第一个指定字符之前的所有内容 * * @param text 原始字符串 * @param delimiterChar 分隔字符 * @return 分隔字符之前的内容 */ public static String substringBeforeFirstChar(String text, char delimiterChar) { if (text == null) { return ""; } int delimiterIndex = text.indexOf(delimiterChar); if (delimiterIndex == -1) { return text; } return text.substring(0, delimiterIndex+1); } /** * 从文本中提取第一个 [] 包裹的键值对字符串并转换为 Map * * @param text 包含键值对的原始文本 * @return 包含键值对的 Map * @throws IllegalArgumentException 如果格式不正确 */ public static Map parseKeyValuePairs(String text) { if (text == null || text.trim().isEmpty()) { throw new IllegalArgumentException("Input text cannot be null or empty"); } // 查找第一个 [ 和对应的 ] int start = text.indexOf('['); int end = text.indexOf(']', start + 1); if (start == -1 || end == -1) { throw new IllegalArgumentException("No valid [] pair found in text"); } // 提取 [] 内的内容 String content = text.substring(start + 1, end).trim(); if (content.isEmpty()) { return new HashMap<>(); // 返回空Map } // 分割键值对 String[] pairs = content.split("\\s+"); Map result = new HashMap<>(); for (String pair : pairs) { // 分割键和值 int equalSign = pair.indexOf('='); if (equalSign == -1) { throw new IllegalArgumentException("Invalid key-value pair format: " + pair); } String key = pair.substring(0, equalSign).trim(); String value = pair.substring(equalSign + 1).trim(); if (key.isEmpty()) { throw new IllegalArgumentException("Key cannot be empty in pair: " + pair); } result.put(key, value); } return result; } }