-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathmain.go
222 lines (188 loc) · 6.25 KB
/
main.go
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
package main
import (
"flag"
"fmt"
"html/template"
"log"
"net/http"
"os"
"time"
"PromAI/pkg/config"
"PromAI/pkg/metrics"
"PromAI/pkg/prometheus"
"PromAI/pkg/report"
"PromAI/pkg/status"
"PromAI/pkg/notify"
"PromAI/pkg/utils"
"github.com/robfig/cron/v3"
"gopkg.in/yaml.v2"
)
// loadConfig 加载配置文件
func loadConfig(path string) (*config.Config, error) {
data, err := os.ReadFile(path) // 读取配置文件
if err != nil {
return nil, fmt.Errorf("reading config file: %w", err)
}
var config config.Config // 定义配置结构体
if err := yaml.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("parsing config file: %w", err)
} // 解析配置文件
// 从环境变量中获取 PrometheusURL
if envPrometheusURL := os.Getenv("PROMETHEUS_URL"); envPrometheusURL != "" {
log.Printf("使用环境变量中的 Prometheus URL: %s", envPrometheusURL)
config.PrometheusURL = envPrometheusURL
} else {
log.Printf("使用配置文件中的 Prometheus URL: %s", config.PrometheusURL)
}
return &config, nil // 返回配置结构体
}
// setup 初始化应用程序
func setup(configPath string) (*prometheus.Client, *config.Config, error) {
config, err := loadConfig(configPath)
if err != nil {
return nil, nil, fmt.Errorf("loading config: %w", err)
}
client, err := prometheus.NewClient(config.PrometheusURL)
if err != nil {
return nil, nil, fmt.Errorf("initializing Prometheus client: %w", err)
}
return client, config, nil
}
func main() {
configPath := flag.String("config", "config/config.yaml", "Path to configuration file")
port := flag.String("port", "8091", "Port to run the HTTP server on")
flag.Parse()
utils.SetGlobalPort(*port)
client, config, err := setup(*configPath)
if err != nil {
log.Fatalf("Error setting up: %v", err)
}
collector := metrics.NewCollector(client.API, config)
// 设置定时任务
if config.CronSchedule != "" {
c := cron.New()
_, err := c.AddFunc(config.CronSchedule, func() {
data, err := collector.CollectMetrics()
if err != nil {
log.Printf("定时任务收集指标失败: %v", err)
return
}
reportFilePath, err := report.GenerateReport(*data)
if err != nil {
log.Printf("定时任务生成报告失败: %v", err)
return
}
log.Printf("定时任务成功生成报告: %s", reportFilePath)
if config.Notifications.Dingtalk.Enabled {
log.Printf("发送钉钉消息")
if err := notify.SendDingtalk(config.Notifications.Dingtalk, reportFilePath); err != nil {
log.Printf("发送钉钉消息失败: %v", err)
}
}
if config.Notifications.Email.Enabled {
log.Printf("发送邮件")
notify.SendEmail(config.Notifications.Email, reportFilePath)
}
})
if err != nil {
log.Printf("设置定时任务失败: %v", err)
} else {
c.Start()
log.Printf("已启动定时任务,执行计划: %s", config.CronSchedule)
}
} else {
log.Printf("未配置定时任务,请手动触发生成报告")
}
if config.ReportCleanup.Enabled {
// 确定使用哪个计划
cleanupSchedule := config.ReportCleanup.CronSchedule
if cleanupSchedule == "" {
cleanupSchedule = config.CronSchedule
}
if cleanupSchedule != "" {
c := cron.New()
_, err := c.AddFunc(cleanupSchedule, func() {
if err := report.CleanupReports(config.ReportCleanup.MaxAge); err != nil {
log.Printf("报告清理失败: %v", err)
return
}
log.Printf("报告清理成功")
})
if err != nil {
log.Printf("设置清理定时任务失败: %v", err)
} else {
c.Start()
log.Printf("已启动清理定时任务,执行计划: %s", cleanupSchedule)
}
} else {
log.Printf("未配置任何定时任务计划,请手动清理报告")
}
}
// 设置路由处理器
setupRoutes(collector, config)
// 启动服务器
log.Printf("Starting server on port: %s with config: %s", *port, *configPath)
log.Printf("Prometheus URL: %s", config.PrometheusURL)
log.Printf("获取报告地址: http://localhost:%s/getreport", *port)
log.Printf("健康看板地址: http://localhost:%s/status", *port)
if err := http.ListenAndServe(":"+*port, nil); err != nil {
log.Fatalf("Error starting HTTP server: %v", err)
}
}
// setupRoutes 设置 HTTP 路由
func setupRoutes(collector *metrics.Collector, config *config.Config) {
// 设置报告生成路由
http.HandleFunc("/getreport", makeReportHandler(collector))
// 设置静态文件服务
http.Handle("/reports/", http.StripPrefix("/reports/", http.FileServer(http.Dir("reports"))))
// 设置状态页面路由
http.HandleFunc("/status", makeStatusHandler(collector.Client, config))
}
// makeReportHandler 创建报告处理器
func makeReportHandler(collector *metrics.Collector) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
data, err := collector.CollectMetrics()
if err != nil {
http.Error(w, "Failed to collect metrics", http.StatusInternalServerError)
log.Printf("Error collecting metrics: %v", err)
return
}
reportFilePath, err := report.GenerateReport(*data)
if err != nil {
http.Error(w, "Failed to generate report", http.StatusInternalServerError)
log.Printf("Error generating report: %v", err)
return
}
http.Redirect(w, r, "/"+reportFilePath, http.StatusSeeOther)
}
}
// makeStatusHandler 创建状态页面处理器
func makeStatusHandler(client metrics.PrometheusAPI, config *config.Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
data, err := status.CollectMetricStatus(client, config)
if err != nil {
http.Error(w, "Failed to collect status data", http.StatusInternalServerError)
log.Printf("Error collecting status data: %v", err)
return
}
// 创建模板函数映射
funcMap := template.FuncMap{
"now": time.Now,
"date": func(format string, t time.Time) string {
return t.Format(format)
},
}
tmpl := template.New("status.html").Funcs(funcMap)
tmpl, err = tmpl.ParseFiles("templates/status.html")
if err != nil {
http.Error(w, "Failed to parse template", http.StatusInternalServerError)
log.Printf("Error parsing template: %v", err)
return
}
if err := tmpl.Execute(w, data); err != nil {
http.Error(w, "Failed to render template", http.StatusInternalServerError)
log.Printf("Error rendering template: %v", err)
return
}
}
}