[notifier] 新增email告警方式
This commit is contained in:
parent
9970e93665
commit
18e1672114
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"sysmonitord/internal/monitor/detector"
|
"sysmonitord/internal/monitor/detector"
|
||||||
"sysmonitord/internal/monitor/timer"
|
"sysmonitord/internal/monitor/timer"
|
||||||
"sysmonitord/internal/monitor/watcher"
|
"sysmonitord/internal/monitor/watcher"
|
||||||
|
"sysmonitord/internal/notifier"
|
||||||
"sysmonitord/internal/scanner/file"
|
"sysmonitord/internal/scanner/file"
|
||||||
"sysmonitord/internal/scanner/process"
|
"sysmonitord/internal/scanner/process"
|
||||||
"sysmonitord/internal/storage"
|
"sysmonitord/internal/storage"
|
||||||
|
|
@ -107,6 +108,10 @@ var StartCmd = &cobra.Command{
|
||||||
procScheduler := timer.NewScheduler(time.Duration(cfg.Scanner.Process.Interval)*time.Second, procDetector)
|
procScheduler := timer.NewScheduler(time.Duration(cfg.Scanner.Process.Interval)*time.Second, procDetector)
|
||||||
procScheduler.Start()
|
procScheduler.Start()
|
||||||
|
|
||||||
|
// ====== 启动告警管理器 ======
|
||||||
|
alerter := notifier.NewAlerter(cfg.Notification)
|
||||||
|
alerter.Start()
|
||||||
|
|
||||||
logger.Log.Info("系统监控守护服务已启动,正在监控系统变化...")
|
logger.Log.Info("系统监控守护服务已启动,正在监控系统变化...")
|
||||||
|
|
||||||
quit := make(chan os.Signal, 1)
|
quit := make(chan os.Signal, 1)
|
||||||
|
|
@ -126,6 +131,14 @@ var StartCmd = &cobra.Command{
|
||||||
fileDetector.HandleEvent(event.Path, event.Op.String())
|
fileDetector.HandleEvent(event.Path, event.Op.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test
|
||||||
|
alerter.PushAlert(notifier.AlertEvent{
|
||||||
|
Type: "File",
|
||||||
|
Path: event.Path,
|
||||||
|
Reason: event.Op.String(),
|
||||||
|
Details: "To test",
|
||||||
|
})
|
||||||
|
|
||||||
case err := <-mon.Errors():
|
case err := <-mon.Errors():
|
||||||
logger.Log.Error("文件监听错误", zap.Error(err))
|
logger.Log.Error("文件监听错误", zap.Error(err))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,28 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Log LogConfig `yaml:"log"`
|
Log LogConfig `yaml:"log"`
|
||||||
Audit AuditConfig `yaml:"audit"`
|
Audit AuditConfig `yaml:"audit"`
|
||||||
Scanner ScannerConfig `yaml:"scanner"`
|
Scanner ScannerConfig `yaml:"scanner"`
|
||||||
Storage StorageConfig `yaml:"storage"`
|
Storage StorageConfig `yaml:"storage"`
|
||||||
|
Notification NotificationConfig `yaml:"notification"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotificationConfig struct {
|
||||||
|
Email EmailConfig `yaml:"email"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmailConfig struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Recipients []string `yaml:"recipients"`
|
||||||
|
SMTP SMTPConfig `yaml:"smtp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SMTPConfig struct {
|
||||||
|
Server string `yaml:"server"`
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
Username string `yaml:"username"`
|
||||||
|
Password string `yaml:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogConfig struct {
|
type LogConfig struct {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
package notifier
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"sysmonitord/internal/config"
|
||||||
|
"sysmonitord/internal/notifier/mail"
|
||||||
|
"sysmonitord/pkg/logger"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AlertEvent struct {
|
||||||
|
Type string
|
||||||
|
Path string
|
||||||
|
Reason string
|
||||||
|
Details string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Alerter struct {
|
||||||
|
cfg config.NotificationConfig
|
||||||
|
mailer *mail.Mailer
|
||||||
|
eventChan chan AlertEvent
|
||||||
|
buffer []AlertEvent
|
||||||
|
mu sync.Mutex
|
||||||
|
timer *time.Timer
|
||||||
|
interval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAlerter(cfg config.NotificationConfig) *Alerter {
|
||||||
|
return &Alerter{
|
||||||
|
cfg: cfg,
|
||||||
|
mailer: mail.NewMailer(cfg.Email),
|
||||||
|
eventChan: make(chan AlertEvent, 100),
|
||||||
|
buffer: make([]AlertEvent, 0),
|
||||||
|
interval: 1 * time.Minute, // Todo: 可配置化
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Alerter) Start() {
|
||||||
|
go a.loop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Alerter) PushAlert(event AlertEvent) {
|
||||||
|
select {
|
||||||
|
case a.eventChan <- event:
|
||||||
|
logger.Log.Debug("[notifier] 推送告警事件", zap.String("path", event.Path), zap.String("reason", event.Reason))
|
||||||
|
default:
|
||||||
|
logger.Log.Warn("[notifier] 告警事件通道已满,丢弃告警", zap.String("path", event.Path), zap.String("reason", event.Reason))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Alerter) loop() {
|
||||||
|
a.timer = time.NewTimer(a.interval)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case event := <-a.eventChan:
|
||||||
|
a.mu.Lock()
|
||||||
|
a.buffer = append(a.buffer, event)
|
||||||
|
a.mu.Unlock()
|
||||||
|
logger.Log.Debug("[notifier] 收到告警,加入待发送序列", zap.String("path", event.Path))
|
||||||
|
|
||||||
|
case <-a.timer.C:
|
||||||
|
a.mu.Lock()
|
||||||
|
if len(a.buffer) > 0 {
|
||||||
|
a.sendAlert()
|
||||||
|
a.buffer = make([]AlertEvent, 0)
|
||||||
|
}
|
||||||
|
a.mu.Unlock()
|
||||||
|
|
||||||
|
a.timer.Reset(a.interval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Alerter) sendAlert() {
|
||||||
|
if len(a.buffer) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
subject := fmt.Sprintf("【Sysmonitor】新增 %d 个告警", len(a.buffer))
|
||||||
|
body := "以下是最近的告警事件:\n\n"
|
||||||
|
|
||||||
|
for _, event := range a.buffer {
|
||||||
|
body += fmt.Sprintf("- [%s] %s: %s (%s)\n", event.Type, event.Path, event.Reason, event.Details)
|
||||||
|
}
|
||||||
|
|
||||||
|
body += "\n请及时关注系统安全状况。"
|
||||||
|
|
||||||
|
if err := a.mailer.Send(subject, body); err != nil {
|
||||||
|
logger.Log.Error("[notifier] 发送告警邮件失败", zap.Error(err))
|
||||||
|
} else {
|
||||||
|
logger.Log.Debug("[notifier] 告警邮件发送成功", zap.Int("count", len(a.buffer)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package mail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/smtp"
|
||||||
|
"sysmonitord/internal/config"
|
||||||
|
"sysmonitord/pkg/logger"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mailer struct {
|
||||||
|
cfg config.EmailConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMailer(cfg config.EmailConfig) *Mailer {
|
||||||
|
return &Mailer{cfg: cfg}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mailer) Send(subject, body string) error {
|
||||||
|
if !m.cfg.Enabled {
|
||||||
|
logger.Log.Debug("[notifier] 未启用邮件通知,跳过....")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := make(map[string]string)
|
||||||
|
headers["From"] = m.cfg.SMTP.Username
|
||||||
|
headers["To"] = m.cfg.Recipients[0]
|
||||||
|
headers["Subject"] = subject
|
||||||
|
|
||||||
|
message := ""
|
||||||
|
for k, v := range headers {
|
||||||
|
message += fmt.Sprintf("%s: %s\r\n", k, v)
|
||||||
|
}
|
||||||
|
message += "\r\n" + body
|
||||||
|
|
||||||
|
auth := smtp.PlainAuth("", m.cfg.SMTP.Username, m.cfg.SMTP.Password, m.cfg.SMTP.Server)
|
||||||
|
addr := fmt.Sprintf("%s:%d", m.cfg.SMTP.Server, m.cfg.SMTP.Port)
|
||||||
|
|
||||||
|
logger.Log.Info("[notifier] 发送邮件通知", zap.String("subject", subject), zap.String("to", m.cfg.Recipients[0]))
|
||||||
|
|
||||||
|
err := smtp.SendMail(addr, auth, m.cfg.SMTP.Username, m.cfg.Recipients, []byte(message))
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Error("[notifier] 发送邮件失败", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Info("[notifier] 邮件发送成功")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user