Kibana 服务器端插件开发

上一节介绍了如何给 Kibana 开发浏览器端的可视化插件。新版 Kibana 跟 Kibana3 比,最大的一个变化是有了独立的 node.js 服务器端。那么同样的,也就有了服务器端的 Kibana 插件。最明显的一个场景:我们可以在 node.js 里跑定时器做 Elasticsearch 的告警逻辑了!

本节示例一个最基础的 Kibana 告警插件开发。只演示基础的定时器和 Kibana 插件规范,实际运用中,肯定还涉及历史记录,告警项配置更新等。请读者不要直接 copy-paste。

首先,我们尽量沿袭 Elastic 官方的 watcher 产品的告警配置设计。也新建一个索引,里面是具体的配置内容:

  1. # curl -XPUT http://127.0.0.1:9200/watcher/watch/error_status -d'
  2. {
  3. "trigger": {
  4. "schedule" : { "interval" : "60" }
  5. },
  6. "input" : {
  7. "search" : {
  8. "request" : {
  9. "indices" : [ "<logstash-{now/d}>", "<logstash-{now/d-1d}>" ],
  10. "body" : {
  11. "query" : {
  12. "filtered" : {
  13. "query" : { "match" : { "host" : "MacBook-Pro" } },
  14. "filter" : { "range" : { "@timestamp" : { "from" : "now-5m" } } }
  15. }
  16. }
  17. }
  18. }
  19. }
  20. },
  21. "condition" : {
  22. "script" : {
  23. "script" : "payload.hits.total > 0"
  24. }
  25. },
  26. "transform" : {
  27. "search" : {
  28. "request" : {
  29. "indices" : [ "<logstash-{now/d}>", "<logstash-{now/d-1d}>" ],
  30. "body" : {
  31. "query" : {
  32. "filtered" : {
  33. "query" : { "match" : { "host" : "MacBook-Pro" } },
  34. "filter" : { "range" : { "@timestamp" : { "from" : "now-5m" } } }
  35. }
  36. },
  37. "aggs" : {
  38. "topn" : {
  39. "terms" : {
  40. "field" : "path.raw"
  41. }
  42. }
  43. }
  44. }
  45. }
  46. }
  47. },
  48. "actions" : {
  49. "email_admin" : {
  50. "throttle_period" : "15m",
  51. "email" : {
  52. "to" : "admin@domain",
  53. "subject" : "Found {{payload.hits.total}} Error Events",
  54. "priority" : "high",
  55. "body" : "Top10 paths:\n{{#payload.aggregations.topn.buckets}}\t{{key}} {{doc_count}}\n{{/payload.aggregations.topn.buckets}}"
  56. }
  57. }
  58. }
  59. }'

我们可以看到,跟原版的相比,只改动了很小的一些地方:

  1. 为了简便,interval 固定写数值,没带 s/m/d/H 之类的单位;
  2. condition 里直接使用了 JavaScript,这点也是 ES 2.x 的 mapping 要求跟 watcher 本身有冲突的一个地方:watcher的 "ctx.payload.hits.total" : { "gt" : 0 } 这种写法,如果是普通索引,会因为字段名里带 . 直接写入失败的;
  3. 因为是在 Kibana 里面运行,所以从 ES 拿到的只有 payload(也就是查询响应),所以把里面的 ctx. 都删掉了。

好,然后创建插件:

  1. cd kibana-4.3.0-darwin-x64/src/plugins
  2. mkdir alert

在自定义插件目录底下创建 package.json 描述:

  1. {
  2. "name": "alert",
  3. "version": "0.0.1"
  4. }

以及最终的 index.js 代码:

  1. 'use strict';
  2. module.exports = function (kibana) {
  3. var later = require('later');
  4. var _ = require('lodash');
  5. var mustache = require('mustache');
  6. return new kibana.Plugin({
  7. init: function init(server) {
  8. var client = server.plugins.elasticsearch.client;
  9. var sched = later.parse.text('every 10 minute');
  10. later.setInterval(doalert, sched);
  11. function doalert() {
  12. getCount().then(function(resp){
  13. getWatcher(resp.count).then(function(resp){
  14. _.each(resp.hits.hits, function(hit){
  15. var watch = hit._source;
  16. var every = watch.trigger.schedule.interval;
  17. var watchSched = later.parse.recur().every(every).second();
  18. var wt = later.setInterval(watching, watchSched);
  19. function watching() {
  20. var request = watch.input.search.request;
  21. var condition = watch.condition.script.script;
  22. var transform = watch.transform.search.request;
  23. var actions = watch.actions;
  24. client.search(request).then(function(payload){
  25. var ret = eval(condition);
  26. if (ret) {
  27. client.search(transform).then(function(payload) {
  28. _.each(_.values(actions), function(action){
  29. if(_.has(action, 'email')) {
  30. var subject = mustache.render(action.email.subject, {"payload":payload});
  31. var body = mustache.render(action.email.body, {"payload":payload});
  32. console.log(subject, body);
  33. }
  34. });
  35. });
  36. }
  37. });
  38. }
  39. });
  40. });
  41. });
  42. }
  43. function getCount() {
  44. return client.count({
  45. index:'watcher',
  46. type:"watch"
  47. });
  48. }
  49. function getWatcher(count) {
  50. return client.search({
  51. index:'watcher',
  52. type:"watch",
  53. size:count
  54. });
  55. }
  56. }
  57. });
  58. };

其中用到了两个 npm 模块,later 模块用来实现定时器和 crontab 文本解析,mustache 模块用来渲染邮件内容模板,这也是 watcher 本身采用的渲染模块。

需要安装一下:

  1. npm install later
  2. npm install mustache

然后运行 ./bin/kibana,就可以看到终端上除了原有的内容以外,还会定期输出 alert 的 email 内容了。

要点解释

这个极简示例中,主要有两段:

  1. 注册为插件
  1. module.exports = function (kibana) {
  2. return new kibana.Plugin({
  3. init: function init(server) {

注意上一节的可视化插件,这块是:

  1. module.exports = function (kibana) {
  2. return new kibana.Plugin({
  3. uiExports: {
  4. visTypes: [
  1. 引用 ES client
  1. init: function init(server) {
  2. var client = server.plugins.elasticsearch.client;

这里通过调用 server.plugins 来直接引用 Kibana 里其他插件里的对象。这样,alert 插件就可以跟其他功能共用同一个 ES client,免去单独配置自己的 ES 设置项和新开网络连接的资源消耗。

本节代码后续优化改进,见:https://github.com/chenryn/kaae。项目中还附带有一个 spy 式插件,有兴趣的读者可以继续学习 spy 这类不太常见的插件扩展的用法。