wrong_sql_send.go
package main import ( _ "github.com/go-sql-driver/mysql" "database/sql" "fmt" "strconv" "gopkg.in/gomail.v2" "crypto/tls" "time" "github.com/tealeg/xlsx" "github.com/Unknwon/goconfig" "strings" "os" ) var now_time = time.Now() var yes_date = now_time.AddDate(0, 0, -1).Format("2006-01-02") //var attach_file_name = "wrong_sql_1_22_"+now_time.Format("20060102")+".xlsx" var mysql_info = get_config_data("mysql_info") var mail_group = get_config_data("mail_group") var send_subject = get_config_data("subject") var host_port = get_config_data("host_port") var limit_record_cnt = 50 /* const ( dbhostsip = "192.168.1.22" dbusername = "dmladmin" dbpassowrd = "dmladmin" dbname = "db_admin" ) */ func get_config_data(sec_name string)(map[string] string){ cfg, err := goconfig.LoadConfigFile("./config/config.ini") if err != nil{ panic("错误") return nil } sec, err := cfg.GetSection(sec_name) return sec } func SendMail(mailTo []string,subject string, body string,total_count int,attach_file_name string ) error { //定义邮箱服务器连接信息,如果是阿里邮箱 pass填密码,qq邮箱填授权码 var smtp_info = get_config_data("smtp") port, _ := strconv.Atoi(smtp_info["port"]) //转换端口类型为int m := gomail.NewMessage() m.SetHeader("From","yw" + "<" + smtp_info["user"] + ">") //这种方式可以添加别名,即“XD Game”, 也可以直接用<code>m.SetHeader("From",mailConn["user"])</code> 读者可以自行实验下效果 m.SetHeader("To", mailTo...) //发送给多个用户 m.SetHeader("Subject", subject) //设置邮件主题 m.SetBody("text/html", body) //设置邮件正文 if total_count > limit_record_cnt { m.Attach("./attach_file/" + attach_file_name) } d := gomail.NewDialer(smtp_info["host"], port, smtp_info["user"], smtp_info["pass"]) d.TLSConfig = &tls.Config{InsecureSkipVerify: true} err := d.DialAndSend(m) fmt.Println(err) return err } func get_excel_data(db_ip string,mysql_host_port string,attach_file_name string){ var file *xlsx.File var sheet *xlsx.Sheet var row *xlsx.Row var cell *xlsx.Cell var now_time = time.Now() var yes_date = now_time.AddDate(0, 0, -1).Format("2006-01-02") style := xlsx.NewStyle() fill := *xlsx.NewFill("solid", "F79646", "FF000000") font := *xlsx.NewFont(12, "Verdana") border := *xlsx.NewBorder("thin", "thin", "thin", "thin") var runsql_all = "select id, replace(replace(run_sql,' ',''),' ','') as run_sql,create_time from tb_wrong_run_sql where create_time>="+"'"+yes_date+"'" +" order by id" db, err := sql.Open("mysql", mysql_info["dbusername"]+":"+mysql_info["dbpassowrd"]+"@tcp("+db_ip+":"+mysql_host_port+")/"+mysql_info["dbname"]) if err != nil { fmt.Println("连接数据库失败:", err) } //使用DB的query方法遍历数据库数据 data_rows, err := db.Query(runsql_all) //获取完毕释放rows,阻止更多的列举 defer data_rows.Close() if err != nil { fmt.Println("获取错误:", err) } file = xlsx.NewFile() sheet, err = file.AddSheet("不符合规范查询") style.Fill = fill style.Font = font style.Border = border style.ApplyFill = true style.ApplyFont = true style.ApplyBorder = true row = sheet.AddRow() cell = row.AddCell() cell.Value = "ID" cell.SetStyle(style) cell = row.AddCell() cell.Value = "SQL" cell.SetStyle(style) cell = row.AddCell() cell.Value = "采集时间" cell.SetStyle(style) for data_rows.Next() { var id int var run_sql string var create_time string data_rows.Scan(&id, &run_sql, &create_time) row = sheet.AddRow() cell = row.AddCell() cell.Value = strconv.Itoa(id) cell = row.AddCell() cell.Value = run_sql cell = row.AddCell() cell.Value = create_time } err = file.Save("./attach_file/"+attach_file_name) if err != nil { fmt.Printf(err.Error()) } } func get_html_data(db_ip string,mysql_host_port string)(string,int) { //使用database/sql包中的Open连接数据库 var runsql_limit = "select id, replace(replace(run_sql,' ',''),' ','') as run_sql,create_time from tb_wrong_run_sql where create_time>="+"'"+yes_date+"'" +" order by id limit "+strconv.Itoa(limit_record_cnt) db, err := sql.Open("mysql", mysql_info["dbusername"]+":"+mysql_info["dbpassowrd"]+"@tcp("+db_ip+":"+mysql_host_port+")/"+mysql_info["dbname"]) if err != nil { fmt.Println("连接数据库失败:", err) return "error",-1 } //使用DB的query方法遍历数据库数据 rows, err := db.Query(runsql_limit) //获取完毕释放rows,阻止更多的列举 defer rows.Close() if err != nil { fmt.Println("获取错误:", err) return "error",-1 } //var title = `xx实例慢查询` var header = `<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head>` var i =0 //如果有数据记录Next指针就不为true var tr = "" for rows.Next() { var id int var run_sql string var create_time string rows.Scan(&id, &run_sql, &create_time) //fmt.Println(id, user, create_time, update_time) i++ var td = "" td = td + "<td>" + strconv.Itoa(id) + "</td>" td = td + "<td style=word-wrap:break-word;word-break:break-all;>" + run_sql + "</td>" td = td + "<td>" + create_time + "</td>" tr = tr + "<tr>" + td + "</tr>" } var body = tr //Err返回可能的、在迭代时出现的错误。Err需在显式或隐式调用Close方法后调用。 //err = rows.Err() var th = `<body text='#000000'><center><font size=5 color='#dd0000'><b> `+ `不符合规范查询数:` + strconv.Itoa(i) + `</b></font></center> <br/><table style=' font-size: 14px;' border='1' cellspacing='0' cellpadding='1' bordercolor='#000000' width='20%' align='center' ></table> <br/><table bgcolor='#B0E0E6' style=' font-size: 14px;'border='1' cellspacing='0' cellpadding='0' bordercolor='#000000' width='95%' align='center' > <tr bgcolor='#F79646' align='left' > <th>id</th> <th style=60px>SQL</th> <th style='50px'>采集时间</th> </tr>` var tail="" if (i >= limit_record_cnt) { tail= `</table><b><p>更多请查看附件!</p></b></body></html>` } else { tail= `</table></body></html>` } var mail = header + th + body + tail return mail,i } func get_total_count(db_ip string,mysql_host_port string)(string,int) { //使用database/sql包中的Open连接数据库 var runsql_total = "select count(1) from tb_wrong_run_sql where create_time>="+"'"+yes_date+"'" fmt.Println(runsql_total) db, err := sql.Open("mysql", mysql_info["dbusername"]+":"+mysql_info["dbpassowrd"]+"@tcp("+db_ip+":"+mysql_host_port+")/"+mysql_info["dbname"]) if err != nil { fmt.Println("连接数据库失败:", err) return "error",-1 } //使用DB的query方法遍历数据库数据 rows, err := db.Query(runsql_total) //获取完毕释放rows,阻止更多的列举 defer rows.Close() if err != nil { fmt.Println("获取错误:", err) return "error",-1 } var total_cnt int for rows.Next() { rows.Scan(&total_cnt) } return "success",total_cnt } func pathexists(path string) (int, error) { _, err := os.Stat(path) if err == nil { return 1, nil } if os.IsNotExist(err) { return 0, nil } return 0, err } func main(){ var record_cnt = 0 var mailTo = []string{} db_ip := os.Args[1] /*外部输入参数IP地址,如192.168.1.22*/ var attach_file_name = "wrong_sql_"+db_ip+"_"+now_time.Format("20060102")+".xlsx" var subject = "【数据库监控测试环境】不符合规范查询:" + db_ip + "(" + send_subject[db_ip]+ ")-"+now_time.Format("20060102") var mysql_host_port = host_port[db_ip] //附件目录 _dir := "./attach_file" exist_flag, err := pathexists(_dir) if err != nil { fmt.Printf("get dir error![%v] ", err) return } if exist_flag == 0 { err := os.Mkdir(_dir, os.ModePerm) if err != nil { fmt.Printf("mkdir failed![%v] ", err) } else { fmt.Printf("mkdir success! ") } } mailTo=strings.Split(mail_group[db_ip], ",") _,total_count:=get_total_count(db_ip,mysql_host_port) body,record_cnt := get_html_data(db_ip,mysql_host_port) //fmt.Print(body) if record_cnt> 0 { //生成excel数据 if total_count > limit_record_cnt { get_excel_data(db_ip,mysql_host_port,attach_file_name) } SendMail(mailTo, subject, body,total_count,attach_file_name) } }
配置文件内容:
config.ini
[smtp] user=yw@test.com pass=test host=mail.test.com port=25 [mysql_info] dbusername=dmladmin dbpassowrd=dmladmin dbname=db_admin [host_port] 192.168.1.22=3306 192.168.1.113=3306 192.168.1.130=3306 192.168.1.131=3306 192.168.1.8=4769 192.168.1.92=3306 192.168.1.63=3306 192.168.1.99=3306 192.168.1.90=3306 192.168.1.127=3306 [mail_group] 192.168.1.22=hxl@163.com,hxl@163.com 192.168.1.113=hxl@163.com,hxl@163.com 192.168.1.130=hxl@163.com,hxl@163.com 192.168.1.131=hxl@163.com,hxl@163.com 192.168.1.8=hxl@163.com,hxl@163.com 192.168.1.92=hxl@163.com,hxl@163.com 192.168.1.63=hxl@163.com,hxl@163.com 192.168.1.99=hxl@163.com,hxl@163.com 192.168.1.90=hxl@163.com,hxl@163.com 192.168.1.127=hxl@163.com,hxl@163.com [subject] 192.168.1.22=test1 192.168.1.113=test2 192.168.1.130=test3 192.168.1.131=test4 192.168.1.8=test5 192.168.1.92=test6 192.168.1.63=test7 192.168.1.99=test8 192.168.1.90=test9 192.168.1.127=test10