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
|
package monitor
import (
"context"
"time"
"github.com/Fuwn/kaze/internal/config"
"github.com/Fuwn/kaze/internal/storage"
)
// Result represents the outcome of a monitor check
type Result struct {
MonitorName string
Timestamp time.Time
Status Status
ResponseTime time.Duration
StatusCode int // HTTP status code (0 for non-HTTP)
Error error
SSLExpiry *time.Time
SSLDaysLeft int
}
// Status represents the status of a monitor
type Status string
const (
StatusUp Status = "up"
StatusDown Status = "down"
StatusDegraded Status = "degraded"
)
// Monitor is the interface that all monitor types must implement
type Monitor interface {
// ID returns the unique identifier for this monitor (group/name format)
ID() string
// Name returns the monitor's name
Name() string
// Group returns the group this monitor belongs to
Group() string
// Type returns the monitor type (http, https, tcp, gemini, icmp, dns, graphql, database)
Type() string
// Target returns the monitor target (URL or host:port)
Target() string
// Interval returns the check interval
Interval() time.Duration
// Retries returns the number of retry attempts
Retries() int
// HideSSLDays returns whether to hide SSL days from display
HideSSLDays() bool
// RoundResponseTime returns whether to round response time
RoundResponseTime() bool
// RoundUptime returns whether to round uptime percentage
RoundUptime() bool
// Check performs the monitoring check and returns the result
Check(ctx context.Context) *Result
}
// New creates a new monitor based on the configuration
func New(cfg config.MonitorConfig) (Monitor, error) {
switch cfg.Type {
case "http", "https":
return NewHTTPMonitor(cfg)
case "tcp":
return NewTCPMonitor(cfg)
case "gemini":
return NewGeminiMonitor(cfg)
case "icmp":
return NewICMPMonitor(cfg)
case "dns":
return NewDNSMonitor(cfg)
case "graphql":
return NewGraphQLMonitor(cfg)
case "database", "db":
return NewDatabaseMonitor(cfg)
default:
return nil, &UnsupportedTypeError{Type: cfg.Type}
}
}
// UnsupportedTypeError is returned when an unknown monitor type is specified
type UnsupportedTypeError struct {
Type string
}
func (e *UnsupportedTypeError) Error() string {
return "unsupported monitor type: " + e.Type
}
// ToCheckResult converts a monitor Result to a storage CheckResult
func (r *Result) ToCheckResult() *storage.CheckResult {
cr := &storage.CheckResult{
MonitorName: r.MonitorName,
Timestamp: r.Timestamp,
Status: string(r.Status),
ResponseTime: r.ResponseTime.Milliseconds(),
StatusCode: r.StatusCode,
SSLExpiry: r.SSLExpiry,
SSLDaysLeft: r.SSLDaysLeft,
}
if r.Error != nil {
cr.Error = r.Error.Error()
}
return cr
}
// ToCheckResultWithOptions converts a monitor Result to a storage CheckResult with display options applied
func (r *Result) ToCheckResultWithOptions(mon Monitor) *storage.CheckResult {
cr := r.ToCheckResult()
// Apply rounding if enabled
if mon.RoundResponseTime() {
// Round to nearest second (1000ms)
cr.ResponseTime = ((cr.ResponseTime + 500) / 1000) * 1000
}
// Hide SSL days if enabled
if mon.HideSSLDays() {
cr.SSLDaysLeft = 0
cr.SSLExpiry = nil
}
return cr
}
|