Files
Lizandro GuarnizoandClaude Sonnet 4.6 5f92934fba feat(url-monitor): agregar monitoreo de disponibilidad de URLs desde servidor
- Modelos UrlMonitor y UrlMonitorLog con purga automática a 7 días
- Cron cada minuto ejecuta chequeos HEAD→GET con fallback, alerta Telegram en cambio de estado
- CRUD completo + chequeo manual + historial de logs
- Migración automática de tablas

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-06 09:33:48 -05:00

103 lines
3.3 KiB
Go

package models
import (
"time"
"github.com/sujit-baniya/fiber-boilerplate/app"
"gorm.io/gorm"
)
type UrlMonitor struct {
gorm.Model
Nombre string `json:"nombre" gorm:"column:nombre;size:100"`
URL string `json:"url" gorm:"column:url;size:500"`
IntervaloMin int `json:"intervalo_min" gorm:"column:intervalo_min;default:5"`
TimeoutSeg int `json:"timeout_seg" gorm:"column:timeout_seg;default:10"`
Activo bool `json:"activo" gorm:"column:activo;default:true"`
// Estado actual
UltimoStatus int `json:"ultimo_status" gorm:"column:ultimo_status"`
UltimaLatMs int64 `json:"ultima_lat_ms" gorm:"column:ultima_lat_ms"`
UltimoCheckAt *time.Time `json:"ultimo_check_at" gorm:"column:ultimo_check_at"`
UltimoOk *bool `json:"ultimo_ok" gorm:"column:ultimo_ok"`
}
func (UrlMonitor) TableName() string { return "url_monitor" }
type UrlMonitorLog struct {
ID uint `json:"id" gorm:"primaryKey;autoIncrement"`
MonitorID uint `json:"monitor_id" gorm:"column:monitor_id;index"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at;index"`
StatusCode int `json:"status_code" gorm:"column:status_code"`
LatenciaMs int64 `json:"latencia_ms" gorm:"column:latencia_ms"`
Ok bool `json:"ok" gorm:"column:ok"`
Error string `json:"error" gorm:"column:error;type:text"`
}
func (UrlMonitorLog) TableName() string { return "url_monitor_log" }
func GetAllUrlMonitors() ([]UrlMonitor, error) {
var items []UrlMonitor
err := app.Http.Database.DB.Order("nombre ASC").Find(&items).Error
return items, err
}
func GetActiveUrlMonitors() ([]UrlMonitor, error) {
var items []UrlMonitor
err := app.Http.Database.DB.Where("activo = true").Find(&items).Error
return items, err
}
func GetUrlMonitorByID(id uint) (*UrlMonitor, error) {
var m UrlMonitor
err := app.Http.Database.DB.First(&m, id).Error
return &m, err
}
func CreateUrlMonitor(m *UrlMonitor) error {
return app.Http.Database.DB.Create(m).Error
}
func SaveUrlMonitor(m *UrlMonitor) error {
return app.Http.Database.DB.Save(m).Error
}
func DeleteUrlMonitor(id uint) error {
return app.Http.Database.DB.Delete(&UrlMonitor{}, id).Error
}
func UpdateUrlMonitorStatus(id uint, statusCode int, latMs int64, ok bool) error {
now := time.Now()
return app.Http.Database.DB.Model(&UrlMonitor{}).Where("id = ?", id).Updates(map[string]interface{}{
"ultimo_status": statusCode,
"ultima_lat_ms": latMs,
"ultimo_check_at": &now,
"ultimo_ok": ok,
}).Error
}
func InsertUrlMonitorLog(monitorID uint, statusCode int, latMs int64, ok bool, errStr string) {
app.Http.Database.DB.Create(&UrlMonitorLog{
MonitorID: monitorID,
CreatedAt: time.Now(),
StatusCode: statusCode,
LatenciaMs: latMs,
Ok: ok,
Error: errStr,
})
}
func GetUrlMonitorLogs(monitorID uint, horas int) ([]UrlMonitorLog, error) {
var items []UrlMonitorLog
desde := time.Now().Add(-time.Duration(horas) * time.Hour)
err := app.Http.Database.DB.
Where("monitor_id = ? AND created_at >= ?", monitorID, desde).
Order("created_at ASC").
Find(&items).Error
return items, err
}
func PurgarUrlMonitorLogs(dias int) error {
corte := time.Now().AddDate(0, 0, -dias)
return app.Http.Database.DB.Where("created_at < ?", corte).Delete(&UrlMonitorLog{}).Error
}