引子
在上一篇Golang实战记中,我做了一个进程监控器,当服务器上的进程结束了,就会向电子邮箱发送一封邮件。
在这个基础上,加入一些必要的功能是值得考虑的,比如:
- 日志信息发送:程序运行过程的输出。
- 错误信息发送:如果程序运行到一半出错了,也可以将错误信息发送给邮箱。
日志功能的实现
为了使程序能够在更多的系统上运行,我没有采用命令名 > 文件名的方法,我们有更加灵活的实现方法,就是把标准输出和标准错误输出导入到日志里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| raw_log_file := pkg.GetLogFile(info) log_file, err := os.OpenFile(raw_log_file, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644) if err != nil { panic(err) } defer log_file.Close()
...
cmd := exec.Command(command[0], command[1:]...) cmd.Stdout = log_file cmd.Stderr = log_file err = cmd.Start() if err != nil { panic(err) }
|
其实,到这里我们已经解决了两个需求,因为我们将运行的输出和错误输出都定向到了日志中。
更加智能的错误信息
目前的主函数是这一个样子的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| package main
import ( "fmt" "os" "os/exec" "profiler/pkg" )
func main() { var info pkg.Information pkg.GetTime(&info, "start") email_info := pkg.InitPrivateEmailInformation()
raw_log_file := pkg.GetLogFile(info) log_file, err := os.OpenFile(raw_log_file, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644) if err != nil { panic(err) } defer log_file.Close()
command := pkg.BuildCommand(os.Args, info) pkg.GetCommandName(&info)
cmd := exec.Command(command[0], command[1:]...) cmd.Stdout = log_file cmd.Stderr = log_file err = cmd.Start() if err != nil { panic(err) }
err = cmd.Wait() if err != nil { panic(err) }
pkg.GetTime(&info, "end") content := pkg.InformationToString(info) fmt.Println(content) pkg.SendEmail(content, email_info.Sender, email_info.Recver, email_info.Port, email_info.Smtp_server, email_info.Password, raw_log_file) }
|
那么接下来,我们可以实现更多的功能,比如:
- 可选择的错误信息发送:如果错误发生在调试阶段,那么就没必要发送邮件了;如果错误发生在无人看管的运行阶段,就需要发送邮件。
- 更加智能的信息:如果运行出错了,可以在邮件的标题中说明出错了。
对于错误信息发送,实现很简单,因为运行过程如果出错了,那么就会导致cmd.Wait()的返回err不为nil,那么就可以将这部分的代码修改为:
1 2 3 4 5 6 7
| err = cmd.Wait()
pkg.GetTime(&info, "end") content := pkg.InformationToString(info) fmt.Println(content) pkg.SendEmail(content, email_info.Sender, email_info.Recver, email_info.Port, email_info.Smtp_server, email_info.Password, raw_log_file, err != nil)
|
然后将SendEmail()进行修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| func SendEmail(content string, sender string, recver string, port int, smtp_server string, password string, attach string, is_failed bool) { e := email.NewEmail() e.From = sender e.To = []string{recver} if is_failed { e.Subject = "Error from Server Profiler" } else { e.Subject = "Success Information from Server Profiler" } e.Text = []byte(content) _, attach_err := e.AttachFile(attach) if attach_err != nil { panic(attach_err) } err := e.Send(smtp_server+":"+fmt.Sprint(port), smtp.PlainAuth("", sender, password, smtp_server)) if err != nil { panic(err) } }
|
就完成了功能的实现。
交叉编译
Golang的一个非常出色的特性就是简单的交叉编译功能,我使用MacOS或者Windows,如果想编译Linux下的可执行程序,只需要:
1
| CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
|
这也是我喜欢Golang胜过C与C++的一个原因——便捷。