kibana官方沒有插件的開發教程,Tim Rose的教程寫的十分詳盡,也是官方推薦的。因爲這個系列的教程是英文版的,且基於kibana4,近日須要作kibana的開發,硬啃下這些教程以後,雖然這些教程比較古老,不少代碼不能用了,可是開發思想仍是通用的。記錄下來,留下個爪。因爲本人水平有限,錯漏的地方歡迎你們指出。html
原文連接:www.timroes.de/writing-kib…前端
原文標題Writing Kibana Plugins – Custom applicationsgit
你須要先讀前面基礎部分第一篇教程,才能開始本章節的學習。github
本教程系列介紹了Kibana中如何建立一個自定義應用程序。一個插件能夠包含一個應用程序,它是Kibana平臺內部的一個獨立的部分,能夠放置任何你想展現的東西。Kibana只是給你提供了一個連接到這個部分,你能夠爲所欲爲的設計這個插件。衆所周知的例子就是Elastic 的timelion插件,他就是一個app插件。chrome
在本教程中,咱們將構建一個很是簡單的Elasticsearch狀態頁面app。它列出全部索引,單擊一個將帶您到有關該索引的信息頁面。您能夠在下面的動畫中看到這個效果。json
在本教程中,咱們將學習:api
完整插件的源代碼能夠在GitHub上找到。這個插件我用了不少ECMAScript 2015 語法。Kibana使用Webpack打包插件文件並編譯成es5語法,因此您能夠放心地使用ECMAScript 2015數組
你能夠在GitHubGitHub中找到完整的代碼promise
或許你已經注意到了,上面看到的kibana的頁面你可能目前並不熟悉,這是kibana5的新的UI設計,到目前爲止尚未發佈,這個教程的代碼時兼容kibana4的,對於kibana4和kibana5之間的,跟開發插件相關的差別,我會指出來的。(譯者:這個已經。。。。)瀏覽器
之前的教程中咱們看到了index.js的結構。要註冊一個新的插件,您可使用uiExport對象的app屬性,以下所示:
export default function (kibana) {
return new kibana.Plugin({
require: ['elasticsearch'],
uiExports: {
app: {
title: 'Indices',
description: 'An awesome Kibana plugin',
main: 'plugins/elasticsearch_status/app',
icon: 'plugins/elasticsearch_status/icon.svg'
}
}
});
複製代碼
在require中,咱們能夠引用其餘的模塊。常見的值是kibana和elasticsearch。指定這些模塊由於kibana是在加載完這些模塊後加載咱們的插件,保證了引用的模塊加載成功。咱們在這裏引用了elasticsearch模塊,由於咱們在後面要使用elasticsearch的數據。 在uiExports中的app屬性,是一個對象,是來描述這個插件信息的。
public/app.js
文件,在package.json
文件中,插件的id應該是elasticsearch_status
還有其餘的一些參數,好比你若是不想讓插件顯示在導航中,能夠添加參數hidden:true。(kibana 的狀態頁面就是這樣。)
若是要從插件中查詢Elasticsearch,那麼最好的解決方案就是,給Kibana服務器建立一個新的API。你插件中調用這個API,它會爲你查詢Elasticsearch。
爲何不直接從您的插件中查詢Elasticsearch?固然,您也可使用Elasticsearch JavaScript客戶端直接從您的前端查詢ES。但這些調用將在用戶的瀏覽器中執行,從而致使CORS(交叉原始資源共享)問題。最好的解決方案是使用Kibana服務器。
所以,如上所述,咱們的插件將會獲取全部索引的列表,而且須要檢索特定索引的狀態。
咱們來看看第二個接口。
要向Kibana添加新的服務器API,使用init方法能夠指定:
// ...
return new kibana.Plugin({
// ...
init(server, options) {
// Initialization goes here
}
});
複製代碼
若是你不熟悉這個JavaScript語法,這只是一個快捷寫法,你也能夠寫init: function(server, options) {…}。
傳遞給該方法的服務器對象其實是一個hapiJS服務器對象。您能夠按以下方式建立新接口:
// inside your init method:
server.route({
path: '/api/elasticsearch_status/index/{name}',
method: 'GET',
handler(req, reply) {
// more to come here in the next step
reply("Hello World");
}
});
複製代碼
這樣,您能夠在Kibana服務器上建立一個新的GET API。你如今能夠調用該/api/elasticsearch_status/index/index名稱
接口(如今也沒有作任何事情)。處理程序方法將得到兩個參數:第一個是已經建立的請求。您能夠今後處的請求中訪問不少信息(例如,使用req.params.name,你將獲取在URL中傳遞的索引的名稱)。第二個參數是回覆函數。您必須調用此函數並將其應該返回的數據傳遞給調用此API的客戶端。
有關完整的文檔,請查看官方hapi文檔的路由方法。
如今咱們在處理函數中,需實際處理查詢Elasticsearch以相關索引的數據。有一個實用方法來調用Elasticsearch,咱們可使用。這個方法也是咱們爲何要在index.js中,要引入elasticsearch
模塊。如下代碼應放在咱們API的處理函數:
server.plugins.elasticsearch.callWithRequest(req, 'cluster.state', {
metric: 'metadata',
index: req.params.name
}).then(function (response) {
reply(response.metadata.indices[req.params.name]);
});
複製代碼
咱們須要將API中的請求,做爲第一個參數傳遞給該callWithRequest方法。這種方法在Kibana服務器的調用和Elasticsearch的調用之間進行傳遞身份認證。第二個參數是咱們要調用的Elasticsearch JavaScript客戶端的函數的名稱- 在咱們的例子中,咱們要調用該cluster.state()方法,而且咱們要將索引的名稱(從請求參數讀出)傳遞給方法。
該方法返回一個Elasticsearch的響應的promise。在resolve函數中,咱們將從響應中提取咱們須要的數據(在咱們的例子中是索引stats),並返回它(經過該reply方法)。
若是你的開發工做是基於Kibana 5.2以上的,callWithRequest的使用會有輕微的變化,這個博客中有概述。
咱們建立了一個Kibana服務器API,如今能夠調用它了。若是您注意GitHub的源代碼,您將注意到,我將API生成提取到另外一個模塊,而且從init方法中調用此方法。我建議這樣作,以保持你的代碼可讀性 - 若是你有不少API你建立,你甚至可能想要使用多個模塊。
第二個服務器API(用於獲取全部索引的列表)能夠在源代碼中找到。我不會在這篇博文中詳細介紹,由於咱們已經涵蓋了全部主題,你能夠本身寫。
咱們應該爲咱們的插件建立一個前端。咱們以前已經在index.js
中註冊了一個app.js做爲主文件。如今是來寫他們的時候了。
咱們將插入文件的前兩行以下:
import 'ui/autoload/styles';
import './less/main.less';
複製代碼
若是您使用 Kibana 5,則第一行很重要,您應該始終將其放在插件中。這將使插件加載Kibana經常使用的全部樣式。若是您不導入此模塊,您的應用程序會和kibana框架看起來格格不入。若是您使用Kibana 4,此文件不存在,您沒法導入(這讓咱們回到第一篇文章中的巨大警告,關於缺乏穩定的公共API)。
第二行是可選的,是app插入本身的LESS樣式的例子。您只需導入您的LESS文件。您也可使用SASS。我建議使用相對路徑,由於這些文件也在您的public件夾,因此你每次都在路徑上寫上你的插件ID。
Kibana使用AngularJS的ngRouter在頁面之間進行路由。若是您的app想要使用路由,則必須明確啓用它,並在app.js文件中配置一些路由:
import uiRoutes from 'ui/routes';
import overviewTemplate from './templates/index.html';
import detailTemplate from './templates/detail.html';
uiRoutes.enable();
uiRoutes
.when('/', {
template: overviewTemplate,
controller: 'elasticsearchStatusController',
controllerAs: 'ctrl'
})
.when('/index/:name', {
template: detailTemplate,
controller: 'elasticsearchDetailController',
controllerAs: 'ctrl'
});
複製代碼
若是須要使用路由,必須調用uiRoutes.enable()。以後,您可使用when和otherwise調用,就像您使用$routeProvider。在這種狀況下,咱們要配置兩個路由:一個用於基本路徑,一個用於路徑/index/:name,name是索引名稱的佔位符。能夠經過使用上面的import語句,將實際的html文件(這文件放在templates文件夾中)引入,並設置兩個路由的模板。咱們還使用兩個控制器,咱們尚未寫。
下面咱們寫控制器,咱們使用Kibana的全局模塊註冊模塊:
import uiModules from 'ui/modules';
uiModules
.get('app/elasticsearch_status')
.controller('elasticsearchStatusController', function ($http) {
$http.get('../api/elasticsearch_status/indices').then((response) => {
this.indices = response.data;
});
});
複製代碼
uiModules是Kibana的核心服務,負責處理應用中的全部模塊。若是要獲取或建立一個,請使用其get方法。第一個參數是要獲取或建立的模塊的名稱。若是模塊已經存在則把存在的模塊返回,若是沒有建立它,返回該模塊。第二個參數能夠是一個模塊數組,放置模塊的依賴。若是模塊已經存在,那麼這些模塊在返回以前,將被添加到模塊的依賴關係列表中。這些模塊不存在,只需將它們添加到新建立的模塊中便可。
此行爲與angular.module方法不一樣,你建立模塊,並指定依賴關係和獲取依賴時,和不傳遞第二個參數時,都能發現。使用這個服務,Kibana也會負責處理加載咱們的Angular模塊。
上面的控制器使用$http服務,來從咱們的接口獲取索引列表,並將其存儲在控制器中。
最後一個須要補充的部分如今,是咱們的模板templates/index.html:
<div class="container">
<div class="row">
<div class="col-12-sm">
<h1>Elasticsearch Status</h1>
<ul class="indexList">
<li ng-repeat="index in ctrl.indices">
<a href="#/index/{{index}}">{{ index }}</a>
</li>
</ul>
</div>
</div>
</div>
複製代碼
咱們的教程中的HTML保持至關簡單。咱們只是ng-repeat用來迭代,從API中檢索全部的索引,並連接到它們。此外,咱們使用一些Bootstrap的CSS類來設計咱們的內容。詳細頁面的HTML能夠在GitHub的源代碼中找到。
在Kibana 5開始,Kibana將只提供給你側邊的導航欄連接,如上面的動圖所示。一旦你被切換到你的插件,kibana沒有提供標題欄或其餘的東西。若是你想要其餘樣式佈局,你將要本身在app中去建立它。在Kibana5以前,您仍然能夠得到一些bar,並能夠經過服務進行修改:
import chrome from 'ui/chrome';
chrome
.setNavBackground('#FF00FF') // Turns the navbar in beautiful pink
.setBrand({
logo: '<CSS background property value for the logo>',
smallLogo: '<CSS background property value a smaller version>'
});
複製代碼
還有其餘的一些方法來建立tabs,等。可是當你建立一個app的時候,要記住這些東西在kibana5的時候會被幹掉。那麼你的app可能就不可用了,由於你所依賴的tabs導航已經不可用了。
從這個很是簡單的app中,你已經學到了不少有用的api了,足夠去建立一個很是棒的自定義app了,因此下一個timelion app就由你來建立啦。