【Golang】进程监控器的错误报告发送

引子

在上一篇Golang实战记中,我做了一个进程监控器,当服务器上的进程结束了,就会向电子邮箱发送一封邮件。

在这个基础上,加入一些必要的功能是值得考虑的,比如:

  1. 日志信息发送:程序运行过程的输出。
  2. 错误信息发送:如果程序运行到一半出错了,也可以将错误信息发送给邮箱。

日志功能的实现

为了使程序能够在更多的系统上运行,我没有采用命令名 > 文件名的方法,我们有更加灵活的实现方法,就是把标准输出和标准错误输出导入到日志里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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)
}

其实,到这里我们已经解决了两个需求,因为我们将运行的输出和错误输出都定向到了日志中。

更加智能的错误信息

目前的主函数是这一个样子的:

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() {
// 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)
}

那么接下来,我们可以实现更多的功能,比如:

  1. 可选择的错误信息发送:如果错误发生在调试阶段,那么就没必要发送邮件了;如果错误发生在无人看管的运行阶段,就需要发送邮件。
  2. 更加智能的信息:如果运行出错了,可以在邮件的标题中说明出错了。

对于错误信息发送,实现很简单,因为运行过程如果出错了,那么就会导致cmd.Wait()的返回err不为nil,那么就可以将这部分的代码修改为:

1
2
3
4
5
6
7
// 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()进行修改:

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++的一个原因——便捷。

文章作者:
文章链接: https://www.coderlock.site/2025/12/08/Golang实战记:进程监控器的错误报告发送/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 寒夜雨