原文地址:http://www.elasticsearch.org/blog/kibana-custom-field-formatters

Kibana 4.1 引入了一个新特性叫字段展示格式(field formatters),让我们可以实时转换字段内容成更形象的样式。这个特性帮助我们不修改数据的存储方式,而用另一种方式显示它。有关 field formatters 的介绍,可以阅读之前一篇博客

本文的目的,则是带大家过一遍 field formatters 的开发流程。从 field formatter 接口开始,自己实现一个基础的 formatter,可以字段给 error 单词加高亮效果,最后完成整个解决方案。

起步

Kibana 开发环境的搭建介绍可以在 Kibana repository 看到。

从 Kibana 根目录触发,field formatters 相关代码存在 /src/ui/public/stringify 目录下。目录结构如下所示:

/stringify
|–type //包括各种 formatter
|–icons
|–editors //formatter 用来请求和显示附加信息的 HTML 页面
|–tests
|–register.js //每个 formatter 都要在这里面注册

Kibana 4.1 里,formatters 位置则在 /src/kibana/components/stringify。如果你是看的 4.1 版,可能跟本文讲的路径稍有区别,请自动对应查找一下,本文以 git master 为准。

现在,让我们在 type 目录 下创建一个文件叫 Highlight.js,下面是初始代码:

define(function (require) {
  return function HighlightFormatProvider(Private) {
    var _ = require('lodash');
    var FieldFormat = Private(require('ui/index_patterns/_field_format/FieldFormat'));
    _.class(Highlight).inherits(FieldFormat);
    function Highlight(params) {
      Highlight.Super.call(this, params);
    }
    Highlight.id = 'highlight';
    Highlight.title = 'Highlight';
    Highlight.fieldType = ['string'];
    Highlight.prototype._convert = {
      text: _.escape,
      html: _.escape
    };
    return Highlight;
  };
});

每种字段格式,都实现为扩展 FieldFormat 的类。Highlight.id 用在 Kibana 内部跟踪 formatter,每个 formatter 必须采用不同的 id。Highlight.title 显示在 formatter 下拉选择框里,Highlight.fieldType 则描述自己适用于哪种类型的字段内容。

Highlight.prototype._convert 是实际进行格式化的地方。包括有 text 和 html 两种方法。text 方法用于 tooltips, filters, legends, 和 axis markers。html 方法用于搜索表格内。两者都接收字段内容为输入,输出我们希望的展示内容。如果两个方法是一样的,可以直接赋值 Highlight.prototype._convert 为一个函数。给 error 单词加高亮的代码如下:

Highlight.prototype._highlight = function (val, replace) {
  return _.escape(val).replace(/(error)/g, replace);
};
Highlight.prototype._convert = {
  text: function(val) {
    return this._highlight(val, function convertToUpperCase(match) {
      return match.toUpperCase();
    });
  },
  html: function(val) {
    return this._highlight(val, '<mark>$&</mark>');
  }
};

只要字段内容中有 error 文本字样,我们就会根据 HTML 或者 text 场景选择包含进 mark 元素或者是转换成大写形式。注意这里使用的 _.escape(val) 语句,这句可以用来放置 HTML 注入和跨站脚本攻击。

然后需要注册这个新的 field formatter。在 register.js 里添加:

fieldFormats.register(require('ui/stringify/types/Highlight'));

未来,我们(Kibana 开发组)可能会把这个功能以插件形式提供,届时注册方法会更加简单。

现在我们可以对 string 类型的字段选择 Highlight 作为 field formatter 了!

在 Discover 页测试效果:

更通用化

插件已经可以运行了,但是我们如果想更通用化一点,不单单可以用来高亮 error 字眼呢?当然不用给每个单词开发一种 formatter,我们可以提供一个输入正则表达式的方式。

在 editor 目录,添加一个叫 highlight.html 的文件,内容如下:

<div class="form-group">
  <label>Pattern</label>
  <input class="form-control" ng-model="editor.formatParams.pattern"/>
</div>

然后回到 Highlight.js 里,我们需要定义 highlight.html 作为我们的编辑页面,然后更新我们的 _highlight 方法,使用输入文本作为匹配时的正则表达式。

Highlight.editor = require('ui/stringify/editors/highlight.html');
Highlight.prototype._highlight = function (val, replace) {
  var escapedVal = _.escape(val);
  var highlightPattern;
  try {
    var inputRegex = this.param('pattern').split('/');
    var pattern = inputRegex[0] || inputRegex[1];
    var flags = inputRegex[2];
    highlightPattern = new RegExp(pattern, flags);
  } catch(e) {
    return escapedVal;
  }
  return escapedVal.replace(highlightPattern, replace);
};

示例

如果在应用 formatter 之前,就能看到输入的正则表达式的效果就更好了。Kibana 里提供了一个 directive 指令让我们可以在修改表达式时观察示例变化。

我们可以增加一些输入字段,并且在模板中加入这个指令。也就是在 highlight.html 后面追加下面这段:

<field-format-editor-samples inputs="editor.field.format.type.sampleInputs"></field-format-editor-samples>

对应的,在 Highlight.js 里添加下面这段:

Highlight.sampleInputs = [
  'Hello world',
  'The quick brown fox jumps over the lazy dog',
  '112345'
];

最终结果如下:

结论

field formatter 接口提供了非常简便的办法让我们定制字段内容的展示方式。Kibana 自带了好几种 formatter,不过如果你没发现比较合适的,你可以随时自己开发添加一个。如果你已经开始计划添加了,也请注意在 Kibana 4.2 发版的时候,回来看看,有没有新的接口变更。