diff --git a/dockercheck.go b/dockercheck.go
index b89d180..5640e5b 100644
--- a/dockercheck.go
+++ b/dockercheck.go
@@ -36,6 +36,7 @@ const (
dcKindStatusChanged dcChangeKind = "status_changed"
dcKindHealthChanged dcChangeKind = "health_changed"
dcKindDisappeared dcChangeKind = "disappeared"
+ dcKindAppeared dcChangeKind = "appeared"
)
type dcStateChange struct {
@@ -58,6 +59,10 @@ func (ch dcStateChange) isProblem() bool {
return false
}
+func (ch dcStateChange) isNew() bool {
+ return ch.Kind == dcKindAppeared
+}
+
func (ch dcStateChange) isRecovery() bool {
switch ch.Kind {
case dcKindStatusChanged:
@@ -108,6 +113,7 @@ func runDockerCheck() error {
// Загружаем предыдущее состояние
prevState := dcLoadState()
+ isFirstRun := len(prevState.Containers) == 0
// Строим map текущего состояния
current := make(map[string]dcContainerInfo, len(containers))
@@ -116,7 +122,7 @@ func runDockerCheck() error {
}
// Сравниваем
- changes := dcCompareStates(prevState.Containers, current)
+ changes := dcCompareStates(prevState.Containers, current, isFirstRun)
// Статистика
runningCount := 0
@@ -140,6 +146,8 @@ func runDockerCheck() error {
for _, ch := range changes {
arrow := dcChangeArrow(ch)
switch ch.Kind {
+ case dcKindAppeared:
+ log.Printf(" %s %-30s | появился (%s) | %s", arrow, ch.Name, ch.CurrState.Status, ch.Image)
case dcKindDisappeared:
log.Printf(" %s %-30s | исчез (был: %s)", arrow, ch.Name, ch.PrevState.Status)
case dcKindStatusChanged:
@@ -265,7 +273,7 @@ func dcNormalizeStatus(raw string) string {
// ── Сравнение состояний ──────────────────────────────────────────────────────
-func dcCompareStates(prev map[string]dcContainerState, curr map[string]dcContainerInfo) []dcStateChange {
+func dcCompareStates(prev map[string]dcContainerState, curr map[string]dcContainerInfo, isFirstRun bool) []dcStateChange {
var changes []dcStateChange
// Проверяем текущие контейнеры
@@ -273,7 +281,16 @@ func dcCompareStates(prev map[string]dcContainerState, curr map[string]dcContain
prevInfo, existed := prev[name]
if !existed {
- // Новый контейнер — не алертим, просто добавится в state
+ if !isFirstRun {
+ // Новый контейнер появился после первого запуска — алертим
+ changes = append(changes, dcStateChange{
+ Name: name,
+ Kind: dcKindAppeared,
+ PrevState: dcContainerState{},
+ CurrState: dcContainerState{Status: currInfo.Status, Health: currInfo.Health},
+ Image: currInfo.Image,
+ })
+ }
continue
}
@@ -365,29 +382,34 @@ func dcSaveState(current map[string]dcContainerInfo) {
// ── Отправка алерта ──────────────────────────────────────────────────────────
func dcSendAlert(hostname string, changes []dcStateChange) {
- var problems, recoveries []dcStateChange
+ var problems, recoveries, appeared []dcStateChange
for _, ch := range changes {
- if ch.isRecovery() {
+ switch {
+ case ch.isNew():
+ appeared = append(appeared, ch)
+ case ch.isRecovery():
recoveries = append(recoveries, ch)
- } else if ch.isProblem() {
+ case ch.isProblem():
problems = append(problems, ch)
}
}
- // Если нет ни проблем, ни восстановлений — молчим
- if len(problems) == 0 && len(recoveries) == 0 {
+ // Если нет никаких изменений — молчим
+ if len(problems) == 0 && len(recoveries) == 0 && len(appeared) == 0 {
return
}
// Заголовок по наиболее критичному событию
var header string
switch {
- case len(problems) > 0 && len(recoveries) > 0:
- header = "⚠️ Изменения в состоянии контейнеров"
case len(problems) > 0:
header = "🚨 АЛЕРТ: Проблемы с контейнерами!"
- default:
+ case len(recoveries) > 0 && len(appeared) > 0:
+ header = "⚠️ Изменения в состоянии контейнеров"
+ case len(recoveries) > 0:
header = "✅ Контейнеры восстановлены"
+ default:
+ header = "ℹ️ Новые контейнеры"
}
message := fmt.Sprintf(
@@ -458,6 +480,20 @@ func dcSendAlert(hostname string, changes []dcStateChange) {
}
}
+ // Новые контейнеры
+ if len(appeared) > 0 {
+ message += "━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
+ message += fmt.Sprintf("🆕 Появились (%d):\n\n", len(appeared))
+ for _, ch := range appeared {
+ message += fmt.Sprintf(
+ "🆕 %s\n"+
+ " 📌 Статус: %s\n"+
+ " 🐳 %s\n\n",
+ ch.Name, ch.CurrState.Status, ch.Image,
+ )
+ }
+ }
+
message += "━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
message += "💡 docker ps -a | docker logs <имя> --tail 50"
@@ -492,6 +528,8 @@ func dcStatusEmoji(status, health string) string {
func dcChangeEmoji(ch dcStateChange) string {
switch ch.Kind {
+ case dcKindAppeared:
+ return "🆕"
case dcKindDisappeared:
return "👻"
case dcKindHealthChanged:
@@ -510,6 +548,9 @@ func dcChangeEmoji(ch dcStateChange) string {
}
func dcChangeArrow(ch dcStateChange) string {
+ if ch.isNew() {
+ return "🆕"
+ }
if ch.isRecovery() {
return "✅"
}