修复Elastic Watcher JVM内存告警Painless脚本编译错误
Elastic Watcher JVM内存告警Painless脚本编译错误修复方案
编译错误根因
移除transform后查询正常,说明索引检索、字段映射均无问题,无详情compile error基本都是以下三类Painless语法问题导致:
- 带
.的字段访问方式错误:host.name、service.name这类字段名本身包含点,若直接用source.host.name写法,Painless会将其解析为嵌套对象属性访问,和实际平级存储的字段结构不匹配,直接触发编译失败。 - 语法不符合Painless规范:比如用
var声明变量(Painless仅支持def做类型推断)、漏写语句分号、未做类型强转导致数值运算类型不匹配、字符串嵌套引号冲突。 - transform返回结构不合法:Watcher要求transform脚本必须返回可序列化的Map/List结构,未写return语句、返回基本类型值都会触发校验错误。
可直接复用的正确配置
transform 数据处理片段
"transform": { "script": { "lang": "painless", "source": """ def alertThreshold = 90.0; def targetAlerts = new ArrayList(); for (def hit : ctx.payload.hits.hits) { def docSource = hit._source; // 安全读取字段,缺省值设为0避免空指针 def usedSurvivor = docSource.getOrDefault('memory_used_g1_survivor_space', 0); def usedEden = docSource.getOrDefault('memory_used_g1_eden_space', 0); def usedOld = docSource.getOrDefault('memory_used_g1_old_gen', 0); def maxSurvivor = docSource.getOrDefault('memory_max_g1_survivor_space', 0); def maxEden = docSource.getOrDefault('memory_max_g1_eden_space', 0); def maxOld = docSource.getOrDefault('memory_max_g1_old_gen', 0); // 强转为double避免整数除法精度丢失 def totalUsed = (double)usedSurvivor + usedEden + usedOld; def totalMax = (double)maxSurvivor + maxEden + maxOld; // 跳过最大内存为0的异常数据,避免除零错误 if (totalMax <= 0) { continue; } def heapUsage = (totalUsed / totalMax) * 100; if (heapUsage > alertThreshold) { targetAlerts.add([ 'host.name': docSource.getOrDefault('host.name', 'unknown_host'), 'service.name': docSource.getOrDefault('service.name', 'unknown_service'), 'heap_usage_percent': Math.round(heapUsage * 100) / 100, 'heap_used_bytes': totalUsed, 'heap_max_bytes': totalMax ]); } } return ['matched_alerts': targetAlerts]; """ } }
condition 判断片段
"condition": { "script": { "lang": "painless", "source": "return ctx.payload.matched_alerts.size() > 0;" } }
action部分直接引用ctx.payload.matched_alerts里的字段做告警模板渲染即可。
Painless脚本调试方法
无需第三方工具,用Elastic原生能力即可精确定位错误:
- 用Kibana开发工具的Painless执行接口单独测试脚本,指定watcher_transform上下文,传入查询返回的样例文档作为测试输入,接口会返回精确到行号的编译错误信息,不会出现无详情报错。测试请求模板:
POST _scripts/painless/_execute { "script": { "lang": "painless", "source": "粘贴待测试的Painless脚本内容" }, "context": "watcher_transform", "context_setup": { "payload": { "hits": { "hits": [ // 粘贴实际查询返回的样例文档作为测试输入 { "_source": { "memory_max_g1_survivor_space": 1073741824, "memory_max_g1_eden_space": 4294967296, "memory_max_g1_old_gen": 8589934592, "memory_used_g1_survivor_space": 987842478, "memory_used_g1_eden_space": 4127195136, "memory_used_g1_old_gen": 8053063680, "host.name": "prod-app-03", "service.name": "payment-service" } } ] } } } }
- 调试阶段可在脚本返回结果中加入中间计算值(比如totalUsed、totalMax),执行后即可直接查看每一步运算结果是否符合预期,无需每次模拟运行完整Watcher流程。脚本验证通过后再粘回Watcher配置即可。
内容的提问来源于stack exchange,提问作者Abo1787
相关产品推荐
相关产品推荐

