JDK 11+ 用 -Xlog:gc* 统一日志,需适配 ISO8601 时间戳与键值对结构,弃用 awk 切列,改用正则提取;多版本兼容需按 JDK 版本自动选参;对接 Prometheus 需转换为 OpenMetrics 格式。

JDK 11+ 的 -Xlog:gc* 已取代老旧的 -XX:+PrintGCDetails 等参数,统一日志格式、支持动态开启、可精细过滤——重构运维脚本的关键不是重写逻辑,而是适配新日志结构和时间戳规范。
识别 GC 日志结构变化
JDK 11+ 默认输出 ISO8601 格式时间(含毫秒与时区),每行以 [yyyy-MM-ddTHH:mm:ss.SSSZZ] 开头;关键事件如 GCCause、GCName、Duration 均以键值对形式内嵌在日志行中,不再依赖固定列偏移。旧脚本若用 awk '{print $5,$9}' 提取停顿时间和原因,会失效。
- 用
grep "GC\|Pause\|Allocation" gc.log | head -n 2快速确认实际字段位置 - 典型 JDK 17 行:
[2024-05-22T14:23:18.123+0800][info][gc,heap,exit ] Heap after GC invocations=42 (full=0): - 关键信息藏在标签(
[gc,heap])、级别(info)和冒号后文本中,需正则提取而非切列
重写日志解析核心逻辑
放弃基于空格/制表符分割的硬编码方式,改用正则匹配结构化字段。例如提取 Young GC 暂停时间:
- 匹配模式:
\[.*?\]\[info\]\[gc,phases\].*?Young.*?pause.*?Duration: ([0-9.]+)ms - 用
perl -nle 'print $1 if /Duration: ([0-9.]+)ms/' gc.log替代旧版awk '/Pause/{print $NF}' - 对 Full GC 或 Metaspace 回收,分别匹配
Full GC或Metaspace.*?used.*?->后的内存变化
兼容多 JDK 版本的日志启动参数
运维脚本常需同时支持 JDK 8–17。可在启动前检测版本并自动选择参数:
java -version 2>&1 | grep "11\|17" && LOG_ARG="-Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=10,filesize=100m"- JDK 8 仍用:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M - 统一日志路径和轮转策略,避免脚本分支处理不同文件名
对接 Prometheus + Grafana 的指标转换
新日志不直接输出 metrics,需轻量级采集器做中间转换。推荐用 gclogparser(Go 编写,无依赖)或自研 Python 脚本:
- 将每条 GC 记录转为 OpenMetrics 格式:
jdk_gc_pause_seconds{phase="young",cause="G1 Evacuation Pause"} 0.042 - 暴露 HTTP 端点供 Prometheus 抓取,或写入临时文件由
textfile_collector加载 - 关键指标保留:暂停时长(直方图)、GC 频次(counter)、堆内存使用峰值(gauge)、晋升失败次数(counter)
不复杂但容易忽略:JDK 17 默认启用 ZGC/G1 并行类卸载,-Xlog:gc+class+unload 可单独打开类卸载日志,这对排查 PermGen/Metaspace 泄漏更精准。脚本升级时顺手加上这一层,监控就更完整了。

















