Writing Kibana Plugins – Custom applications
在閱讀本教程之前,您需要閱讀第1部分 - 基礎知識。
本部分教程系列介紹了Kibana中定制應用程序的創建。一個應用程序是插件中的一個可能的組件,它在Kibana平台內部有自己完整的部分,可以放置任何你想要的東西。Kibana只是提供你一個鏈接到這個部分,你可以隨你的感覺設計。其中一個很好的例子是Elastic的timelion插件。
在本教程中,我們將構建一個非常簡單的Elasticsearch狀態頁面應用程序。它將只列出所有索引,單擊一個將帶您到有關該索引的統計信息的頁面。您可以在下面的動畫中看到最終結果。
在本教程中,我們將學習:
- 如何創建應用程序插件的基本結構
- 如何從elasticsearch 正確地與插件進行通信
- 如何在應用程序中創建多個子頁面並在它們之間進行導航
完整插件的源代碼可以在GitHub上找到。這個插件我用了很多ECMAScript 2015 Syntax。Kibana使用Webpack將您的插件文件捆綁在一起,所以您可以安全地使用ECMAScript 2015,它將被Kibana折疊到ES 5 JavaScript。
GitHub源碼:https://github.com/timroes/elasticsearch_status
New Kibana 5 design
你可能已經注意到,上面Kibana的設計可能看起來很少見(但是)。這是Kibana 5的新UI,尚未發布。教程中的所有內容也適用於Kibana 4,我將在本教程中展示與插件開發相關的舊設計與新設計之間的差異。
Creating the basic structure
我們已經看到了本系列前幾部分的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對象內,您可以指定應用程序鍵,該鍵本身也是描述應用程序的對象。
title
鍵是此應用程序的可讀名稱。這是在Kibana的側欄中顯示的(或在Kibana 5之前的應用程序菜單中的圖標下方)。description是對應用程序的描述。這個目前不在任何地方使用。
main鍵是您的應用程序的主要javascript的必須字符串。它將始終以plugins/<your plugin id>/開頭,后跟插件中public文件夾中JavaScript的名稱。例如在上面的示例中,您的插件中應該有一個public / app.js文件,而package.json中的plugin id應該是elasticsearch_status。
icon鍵是指此應用程序的圖標。這將顯示在側面導航中的名稱旁邊(或應用程序菜單中的Kibana 5之前)。它又是一個將被解決的字符串,與上述相同。
您可以為應用程序指定幾個其他鍵,上面沒有顯示。你可以將hidden設置為true,如果您不希望應用程序顯示在導航中(例如,Kibana狀態頁面是這樣的應用程序)。
Creating a new Server API
如果要從應用程序查詢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){...}的一個快捷方式。
傳遞給該方法的server對象實際上是一個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 / <some index name here>接口(也沒有做任何事情)。handler 程序方法將獲得兩個參數:第一個是已經創建的請求。您可以從此處的請求中訪問很多(例如,使用req.params.name,您將獲得在URL中傳遞的索引的名稱)。第二個參數是回復函數。您必須調用此函數並將其應該返回的數據傳遞給調用此API的客戶端。
有關完整的文檔,請查看路由方法的官方hapi文檔。
Querying Elasticsearch
現在我們需要某種方式實際上從處理程序方法中查詢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的響應解決的承諾。在解析函數中,我們將從響應(在我們的例子中為索引統計)提取我們需要的數據,並返回它(通過回復方法)。
如果您正在開發Kibana 5.2,在本博客中概述的callWithRequest的使用會有輕微的變化。
這樣我們創建了我們的第一個Kibana服務器API,現在可以調用它了。如果您注意GitHub的源代碼,您將注意到,我提取API以生成另一個模塊,並且從init方法中調用此方法。我建議這樣做,以保持你的代碼可讀 - 如果你有很多創建的API,你甚至可能想要在多個模塊中使用它們。
第二個服務器API(用於獲取所有索引的列表)可以在源代碼中找到。我不會在這篇博文中詳細介紹,因為我們已經涵蓋了所有主題,你可以自己寫。
Creating the frontend
最后但並非最不重要的是,我們應該為應用程序創建實際的前端。我們之前已經將index.js中的特定app.js注冊為主文件。現在是創建它的時間了,並填寫一些內容。
import 'ui/autoload/styles'; import './less/main.less';
如果您使用Kibana 5,則第一行很重要,您應該始終將其放在應用程序插件中。這將使Kibana加載其通常具有的所有樣式。如果您不導入(或要求,如果您喜歡ES5語法)此模塊,您的應用程序周圍的Kibana框架將在用戶進入應用程序時看起來像壞的。如果您使用Kibana 4,此文件不存在,您無法導入(這讓我們回到第一篇文章中的巨大警告,關於缺少穩定的公共API)。
第二行是可選的,並顯示如何為您的應用程序插入自己的LESS樣式。您只需導入您的LESS文件。您也可以使用SASS替代。我建議使用相對路徑,這些文件也在您的公共文件夾,所以你不需要一遍又一遍重復你的插件ID。
Creating routing options
Kibana使用AngularJS'ngRouter在頁面之間進行路由。如果您的應用程序想要使用路由,則必須明確啟用它,並在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和其它的調用,就像你從$ routeProvider中使用的一樣。在這種情況下,我們要配置兩條路由:一個是基本路徑,一個是/ index /:name路徑,該名稱是索引名稱的占位符。可以通過使用上面的import語句將實際的html文件(在我們的例子中都放置在模板文件中)設置為兩個路由的模板。我們還使用兩個控制器,我們還沒有寫。
所以我們僅僅使用全局Angular模塊注冊正在運行的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的核心服務,負責應用中的所有Angular模塊。如果要獲取或創建一個,請使用其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 5之前,您仍然可以獲得標題欄,並可以通過服務進行修改:
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>' });
有更多的方法來創建制表符等。但是當您開發應用程序組件時,請記住,這些內容在Kibana 5(截至今天)中已經消失,您的應用程序可能無法使用,因為您缺少依賴的選項卡導航。
What’s next?
通過這個非常簡單的應用程序組件,我們覆蓋了您構建自己的awesome應用程序組件插件所需的大量API。所以現在由你來構建下一個timelion。
原文地址:https://www.timroes.de/2016/02/21/writing-kibana-plugins-custom-applications/