ZabbixAPIとJavaScriptを使って簡単なグラフ表示UIを作ってみました。
『ホストグループ』→『ホスト』と選択すればいくつかのグラフが表示されます。
なぜこんなことをしてみたかというと、「Zabbixの標準UIはグラフの一覧性が低いと思うから」です。
ドロップダウンメニューで1つずつ進んでいくのではなく、チェックボックスや検索機能を使いたかった。
これに関してはぜんぜんいけそうだなという印象です。
グラフの描画にはGoogleChartAPIを使いました。
作っておいてなんですが、自分でグラフ書くのはやめておいたほうがいいです。
APIではヒストリ(短期間保存の詳細情報)は取れるがトレンド(長期間保存のサマリ情報)が取れないからです。
Zabbix本体のグラフ画像URLを動的に生成したほうがいいです。
このあたり踏まえてまた改良版を作ってみたいと思います。
今回の実装について
参考にした資料を挙げておきます
・まずは本家ドキュメント
これがないと何もできません
・@kodai74さんの資料
jQueryを使った基本的なAPIの叩き方が紹介されてます(28~29ページ)
・@sechiroさんのブログ
APIの動作確認用に任意のAPIを叩くページを作っておくと便利です
今回のHTML&JavaScriptのソースです。
普段全然書かないので汚くてすみません。
細かいことでもツッコミ大歓迎です!
HTML
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Zabbix API Demo</title> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></script> <script type="text/javascript" src="zabbix_api.js"></script> </head> <body> <form id="hostgroup"> <legend>Host Group</legend> <div id="hostgrouplist"></div> <input id="hostgroupbtn" type='button'>Select</input> </form> <form id="host"> <legend>Host</legend> <div id="hostlist"></div> <input id="hostbtn" type='button'>Select</input> </form> <div id="graph"></div> </body> </html>
var authid; //表示するグラフ //typeはitemのvalue_typeに合わせる。0:float,3:??? var graphs = [ {label:'LA5' , filter:{key_:'system.cpu.load[,avg5]'}, type:0}, {label:'Mem Avail', filter:{key_:'vm.memory.size[available]'}, type:3}, ]; function getValues(arr, key){ return $.map(arr, function(obj){ return obj[key]; }); } function callAPI(method, params, async, success, error) { var url = 'http://192.168.1.10/zabbix/api_jsonrpc.php'; //環境に合わせる var sendData = { jsonrpc: '2.0', id: 1, auth: authid, method: method, params: params, } $.ajax({ url: url, contentType: 'application/json-rpc', dataType: 'json', type: 'POST', processData: false, data: JSON.stringify(sendData), async: async, success: success, error: error, }); }; function getAPIResponse(method, params, async, callback){ callAPI(method, params, async, function(response){ if(response['error']){ alert("API Error:" + JSON.stringify(response)); }else{ callback(response['result']); } }, function(response){ alert("Connect Error:" + JSON.stringify(response)); } ); } function authAPI() { var user = 'admin'; //adminとか絶対やめましょうね!!! var password = 'zabbix'; // authid = null; getAPIResponse( 'user.authenticate', {"user":user, "password":password}, false, function(result){ authid = result; } ); } function initHostGroup(){ getAPIResponse( 'hostgroup.get', {output: "extend"}, true, function(hostgroups){ $.each(hostgroups, function(idx, obj){ $('#hostgrouplist') .append($('<input></input>').attr({type:'checkbox', value:obj.groupid})) .append($('<label></label>').text(obj.name)); if((idx+1) % 5 == 0){$('#hostgrouplist').append($('<br/>'));} }); } ); }; function updateHost(){ $('#hostlist').empty(); var groupids = $('#hostgrouplist>input:checked').map(function(){ return $(this).val(); }).get(); getAPIResponse( 'host.get', {groupids:groupids, output:"extend", sortfield:"host"}, true, function(hosts){ $.each(hosts, function(idx, h){ $('#hostlist') .append($('<input></input>') .attr({type:'checkbox', name:h.host, value:h.hostid})) .append($('<label></label>').text(h.host)) .append($('<br/>')); }); } ); } function updateGraph(){ var hosts = []; var now = parseInt((new Date)/1000); $('#hostlist>input:checked').each(function(){ hosts.push({name:this.name, id:this.value}); }); $('#graph').empty(); for(var i in hosts){ for(var j in graphs){ $('#graph').append($('<img/>').attr('id', "graph-"+i+"-"+j)); if(j == graphs.length - 1){ $('#graph').append($('<br/>')); } } } for(var i in hosts){ host = hosts[i]; for(var j in graphs){ graph = graphs[j]; getAPIResponse( 'item.get', {hostids:[host.id], filter:graph.filter}, false, function(result){ itemid = result[0].itemid; getAPIResponse( 'history.get', { history: graph.type, itemids: [itemid], output: "extend", time_from: now - 86400, time_till: now, limit: 288 }, false, function(result){ $("#graph-"+i+"-"+j).attr('src', createChartURL( host.name +":"+ graph.label,getValues(result, 'value'))); } ); } ); } } } function createChartURL(label, data){ max = Math.ceil(Math.max.apply(null, data)); for(i in data){ data[i] = parseInt(data[i] * 100 / max); } var url = "http://chart.apis.google.com/chart" + "?cht=lc" + "&chs=300x180" + "&chtt=" + label + "&chxt=y" + "&chxr=0,0," + max + "&chd=t:" + data.join(); return url; } $(document).ready(function(){ $('#hostgroupbtn').click(updateHost); $('#hostbtn').click(updateGraph); authAPI(); initHostGroup(); });
CallBack祭りで読みづらい!!!
そしてグラフ更新のところを非同期にすると挙動がおかしくなる。
JavaScript難しいなぁ