java实现对服务器的自动巡检邮件通知
程序员文章站
2024-03-31 13:12:46
1、需求
之前一直是手动的巡检,然后贴图,最近服务器数量大增,有点忙不过来了。因为一直用的java,对shell脚本不是特别了解,所以这次用java写了个小项目,实现...
1、需求
之前一直是手动的巡检,然后贴图,最近服务器数量大增,有点忙不过来了。因为一直用的java,对shell脚本不是特别了解,所以这次用java写了个小项目,实现对多服务器,多任务的巡检,巡检结果有故障的会通过邮件通知。
2、功能和效果
巡检的项目主要是服务,硬盘,内存等,命令可配置,巡检结果以日期和服务器为基准输出文件,错误信息通过邮件通知管理运维人员。
3、代码
action:
package com.save.action; import java.text.simpledateformat; import java.util.arraylist; import java.util.date; import java.util.hashset; import java.util.iterator; import java.util.list; import java.util.map; import java.util.set; import java.util.regex.matcher; import java.util.regex.pattern; import org.apache.commons.lang3.stringutils; import org.slf4j.logger; import org.slf4j.loggerfactory; import com.alibaba.fastjson.json; import com.save.pojo.cmd; import com.save.until.mailutil; import com.save.until.propertiesutil; import com.save.until.sshcommutil; import com.save.until.writeuntil; /** * 巡检任务 * @author zhangzhuo * */ public class inspaction { final static logger logger = loggerfactory.getlogger(inspaction.class); /* public static void main(string[] args) { inspaction n = new inspaction(); try { n.execute(); } catch (exception e) { // todo auto-generated catch block e.printstacktrace(); logger.error("dd"); } }*/ /** * 执行巡检任务 * @param args */ public void execute() throws exception{ list<cmd> list = this.handlerdata(); set<string> mail = new hashset<string>(); for (cmd cmd : list) { string ip = cmd.getip(); int port = 22; string localip = null; int localport = 0; int timeout = 6000; string username = cmd.getusername(); string password = cmd.getpassword(); string server = cmd.getserver(); string[] cmds = cmd.getcmds(); string[] result = null; logger.info(ip+"执行巡检任务开始"); try { result = sshcommutil.execshellcmdbyssh(ip, port, localip, localport, timeout, username, password, cmds); } catch (exception e) { e.printstacktrace(); logger.error(ip+"巡检,服务器连接不上"); mail.add(ip+" "+"巡检,服务器连接不上"); } date date = new date(); simpledateformat formatter = new simpledateformat("yyyy/mm/dd"); string datestring = formatter.format(date); //1、服务存活验证 2、硬盘占用验证 3、巡检结果写入文件 if (result != null) { for (string string : result) { if (string.contains("ps -ef|grep java")||string.contains("ps -ef|grep mongo")||string.contains("ps -ef|grep redis")) { if (!string.contains(server)) { mail.add(ip+" "+server+"服务不存在"); } } if (string.contains("df -h")) { string patt = "^[5]\\d{1}\\%|[5-9]\\d{1}\\%|\\d{3,}\\%$"; string group = null; pattern p = pattern.compile(patt); matcher m = p.matcher(string); while (m.find()) { group = m.group(); } if (!stringutils.isblank(group)) { mail.add(ip+" "+"硬盘占用超出预警线"); } } writeuntil.createfile("e:\\save", datestring, "\\"+ip+".txt", string); } logger.info(ip+"巡检结束"); } } //发送故障邮件通知 if (!mail.isempty()||mail.size()!=0) { mailutil.getinstance().sendmail(mail); } } /** * 数据处理 * @return */ private list<cmd> handlerdata(){ logger.info("开始加载需要巡检的服务器数据"); cmd cmd = null; list<cmd> list = new arraylist<cmd>(); map map = propertiesutil.getinstance().getallproperty(); iterator<map.entry<string, string>> it = map.entryset().iterator(); while (it.hasnext()) { map.entry<string, string> entry = it.next(); cmd =new cmd(); cmd.setip(entry.getkey()); cmd cmd2 = json.parseobject(entry.getvalue(), cmd.class); string[] cmds = cmd2.getshell().split(","); cmd.setcmds(cmds); cmd.setserver(cmd2.getserver()); cmd.setusername(cmd2.getusername()); cmd.setpassword(cmd2.getpassword()); list.add(cmd); } logger.info("数据加载完毕"); return list; } }
pojo:
package com.save.pojo; public class cmd { private string ip; private string username; private string password; private string shell; private string[] cmds; private string server; public string getserver() { return server; } public void setserver(string server) { this.server = server; } public string getshell() { return shell; } public void setshell(string shell) { this.shell = shell; } public string getip() { return ip; } public void setip(string ip) { this.ip = ip; } public string getusername() { return username; } public void setusername(string username) { this.username = username; } public string getpassword() { return password; } public void setpassword(string password) { this.password = password; } public string[] getcmds() { return cmds; } public void setcmds(string[] cmds) { this.cmds = cmds; } }
工具类:
package com.save.until; import java.io.ioexception; import java.io.inputstream; import java.io.outputstream; import java.net.inetaddress; import java.net.inetsocketaddress; import java.net.socket; import java.net.unknownhostexception; import java.util.properties; import org.slf4j.logger; import org.slf4j.loggerfactory; import com.jcraft.jsch.jsch; import com.jcraft.jsch.jschexception; import com.jcraft.jsch.session; import com.jcraft.jsch.socketfactory; /** * ssh创建与服务器连接工具类 * @author 张卓 * 2017-4-21 */ public class jschutil { final static logger logger = loggerfactory.getlogger(jschutil.class); private static jsch jsch = new jsch(); /** * 创建session,并打开session连接 * */ public static session createsession(string dstip, int dstport, final string localip, final int localport, string username, string password, final int timeout) throws jschexception { //jsch.setknownhosts("/home/foo/.ssh/known_hosts"); logger.info("开始连接:"+dstip); // 建立一个ssh连接 session session = jsch.getsession(username, dstip, dstport); session.setpassword(password); properties sshconfig = new properties(); sshconfig.put("stricthostkeychecking", "no");//跳过主机检查 session.setconfig(sshconfig); // 此socket工厂用于创建目标主机的socket, // 并创建我们使用的这个socket字节流 session.setsocketfactory(new socketfactory() { public outputstream getoutputstream(socket socket) throws ioexception { return socket.getoutputstream(); } public inputstream getinputstream(socket socket) throws ioexception { return socket.getinputstream(); } public socket createsocket(string host, int port) throws ioexception, unknownhostexception { socket socket = new socket(); if (localip != null) { socket.bind(new inetsocketaddress(inetaddress .getbyname(localip), localport)); } socket.connect( new inetsocketaddress(inetaddress.getbyname(host), port), timeout); return socket; } }); session.connect(timeout); return session; } }
package com.save.until; import java.util.properties; import java.util.set; import javax.mail.authenticator; import javax.mail.message; import javax.mail.passwordauthentication; import javax.mail.session; import javax.mail.transport; import javax.mail.internet.internetaddress; import javax.mail.internet.mimemessage; import org.slf4j.logger; import org.slf4j.loggerfactory; import com.sun.mail.util.mailsslsocketfactory; /** * 邮件发送 * @author zhangzhuo * */ public class mailutil { final static logger logger = loggerfactory.getlogger(mailutil.class); private static mailutil instance = new mailutil(); private mailutil (){} public static mailutil getinstance() { return instance; } public void sendmail(set<string> mail) { string from = "xxx@qq.com";// 发件人电子邮箱 string host = "smtp.qq.com"; // 指定发送邮件的主机smtp.qq.com(qq)|smtp.163.com(网易) properties properties =new properties(); properties.setproperty("mail.smtp.host", host);// 设置邮件服务器 properties.setproperty("mail.smtp.auth", "true");// 打开认证 try { //qq邮箱需要下面这段代码,163邮箱不需要 mailsslsocketfactory sf = new mailsslsocketfactory(); sf.settrustallhosts(true); properties.put("mail.smtp.ssl.enable", "true"); properties.put("mail.smtp.ssl.socketfactory", sf); // 1.获取默认session对象 session session = session.getdefaultinstance(properties, new authenticator() { public passwordauthentication getpasswordauthentication() { return new passwordauthentication("xxx@qq.com", "xxx"); // 发件人邮箱账号、授权码 } }); // 2.创建邮件对象 message message = new mimemessage(session); message.setfrom(new internetaddress(from)); message.addrecipient(message.recipienttype.to, new internetaddress("xxx@qq.com")); message.setsubject("巡检故障通知"); stringbuffer sb = new stringbuffer(); for (string string : mail) { sb.append("<div>"+string+"</div><br/><hr/>"); } string content = sb.tostring(); message.setcontent(content, "text/html;charset=utf-8"); transport.send(message); logger.info("故障邮件发送成功"); } catch (exception e) { e.printstacktrace(); } } }
package com.save.until; import java.io.file; import java.io.fileoutputstream; import java.io.inputstream; import java.io.inputstreamreader; import java.io.outputstream; import java.net.uri; import java.util.enumeration; import java.util.hashmap; import java.util.map; import java.util.properties; /** * 读取文件工具类 * @author zhangzhuo * */ public class propertiesutil { private properties props; private uri uri; private static propertiesutil ourinstance = new propertiesutil("/config.properties"); public static propertiesutil getinstance() { return ourinstance; } public propertiesutil(string filename){ readproperties(filename); } private void readproperties(string filename) { try { props = new properties(); inputstream fis =getclass().getresourceasstream(filename); inputstreamreader re=new inputstreamreader(fis,"utf-8"); props.load(re); } catch (exception e) { e.printstacktrace(); } } /** * 获取某个属性 */ public string getproperty(string key){ return props.getproperty(key); } /** * 获取所有属性,返回一个map,不常用 * 可以试试props.putall(t) */ public map getallproperty(){ map map=new hashmap(); enumeration enu = props.propertynames(); while (enu.hasmoreelements()) { string key = (string) enu.nextelement(); string value = props.getproperty(key); map.put(key, value); } return map; } /** * 在控制台上打印出所有属性,调试时用。 */ public void printproperties(){ props.list(system.out); } /** * 写入properties信息 */ public void writeproperties(string key, string value) { try { outputstream fos = new fileoutputstream(new file(uri)); props.setproperty(key, value); // 将此 properties 表中的属性列表(键和元素对)写入输出流 props.store(fos, "『comments』update key:" + key); } catch (exception e) { e.printstacktrace(); } } }
package com.save.until; import java.io.ioexception; import java.io.inputstream; import java.io.outputstream; import org.slf4j.logger; import org.slf4j.loggerfactory; import com.jcraft.jsch.channel; import com.jcraft.jsch.jschexception; import com.jcraft.jsch.session; /** * 执行shell工具类 * @author zhangzhuo * */ public class sshcommutil { final static logger logger = loggerfactory.getlogger(sshcommutil.class); /** * shh连接linux shell,返回结果 */ public static string[] execshellcmdbyssh(string dstip, int dstport, string localip, int localport, int timeout, string username, string password, string... cmds) throws exception { session session = null; channel channel = null; inputstream is = null; outputstream os = null; try { session = jschutil.createsession(dstip, dstport, localip, localport, username, password, timeout); logger.info("开始创建channel通道!"); //创建一个channel类型的通道 channel = session.openchannel("shell"); // enable agent-forwarding. // ((channelshell)channel).setagentforwarding(true); // choose the pty-type "vt102". // ((channelshell)channel).setptytype("vt102"); // set environment variable "lang" as "ja_jp.eucjp". // ((channelshell)channel).setenv("lang", "ja_jp.eucjp"); channel.connect(); is = channel.getinputstream(); os = channel.getoutputstream(); string[] result = new string[cmds.length]; for (int i = 0; i < cmds.length; i++) { result[i] = sendcommand(is, os, cmds[i]); } return result; } catch (jschexception e) { if (e.getmessage().contains("auth fail")) { logger.error(dstip+"服务器验证失败"); throw new exception("auth error"); } else { logger.error(dstip+"服务器连接失败"); throw new exception("connect error"); } } catch (exception e) { throw e; } finally { try { is.close(); } catch (ioexception e) { } try { os.close(); } catch (ioexception e) { } channel.disconnect(); session.disconnect(); } } /** *执行shell脚本并返回结果 * */ private static string sendcommand(inputstream is, outputstream os, string cmd) throws ioexception { logger.info("开始执行脚本!"); os.write(cmd.getbytes()); os.flush(); stringbuffer sb = new stringbuffer(); int beat = 0; while (true) { if (beat > 3) { break; } if (is.available() > 0) { byte[] b = new byte[is.available()]; is.read(b); sb.append(new string(b)); beat = 0; } else { if (sb.length() > 0) { beat++; } try { thread.sleep(sb.tostring().trim().length() == 0 ? 1000 : 300); } catch (interruptedexception e) { } } } return sb.tostring(); } }
package com.save.until; import java.io.bufferedreader; import java.io.ioexception; import java.io.inputstream; import java.io.inputstreamreader; import java.util.arraylist; import java.util.list; import com.jcraft.jsch.channelexec; import com.jcraft.jsch.jsch; import com.jcraft.jsch.jschexception; import com.jcraft.jsch.session; /** * ssh工具类 * */ public class sshexcutecommandhelper { session session = null; channelexec openchannel = null; /** * @param host 主机ip * @param name 用户名 * @param pwd 密码 * @param port ssh端口 */ public sshexcutecommandhelper(string host, string user, string pwd, int port) { jsch jsch = new jsch(); try { session = jsch.getsession(user, host, port); java.util.properties config = new java.util.properties(); config.put("stricthostkeychecking", "no"); session.settimeout(1000); session.setconfig(config); session.setpassword(pwd); } catch (jschexception e) { e.printstacktrace(); } } /** * 是否连接成功,调用如果不需要调用execcommand方法那么必须调用 disconnect方法关闭session * @return */ public boolean canconnection(){ try { session.connect(); return true; } catch (jschexception e) { e.printstacktrace(); return false; } } /** * 关闭连接 */ public void disconnect(){ if (openchannel != null && !openchannel.isclosed()) { openchannel.disconnect(); } if (session != null && session.isconnected()) { session.disconnect(); } } /** * 执行命令 * @param command * @return */ public string execcommand(string command) { stringbuffer result = new stringbuffer(); try { if(!session.isconnected()){ session.connect(); } openchannel = (channelexec) session.openchannel("exec"); openchannel.setcommand(command); //int exitstatus = openchannel.getexitstatus(); openchannel.connect(); inputstream in = openchannel.getinputstream(); bufferedreader reader = new bufferedreader( new inputstreamreader(in)); string tmpstr = ""; while ((tmpstr = reader.readline()) != null) { result.append(new string(tmpstr.getbytes("gbk"), "utf-8")).append("\n"); } } catch (exception e) { e.printstacktrace(); result.append(e.getmessage()); } finally { disconnect(); } return result.tostring(); } /** * 解析 * @param result * @return */ public list<list<string>> parseresult(string result){ list<list<string>> parseresult = new arraylist<list<string>>(); list<string> list = null; // for (string line : result.split("\n")) { list = new arraylist<string>(); string[] columns = {}; //这个是针对df命令的 [mounted on] 其实就一个,如果用空格就会分割出两个 if(line.contains("mounted ")){ columns = line.replace("mounted ", "mounted-").split(" "); }else{ columns = line.split(" "); } for (string column : columns) { if (!" ".equals(column) && !"".equals(column)) { list.add(column); } } parseresult.add(list); } return parseresult; } //测试 /* public static void main(string args[]) { sshexcutecommandhelper execute = new sshexcutecommandhelper("192.168.175.128", "root", "123456", 22); system.out.println("是否连接成功"+execute.canconnection()); string s = execute.execcommand("free -m"); system.out.println("解析前"); system.out.println(s); system.out.println("解析后"); list<list<string>> parseresult = execute.parseresult(s); for (list<string> l : parseresult) { system.out.println(l); } }*/ }
package com.save.until; import java.io.file; import java.io.fileoutputstream; import java.io.ioexception; import java.io.inputstream; import java.text.simpledateformat; import java.util.date; import org.slf4j.logger; import org.slf4j.loggerfactory; import com.save.action.inspaction; /** * * @author zhangzhuo * */ public class writeuntil { final static logger logger = loggerfactory.getlogger(writeuntil.class); /** * 新建文件夹,并创建文件写入数据 */ public static void createfile(string basepath,string filepath, string filename, string input) { string[] dirs = filepath.split("/"); string temppath = basepath; for (string dir : dirs) { if (null == dir || "".equals(dir)) continue; temppath += "\\" + dir; } //文件夹判断 file dir = new file(temppath);//"d:\\test_dir" if (dir.exists()) { if (dir.isdirectory()) { logger.info("文件夹存在"); } else { logger.info("同名文件存在,无法创建目录"); } } else { logger.info("文件夹不存在,开始创建"); dir.mkdirs(); } //文件判断 file file = new file(temppath+filename);//"d:\\test_file.txt" if (file.exists()) { logger.info(filename+"已存在"); } else { logger.info(filename+"文件不存在,开始创建"); try { file.createnewfile(); } catch (ioexception e) { e.printstacktrace(); } } //写入数据 //方法一、每次写入覆盖之前的 /* try { fileoutputstream fos = new fileoutputstream(temppath+filename); fos.write(input.getbytes()); fos.close(); } catch (exception e) { e.printstacktrace(); }*/ try { fileoutputstream fos = new fileoutputstream(temppath+filename, true); fos.write(input.getbytes()); fos.close(); } catch (exception e) { // todo auto-generated catch block e.printstacktrace(); } } //测试 /* public static void main(string[] args) { //createfile("e:\\log", "2014/16/2/", "\\2020.txt", "hahha"); date date = new date(); simpledateformat formatter = new simpledateformat("yyyy/mm/dd"); string datestring = formatter.format(date); system.out.println(datestring); }*/ }
applicationcontext.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- 配置作业类 --> <bean id="inspaction" class="org.springframework.scheduling.quartz.methodinvokingjobdetailfactorybean"> <property name="targetobject"> <bean class="com.save.action.inspaction" /> </property> <property name="targetmethod" value="execute" /> <property name="concurrent" value="false" /><!-- 作业不并发调度 --> </bean> <!-- 配置触发器 --> <bean id="crontrigger" class="org.springframework.scheduling.quartz.crontriggerbean"> <property name="jobdetail" ref="inspaction" /> <!-- 每天7:00运行一次 --> <property name="cronexpression" value="0 0 07 * * ?" /> </bean> <!-- 配置调度工厂 --> <bean class="org.springframework.scheduling.quartz.schedulerfactorybean"> <property name="triggers"> <list> <ref bean="crontrigger" /> </list> </property> </bean> </beans>
config.properties
#测试用服务器 192.168.175.128={"username":"root","password":"123456","shell":"ps -ef|grep mongo\n,df -h\n, free -m\n, top\n","server":"mongod"} 192.168.175.129={"username":"root","password":"123456","shell":"ps -ef|grep redis\n,df -h\n, free -m\n, top\n","server":"mongod"} log4j.properties
#指定根logger,及日志输出级别 #大于等于该级别的日志将被输出( debug < info < warn < error < fatal ),设为off可以关闭日志 log4j.rootlogger=info, a1,a2 #指定log输出目的,这里设为输出日志到指定目录的文件my.log中 log4j.appender.a1=org.apache.log4j.fileappender log4j.appender.a1.file=e:\\save\\log\\xj.log #指定日志信息的格式 log4j.appender.a1.layout=org.apache.log4j.patternlayout log4j.appender.a1.layout.conversionpattern=%r %d{yyyy-mm-dd hh:mm:ss} %c %p -%m%n #把a2输出到控制台 log4j.appender.a2=org.apache.log4j.consoleappender log4j.appender.a2.layout=org.apache.log4j.patternlayout log4j.appender.a2.layout.conversionpattern=%d{yyyy-mm-dd hh:mm:ss} %c %p -%m%n
pom.xml:
<project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelversion>4.0.0</modelversion> <groupid>com.save</groupid> <artifactid>save-xj</artifactid> <packaging>war</packaging> <version>0.0.1-snapshot</version> <name>save-xj maven webapp</name> <url>http://maven.apache.org</url> <dependencies> <!-- ssh连接 --> <dependency> <groupid>com.jcraft</groupid> <artifactid>jsch</artifactid> <version>0.1.53</version> </dependency> <!-- json转换 --> <dependency> <groupid>com.alibaba</groupid> <artifactid>fastjson</artifactid> <version>1.2.31</version> </dependency> <!-- spring的包 --> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-context</artifactid> <version>3.1.1.release</version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-context-support</artifactid> <version>3.1.1.release</version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-tx</artifactid> <version>3.1.1.release</version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-web</artifactid> <version>3.0.5.release</version> </dependency> <!-- 定时任务 --> <dependency> <groupid>org.quartz-scheduler</groupid> <artifactid>quartz</artifactid> <version>1.8.5</version> </dependency> <!-- 日志的包 --> <dependency> <groupid>log4j</groupid> <artifactid>log4j</artifactid> <version>1.2.17</version> </dependency> <dependency> <groupid>org.slf4j</groupid> <artifactid>slf4j-log4j12</artifactid> <version>1.7.21</version> </dependency> <!-- 邮件 --> <dependency> <groupid>com.sun.mail</groupid> <artifactid>javax.mail</artifactid> <version>1.4.4</version> </dependency> <dependency> <groupid>javax.mail</groupid> <artifactid>mail</artifactid> <version>1.4</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupid>org.apache.commons</groupid> <artifactid>commons-lang3</artifactid> <version>3.4</version> </dependency> </dependencies> <build> <plugins> <!-- 配置tomcat插件 --> <plugin> <groupid>org.apache.tomcat.maven</groupid> <artifactid>tomcat7-maven-plugin</artifactid> <version>2.2</version> <configuration> <port>8080</port> <path>/</path> </configuration> </plugin> </plugins> </build> </project>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: java实现构造无限层级树形菜单