国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

使用Java編寫一個簡單的Web的監控系統

2019-11-26 14:50:48
字體:
來源:轉載
供稿:網友

公司的服務器需要實時監控,而且當用戶空間已經滿了,操作失敗,或者出現程序Exception的時候就需要實時提醒,便于網管和程序員調式,這樣就把這個實時監控系統分為了兩部分,
 
第一部分:實時系統監控(cpu利用率,cpu溫度,總內存大小,已使用內存大小)
第二部分:實時告警
由于無刷新實時性,所以只能使用Ajax,這里沒有用到任何ajax框架,因為調用比較簡單
大家知道,由于java的先天不足,對底層系統的調用和操作一般用jni來完成,特別是cpu溫度,你在window下是打死用命令行是得不到的, 但由于我們的服務器系統是linux,所以可以不調用jni完全用java的方式來得到系統信息,這里用到了runtime的exec()函數,通過解析 本地命令調用的結果來查詢本地信息,

* 取得linux系統下的cpu、內存信息  *  * */  public  final  class LinuxSystemTool  {  /**  * get memory by used info  *  * @return int[] result  * result.length==4;int[0]=MemTotal;int[1]=MemFree;int[2]=SwapTotal;int[3]=SwapFree;  * @throws IOException  * @throws InterruptedException  */  public  static  int [] getMemInfo() throws IOException, InterruptedException  {  File file = new File( "/proc/meminfo" );  BufferedReader br = new BufferedReader( new InputStreamReader(  new FileInputStream(file)));  int [] result = new  int [ 4 ];  String str = null ;  StringTokenizer token = null ;  while ((str = br.readLine()) != null )  {  token = new StringTokenizer(str);  if (!token.hasMoreTokens())  continue ;   str = token.nextToken();  if (!token.hasMoreTokens())  continue ;   if (str.equalsIgnoreCase( "MemTotal:" ))  result[0 ] = Integer.parseInt(token.nextToken());  else  if (str.equalsIgnoreCase( "MemFree:" ))  result[1 ] = Integer.parseInt(token.nextToken());  else  if (str.equalsIgnoreCase( "SwapTotal:" ))  result[2 ] = Integer.parseInt(token.nextToken());  else  if (str.equalsIgnoreCase( "SwapFree:" ))  result[3 ] = Integer.parseInt(token.nextToken());  }   return result;  }   /**  * get memory by used info  *  * @return float efficiency  * @throws IOException  * @throws InterruptedException  */  public  static  float getCpuInfo() throws IOException, InterruptedException  {  File file = new File( "/proc/stat" );  BufferedReader br = new BufferedReader( new InputStreamReader(  new FileInputStream(file)));  StringTokenizer token = new StringTokenizer(br.readLine());  token.nextToken();  int user1 = Integer.parseInt(token.nextToken());  int nice1 = Integer.parseInt(token.nextToken());  int sys1 = Integer.parseInt(token.nextToken());  int idle1 = Integer.parseInt(token.nextToken());   Thread.sleep(1000 );   br = new BufferedReader(  new InputStreamReader( new FileInputStream(file)));  token = new StringTokenizer(br.readLine());  token.nextToken();  int user2 = Integer.parseInt(token.nextToken());  int nice2 = Integer.parseInt(token.nextToken());  int sys2 = Integer.parseInt(token.nextToken());  int idle2 = Integer.parseInt(token.nextToken());   return ( float )((user2 + sys2 + nice2) - (user1 + sys1 + nice1)) / ( float )((user2 + nice2 + sys2 + idle2) - (user1 + nice1 + sys1 + idle1));  }  }  

 
這里的兩個方法,解釋一下,
方法1文件"/proc/meminfo"里面包含的就是內存的信息,還包括了swap的信息。例如:

$ cat /proc/meminfo total: used: free: shared: buffers: cached: Mem: 1057009664 851668992 205340672 0 67616768 367820800 Swap: 2146787328 164429824 1982357504 MemTotal: 1032236 kB MemFree: 200528 kB MemShared: 0 kB 

這樣可以用截取字符串的方法,來得到linux內存信息.
方法2在文件"/proc/stat"里面就包含了CPU的信息。每一個CPU的每一tick用在什么地方都在這個文件里面記著。后面的數字含義分 別是: user、nice、sys、idle、iowait。有些版本的kernel沒有iowait這一項。這些數值表示從開機到現在,CPU的每tick用 在了哪里。例如:

cpu0 256279030 0 11832528 1637168262 

