打造自己的Linux服務器監控小工具
周末在家蠻無聊的,思考人生的同時突發奇想就寫一個服務器監控的小工具吧。學JAVA快1年了,剛好檢驗一下自己!
仔細想想呢估計作用可能也有限,畢竟外面各種監控工具也很多,初衷其實也只是練練手,加上平時比較懶,那么為了更方便的看服務器性能指標,所以就選了這個題材咯,那么就開始吧。
不過優點也是有的嘛,至少不需要在服務器端裝一個腳本之類的了。
一、小工具的功能
1 能夠讀取服務器CPU,IO,Memory的性能指標并在頁面展示出來
2 把監控的信息打印到文件,方便進行數據分析
二、準備工作
java開發環境、JDK1.7+、 Eclipse
maven環境
git
三、使用到的框架
前臺:
JS的FLOT框架
后臺:
SpringMVC框架
工作流程圖(其實蠻簡單的)
項目結構目錄
四、實現代碼
主要的功能類
1 LinuxService 提供服務器指令輸入的服務入口
2 LinuxConnectionPool 把服務器連接對象保存起來,每一次獲得請求時會先檢查連接是否在池子中存在,有的話直接用,沒有的話就創建一個新的
3 LinuxConnection 服務器連接對象,負責創建connection
4 LinuxSessionHandle 負責創建session并執行CMD指令最后銷毀session
5 EntityBaseUtil 提供了把Linux返回的結果轉換成比較適合裝入實體類的方法String Transfer ListString[]
代碼
1 LinuxService
package com.sunfan.monitor.service; import java.io.IOException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.sunfan.monitor.manager.pool.LinuxConnectionPool; import com.sunfan.monitor.platform.IConnectable; import com.sunfan.monitor.platform.linux.LinuxSessionHandle; /** * * @author sunfan * */ @Component public class LinuxService { private String defaultTopComand = "top -b -n 1"; private String defaultMpstatComand = "mpstat -P ALL"; private String defaultFreeCommand = "free -m"; private String defaultIostatCommand = "iostat -d -m"; @Autowired private LinuxConnectionPool pool ; @Autowired private LinuxSessionHandle handle; /** * execute default command "top -b -n 1" and return String type reslut * * @param url server's ip * @param user login name * @param password login password * @return * @throws IOException */ public String topMonitor(String url,String user,String password) throws IOException{ return this.executeCommand(url, user, password, defaultTopComand); } /** * execute default command "mpstat -P ALL" to get cpus performance * * @param url * @param user * @param password * @return * @throws IOException */ public String cpuMonitor(String url,String user,String password) throws IOException{ return this.executeCommand(url, user, password, defaultMpstatComand); } /** * execute default command "free -m" to get memory performance * @param url * @param user * @param password * @return * @throws IOException */ public String memoryMonitor(String url,String user,String password) throws IOException{ return this.executeCommand(url, user, password, defaultFreeCommand); } /** * execute default command "free -m" to get memory performance * @param url * @param user * @param password * @return * @throws IOException */ public String inputOutputMonitor(String url,String user,String password) throws IOException{ return this.executeCommand(url, user, password, defaultIostatCommand); } public String executeCommand(String url,String user,String password,String command) throws IOException{ IConnectable lc = pool.borrowObject(url,user,password); return handle.executeCommand(lc.getConnection(),command); } } |
2 LinuxConnectionPool
package com.sunfan.monitor.manager.pool; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.sunfan.monitor.manager.IConnectionPool; import com.sunfan.monitor.platform.IConnectable; import com.sunfan.monitor.platform.linux.LinuxConnection; /** * * @author sunfan * */ @Component public class LinuxConnectionPool implements IConnectionPool { private Logger logger = LoggerFactory.getLogger(getClass()); private Map<String, IConnectable> connectionPool = new HashMap<String, IConnectable>(); /** * save connecion in the connectionPool,if conn is already exist return * false else return true * * @param conn * @return */ public synchronized Boolean saveObject(IConnectable conn) { String key = rewardConnectionKey(conn); if (isExist(key)) { logger.info("this key{} has already exist", key); return false; } connectionPool.put(key, conn); return true; } /** * borrow connection object in the connect-pool * * @param key * @return */ public IConnectable borrowObject(String key) { if (!isExist(key)) { throw new IllegalArgumentException("key not found:" + key); } return connectionPool.get(key); } public IConnectable borrowObject(String url,String user,String password){ String key = this.rewardConnectionKey(url, user, password); if (!isExist(key)){ try { LinuxConnection connect = new LinuxConnection(url, user, password); connectionPool.put(key, connect); return connect; } catch (IOException e) { throw new RuntimeException("connection error"+url,e); } }else { return connectionPool.get(key); } } /** * borrow connection object in the connect-pool if the connection hasn't in * the connectionPool return null,else return connect object * * @param conn * @return */ public IConnectable borrowObject(IConnectable conn) { String key = rewardConnectionKey(conn); return borrowObject(key); } /** * close single connection in the connection-pool and close/release of this * connection * * @param conn * @throws IOException */ public void remove(IConnectable conn) throws IOException { String key = rewardConnectionKey(conn); remove(key); } /** * close single connection in the connection-pool and close/release of this * connection * * @param conn * @throws IOException */ public synchronized void remove(String key) throws IOException { if (!isExist(key)) { throw new IllegalArgumentException(key + "is not exist"); } connectionPool.get(key).close(); connectionPool.remove(key); } /** * delete every connection in the connection-pool and also close/release of * all connection * * @throws IOException */ public void clear() throws IOException { for (String keyString : connectionPool.keySet()) { connectionPool.get(keyString).close(); } connectionPool.clear(); } /** * according to the connection to generate key if the connecion is not equal * null return url/usr/password * * @param conn * @return */ public String rewardConnectionKey(IConnectable conn) { return conn.getUrl() + "/" + conn.getUser() + "/" + conn.getPassword(); } public String rewardConnectionKey(String url, String user, String password) { return url + "/" + user + "/" + password; } /** * To confirm whether the connectionPool has this key if already has return * true else return false * * @param key * @return */ public Boolean isExist(String key) { return connectionPool.containsKey(key); } } |
3 LinuxConnection
package com.sunfan.monitor.platform.linux; import java.io.Closeable; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sunfan.monitor.platform.IConnectable; import com.trilead.ssh2.Connection; import com.trilead.ssh2.ConnectionInfo; /** * * @author sunfan * */ public class LinuxConnection implements IConnectable, Closeable { Logger log = LoggerFactory.getLogger(LinuxConnection.class); private String url, user, password; private Connection connection; /** * init server's connect * * @param url * @param user * @param password * @throws IOException */ public LinuxConnection(String url, String user, String password) throws IOException{ this.url = url; this.user = user; this.password = password; this.connection = createConnection(); } /** * this method will establish connection unless username or password * incorrect and remote server is not find * * @return connection * @throws IOException */ private Connection createConnection() throws IOException { connection = new Connection(url); ConnectionInfo info = connection.connect(); // establish connection if (false == connection.authenticateWithPassword(user, password)){ log.error("connect server failed,please check the username and password. " + this.user + " " + this.password); throw new IllegalArgumentException("connection remote server fail"); } return connection; } /** * close connection */ @Override public void close() throws IOException { if (connection != null) this.connection.close(); } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Connection getConnection() { return connection; } public void setConnection(Connection connection) { this.connection = connection; } } |
4 LinuxSessionHandle
package com.sunfan.monitor.platform.linux; import java.io.BufferedReader; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.sunfan.monitor.platform.IMonitorable; import com.trilead.ssh2.Connection; import com.trilead.ssh2.Session; import com.trilead.ssh2.StreamGobbler; /** * * @author sunfan * */ @Component public class LinuxSessionHandle implements IMonitorable,Closeable{ Logger logger = LoggerFactory.getLogger(LinuxSessionHandle.class); private Session session; /** * open session then execute commands on remote server and return the result of it * @param command * @return String * @throws IOException */ public synchronized String executeCommand(Connection conn,String command) throws IOException { String str=""; try { session = conn.openSession(); session.execCommand(command); str = this.read().toString(); } catch (Exception e) { session.ping(); throw new IOException("session exception",e); } finally{ close(); } return str; } /** * read the result of remote server execute commands * @return * @throws IOException */ private StringBuffer read() throws IOException{ InputStream stdout = new StreamGobbler(session.getStdout()); BufferedReader br = new BufferedReader(new InputStreamReader(stdout)); String tempString = null; // readLine()每次調用都默認會讀一行 StringBuffer str = new StringBuffer(); while ((tempString = br.readLine()) != null) { str.append(tempString+"\r\n"); } br.close(); return str; } /** * close session */ @Override public void close() throws IOException { if (this.session != null) this.session.close(); } } 5 EntityBaseUtil package com.sunfan.monitor.entity.util; import java.util.ArrayList; import java.util.List; /** * * @author sunfan * */ public class EntityBaseUtil { /**change String result to List<String> result by split "\r\n" * remove the content above flag * to transfer List<String> ---> list<String[]> by .split("\\s{1,}") * @param result * @param flag * @return */ public List<String[]> transferListofStringArray(String result,String flag){ List<String> resList = this.transferList(result); List<String> contentList = this.removeResultHead(resList,flag); return this.transferArrayOfList(contentList); } /** * change String result to List<String> result by split "\r\n" * @param result * @return List<String> */ public List<String> transferList(String result){ String[] strs = result.split("\r\n"); List<String> list = new ArrayList<String>(); for(String s:strs){ list.add(s); } return list; } /**remove the content above flag * * @return List<String> */ public List<String> removeResultHead(List<String> resultList,String flag){ List<String> contentList = new ArrayList<String>(); contentList.addAll(resultList); for(String res:resultList){ if(res.contains(flag)){ break; } contentList.remove(res); } return contentList; } /**to transfer List<String> ---> list<String[]> by .split("\\s{1,}") * * @param contentList * @return List<String[]> */ public List<String[]> transferArrayOfList(List<String> contentList){ List<String[]> contentLists =new ArrayList<>(); for(String content:contentList){ contentLists.add(content.split("\\s{1,}")); } return contentLists; } /**get result of reference by title * * @param head data of reference title * @param title reference title * @param infos data of each reference * @return String result of reference by title ,if title is not matched ,return " " */ public String resolveValueByTagName(List<String> head,String[] infos,String title){ if(head.indexOf(title)>0){ return infos[head.indexOf(title)]; } return ""; } } |
五、測試
這個小工具耗時2個周末終于搞定了,感謝大家的觀看,寫的不好或者欠缺考慮的地方請@我,謝謝各位老師。
如果喜歡請點一下推薦哦,謝謝!
源碼地址:https://github.com/sunfan1988/sunfan
六 將來的擴展
1 把日志功能完善
2 按照今后的需求把性能監控器逐個配置上去,基本上只要改一下controller和JSP頁面就可以了。
七、感謝幫助過我的人
1 感謝張少能、朱際華、陳淼杰等小伙伴在我開發這個小工具過程中的指點,真的學到了很多。
posted on 2014-07-21 10:18 順其自然EVO 閱讀(2123) 評論(0) 編輯 收藏 所屬分類: 測試學習專欄