kiss server monitoring tool with email alerts
go
monitoring
1package main
2
3import (
4 "errors"
5 "fmt"
6 "os"
7 "os/exec"
8 "path"
9 "runtime"
10 "runtime/debug"
11 "strings"
12
13 "github.com/spf13/cobra"
14)
15
16var (
17 flagConfig = "config"
18 flagDaemon = "daemon"
19 cfgFile string
20 runAsDaemon bool
21)
22
23func main() {
24 homeDir, err := os.UserHomeDir()
25 if err != nil {
26 fmt.Fprintf(os.Stderr, "error getting user home directory: %v", err)
27 os.Exit(1)
28 }
29
30 version, err := getVersion()
31 if err != nil {
32 fmt.Fprintf(os.Stderr, "error getting version: %v", err)
33 version = "unknown"
34 }
35
36 rootCmd := &cobra.Command{
37 Use: "servmon",
38 Short: "KISS server monitoring tool with email alerts",
39 Version: version,
40 RunE: func(cmd *cobra.Command, args []string) error {
41 runAsDaemon, err := cmd.Flags().GetBool(flagDaemon)
42 if err != nil {
43 return fmt.Errorf("error getting flag %s: %v", flagDaemon, err)
44 }
45
46 if runAsDaemon {
47 pid, err := runAsDaemonProcess()
48 if err != nil {
49 return err
50 }
51
52 cmd.Println("Running as daemon with PID", pid)
53 return nil
54 }
55
56 cfgPath, err := cmd.Flags().GetString(flagConfig)
57 if err != nil {
58 return fmt.Errorf("error getting flag %s: %v", flagConfig, err)
59 }
60
61 if _, err := os.Stat(cfgPath); os.IsNotExist(err) {
62 cfg := defaultConfig()
63 if err := cfg.Save(cfgFile); err != nil {
64 return err
65 }
66
67 cmd.Println("Configuration file generated at", cfgFile)
68 return nil
69 } else if err != nil {
70 return fmt.Errorf("error checking config file: %v", err)
71 }
72
73 cfg, err := loadConfig(cfgPath)
74 if err != nil {
75 return err
76 }
77
78 go monitorCPU(cfg)
79 go monitorMemory(cfg)
80 go monitorDisk(cfg)
81 go monitorHTTP(cfg)
82
83 select {} // keep alive
84 },
85 }
86
87 rootCmd.CompletionOptions.DisableDefaultCmd = true
88 rootCmd.PersistentFlags().StringVar(&cfgFile, flagConfig, path.Join(homeDir, ".servmon.yaml"), "config file")
89 rootCmd.PersistentFlags().BoolVarP(&runAsDaemon, flagDaemon, "d", false, "run as daemon")
90
91 if err := rootCmd.Execute(); err != nil {
92 fmt.Fprint(os.Stderr, err)
93 os.Exit(1)
94 }
95}
96
97func runAsDaemonProcess() (int, error) {
98 if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" {
99 var args []string
100 for _, a := range os.Args[1:] {
101 if a != "-d" && a != "--daemon" {
102 args = append(args, a)
103 }
104 }
105
106 cmd := exec.Command(os.Args[0], args...)
107 cmd.Stdout = os.NewFile(3, "log.out")
108 cmd.Stderr = os.NewFile(4, "log.err")
109 cmd.Stdin = os.NewFile(3, "log.in")
110
111 if err := cmd.Start(); err != nil {
112 return 0, fmt.Errorf("error starting as daemon: %v", err)
113 }
114
115 pid := cmd.Process.Pid
116
117 // Detach the process
118 err := cmd.Process.Release()
119 if err != nil {
120 return 0, fmt.Errorf("error detaching process: %v", err)
121 }
122
123 return pid, nil
124 }
125
126 return 0, fmt.Errorf("daemon mode is not supported on %s", runtime.GOOS)
127}
128
129func getVersion() (string, error) {
130 version, ok := debug.ReadBuildInfo()
131 if !ok {
132 return "", errors.New("failed to get version")
133 }
134
135 return strings.TrimSpace(version.Main.Version), nil
136}