引子
在上一篇Golang实战记中,我做了一个进程监控器,当服务器上的进程结束了,就会向电子邮箱发送一封邮件。
在这个基础上,加入一些必要的功能是值得考虑的,比如:
- 日志信息发送:程序运行过程的输出。
- 错误信息发送:如果程序运行到一半出错了,也可以将错误信息发送给邮箱。
日志功能的实现
为了使程序能够在更多的系统上运行,我没有采用命令名 > 文件名的方法,我们有更加灵活的实现方法,就是把标准输出和标准错误输出导入到日志里:
// Prepare the Log
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()
...
// Output into the Log
cmd := exec.Command(command[0], command[1:]...)
cmd.Stdout = log_file
cmd.Stderr = log_file
err = cmd.Start()
if err != nil {
panic(err)
}其实,到这里我们已经解决了两个需求,因为我们将运行的输出和错误输出都定向到了日志中。
更加智能的错误信息
目前的主函数是这一个样子的:
package main
import (
"fmt"
"os"
"os/exec"
"profiler/pkg"
)
func main() {
// Init
var info pkg.Information
pkg.GetTime(&info, "start")
email_info := pkg.InitPrivateEmailInformation()
// Prepare the Log
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()
// Get the Command Name
command := pkg.BuildCommand(os.Args, info)
pkg.GetCommandName(&info)
// Start the Process
cmd := exec.Command(command[0], command[1:]...)
cmd.Stdout = log_file
cmd.Stderr = log_file
err = cmd.Start()
if err != nil {
panic(err)
}
// Wait till end
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,那么就可以将这部分的代码修改为:
// Wait till end
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()进行修改:
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下的可执行程序,只需要:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build这也是我喜欢Golang胜过C与C++的一个原因——便捷。