就是cpu0從開機到現在有 256279030 tick用在了user消耗,11832528用在了sys消耗。所以如果想計算單位時間(例如1s)里面CPU的負載,那只需要計算1秒前后數值的差除以每一秒的tick數量就可以了。
ok這樣還剩下cpu溫度,怎么做呢
發現了一個文件"cat /proc/acpi/thermal_zone/THM/temperature";可以返回本機的linux溫度,
大概是這樣的:

temperature:      68C

但不是每臺linux機器都有這個THM你要確定你的linux加載了這個THM才能使用這個文件,這樣就用InputStreamReader(new FileInputStream(new File("/proc/acpi/thermal_zone/THM/temperature")), 去讀取這個文件,后面的相信大家一定會做了吧,就是把內容讀出來,然后分割字符串去得到這個68。ok,系統基本信息全部完成,然后ok現在就只有一件事就是用Ajax去調用這個類來得到 基本信息,然后返回到頁面上,Ajax的用法就不贅言了。
 
下面是系統監控的效果,大概是Ajax每幾秒去linux下去取一次系統信息,然后顯示在jsp頁面上,以下是效果。

20151117154830520.png (450×204)

到這里第一部分系統監控部分已經完成,現在開始完成實時告警部分,分析需求
1溫度和cpu超過額定值需要告警
2用戶操作系統失敗,用戶存儲空間不足也需要告警,還有我們公司的業務操作失敗告警,如果發生Exception也只能告警,當然要把異常的堆棧的 信息保存在數據庫里,我就這樣設計如果用戶在操作中觸發了這些錯誤,則保存在數據庫的告警表里,然后實時監控的再取出來這些信息。
3告警是要實時的那么要怎么從告警表里查到當前以后的數據呢,一開始想到用當前時間,在當前時間加上Ajax發送時間間隔,select * from warnlist where date>new Date()+AjaxTime這種形式,后來發現時間是很不正確的,網絡延遲,程序處理時間,(cpu信息用了sleep函數),等等你常常會發現有些 告警信息被無情的放過,而有的時候有重復數據,這樣我想到了用id,每次進入告警系統先查詢到最大的告警id,然后保存在session中,然后ajax 從數據庫里取告警信息的時候都查這個id之后的數據(就是進入監控系統后的最新數據),然后session再保存新的最大id,下次ajax取還是從這個 session中取最大id,這樣信息就可以當ajax取的時候都保證是最新的,而且沒有重復,very good!就這樣做了
這樣設計了一張告警處理表

CREATE  TABLE `warnlist` (  `Id` bigint (20) NOT  NULL auto_increment,  `warnleave` tinyint(2) NOT  NULL  default  '0' ,//告警級別:告警的嚴重程度  `fromguy` varchar (20) NOT  NULL ,//屬于哪個用戶哪個組織的告警  `warncontent` varchar (100) NOT  NULL ,//告警內容,比如cpu使用率超過80%  `aviliablevalue` varchar (12) default  NULL ,//允許值 比如85%  `warnvalue` varchar (12) default  NULL ,//告警值 80  `warntime` datetime NOT  NULL ,//告警時間  `stackinfo` varchar (255) default  NULL ,//異常的堆棧信息  `dealwith` tinyint(2) NOT  NULL  default  '0' ,//處理結果  `version` int (11) default  NULL ,//version  `organizerID` varchar (20) default  NULL ,//組織id  `des` varchar (255) default  NULL ,  PRIMARY  KEY  (`Id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

 
假設我ajax從系統取信息后,那么要寫個邏輯,if(cpuTempature>75C)or if(cpuUserd>80%)則寫入數據庫,然后再查詢大于上一次發送Ajax數據庫的最大id的告警信息(這期間如果發生的以下錯誤一并查 出:用戶存儲空間不足,還有我們公司的業務操作失敗告警,Exception等),循環插入一個xml解析類中,大概形式是這樣的Ajax返回這個 xml,供頁面提取信息

< response >  < cpuUsed > 67 </ cpuUsed >  < cpuTemp > 76 < cpuTemp >  < Memory > 1023422 </ Memory >  < freeMemory > 43244 </ freeMemory >  < wannlist >  < warnid > 2 </ warnid >  < warncontent > 系統存儲空間不足 </ warncontent >  < fromguy > kakaluyi </ fromguy >  .............. </ wanrlist >  < warnlist >  < warnid > 3 </ warnid >  < warncontent > cpu溫度過高 </ warncontent >  < fromguy > 系統 </ fromguy >  < orgid > 系統 </ orgid >  < warnvalue > 78 </ warnvalue >  ............. </ warnlist >  ........  </ response >  

 
系統信息的顯示代碼,就是關聯上面那個圖片的:

var cpuUsed = req .responseXML.getElementsByTagName('cpuUsed')[0].firstChild.nodeValue; var totalMemory = req .responseXML.getElementsByTagName('totalMemory')[0].firstChild.nodeValue; var freeMemory = req .responseXML.getElementsByTagName('freeMemory')[0].firstChild.nodeValue; var cpuTemp = req .responseXML.getElementsByTagName('cpuTemp')[0].firstChild.nodeValue; $('cpuUsed').innerHTML = cpuUsed ; $('totalMemory').innerHTML = totalMemory ; $('freeMemory').innerHTML = freeMemory ; $('cpuTemp').innerHTML = cpuTemp ;  //jsp < tr >  < td  class = "label"  width = "20%" >  

服務器CPU使用率:

</ td >  < td  class = "text" >  < font  color = "#FF0000"  size = "+2" > < label  id = "cpuUsed" > </ label >  </ font >  < 告警預定閥值: 80% >  </ td >  </ tr >   ......... 

然后就是頁面展現的問題了這里我用了dom節點的增刪,一個頁面保持50條記錄,如果超過50條則刪除以前的節點,代碼為:
 

var length=req.responseXML.getElementsByTagName( 'warnlist' ).length; if (length>0) { var trlength=document.getElementsByTagName( 'table' )[4].childNodes[0].childNodes.length;  if (trlength+length-1>50) //如果大于50條,則查找告警列表的table,得到  告警信息的子節點,然后刪除多余的最早的告警信息 { var tbody=document.getElementsByTagName( 'table' )[4].childNodes[0]; for ( var i=1;i<trlength+length-50;i++) { var tr=tbody.childNodes[i]; tr.parentNode.removeChild(tr);  } 

 
然后插入新的告警信息,

for ( var i=0;i<length;i++) { var onewarnlist=req.responseXML.getElementsByTagName( 'warnlist' )[i].childNodes; if (onewarnlist[0].firstChild.nodeValue==0) { var leave= "企業級告警" ; } else { var leave= "運營商級告警" ; } var from=onewarnlist[1].firstChild.nodeValue; var warncontent=onewarnlist[2].firstChild.nodeValue; var aviliablevalue=onewarnlist[3].firstChild.nodeValue; var warnvalue=onewarnlist[4].firstChild.nodeValue; var warntime=onewarnlist[5].firstChild.nodeValue; var id=onewarnlist[8].firstChild.nodeValue; if (onewarnlist[6].firstChild.nodeValue==0) { var dealwith= "未處理" ; } else { var dealwith= "<font color='red'>已處理</font>" ; } var table=document.getElementById( 'warntable' ); var tr=document.createElement( 'tr' );  if (x%2==1) { tr.style.backgroundColor="#BFD3F9"  } else { tr.style.backgroundColor="#FBFCEB"  } x++; table.appendChild(tr); var td=document.createElement( 'td' ); td.className ='listText' ; td.innerHTML =x; tr.appendChild(td); var td1=document.createElement( 'td' ); td1.className ='listText' ; td1.innerHTML = leave; tr.appendChild(td1); var td2=document.createElement( 'td' ); td2.className ='listText' ; td2.innerHTML = from; tr.appendChild(td2); var td3=document.createElement( 'td' ); td3.className ='listText' ; td3.innerHTML = warncontent; tr.appendChild(td3);6 var td4=document.createElement( 'td' ); td4.className ='listText' ; td4.innerHTML = aviliablevalue; tr.appendChild(td4); var td5=document.createElement( 'td' ); td5.className ='listText' ; td5.innerHTML = '<font color="#FF0000">' +warnvalue+ '</font>' ; tr.appendChild(td5); var td6=document.createElement( 'td' ); td6.className ='listText' ; td6.innerHTML = warntime; tr.appendChild(td6); var td7=document.createElement( 'td' ); td7.className ='listText' ; td7.innerHTML = dealwith; tr.appendChild(td7); var td8=document.createElement( 'td' ); td8.className ='listText' ; td8.innerHTML = id; tr.appendChild(td8);   } 

 
ok,一切大功告成,以下是最終效果

20151117155058639.png (762×343)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 全州县| 隆安县| 拜城县| 通州市| 和田市| 五莲县| 仙桃市| 南开区| 镇平县| 桃园县| 葵青区| 石嘴山市| 林口县| 招远市| 莒南县| 木兰县| 中西区| 桑植县| 响水县| 南皮县| 台东县| 黄冈市| 巩留县| 博白县| 忻州市| 慈利县| 晋宁县| 桐庐县| 永嘉县| 滦平县| 清流县| 蒙自县| 昌宁县| 北碚区| 贞丰县| 靖远县| 江山市| 汕尾市| 大宁县| 昆明市| 云安县|