150 lines
3.3 KiB
Go
150 lines
3.3 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// UIMetric represents a metric for UI display
|
|
type UIMetric struct {
|
|
Name string
|
|
Value string
|
|
Status string // "ok", "warning", "error"
|
|
Timestamp time.Time
|
|
Error string
|
|
}
|
|
|
|
// UIMetricGroup represents a group of metrics for UI display
|
|
type UIMetricGroup struct {
|
|
Title string
|
|
Metrics []UIMetric
|
|
Errors []string
|
|
}
|
|
|
|
// UIExporter exports metrics in a format suitable for UI display
|
|
type UIExporter struct {
|
|
Collectors []Collector
|
|
}
|
|
|
|
func NewUIExporter(collectors ...Collector) *UIExporter {
|
|
return &UIExporter{Collectors: collectors}
|
|
}
|
|
|
|
// Export collects all metrics and formats them for UI
|
|
func (e *UIExporter) Export(ctx context.Context) []UIMetricGroup {
|
|
groups := []UIMetricGroup{}
|
|
|
|
for _, collector := range e.Collectors {
|
|
collection := collector.Collect(ctx)
|
|
// Capitalize first letter
|
|
name := collector.Name()
|
|
if len(name) > 0 {
|
|
name = strings.ToUpper(name[:1]) + name[1:]
|
|
}
|
|
group := UIMetricGroup{
|
|
Title: name,
|
|
Metrics: []UIMetric{},
|
|
Errors: collection.Errors,
|
|
}
|
|
|
|
for _, metric := range collection.Metrics {
|
|
status := "ok"
|
|
value := formatMetricValue(metric)
|
|
|
|
// Determine status based on metric type and value
|
|
if metric.Name == "zfs_pool_health" {
|
|
if metric.Value == 0.0 {
|
|
status = "error"
|
|
} else if metric.Value == 0.5 {
|
|
status = "warning"
|
|
}
|
|
} else if metric.Name == "smart_health" {
|
|
if metric.Value == 0.0 {
|
|
status = "error"
|
|
}
|
|
} else if metric.Name == "service_state" {
|
|
if metric.Value == 0.0 {
|
|
status = "error"
|
|
}
|
|
} else if strings.HasPrefix(metric.Name, "host_load") {
|
|
if metric.Value > 10.0 {
|
|
status = "warning"
|
|
}
|
|
if metric.Value > 20.0 {
|
|
status = "error"
|
|
}
|
|
}
|
|
|
|
group.Metrics = append(group.Metrics, UIMetric{
|
|
Name: formatMetricName(metric),
|
|
Value: value,
|
|
Status: status,
|
|
Timestamp: time.Now(),
|
|
})
|
|
}
|
|
|
|
groups = append(groups, group)
|
|
}
|
|
|
|
return groups
|
|
}
|
|
|
|
func formatMetricName(metric MetricValue) string {
|
|
name := metric.Name
|
|
if len(metric.Labels) > 0 {
|
|
labels := []string{}
|
|
for k, v := range metric.Labels {
|
|
labels = append(labels, fmt.Sprintf("%s=%s", k, v))
|
|
}
|
|
name = fmt.Sprintf("%s{%s}", name, strings.Join(labels, ", "))
|
|
}
|
|
return name
|
|
}
|
|
|
|
func formatMetricValue(metric MetricValue) string {
|
|
switch metric.Name {
|
|
case "zfs_pool_health":
|
|
if metric.Value == 1.0 {
|
|
return "ONLINE"
|
|
} else if metric.Value == 0.5 {
|
|
return "DEGRADED"
|
|
}
|
|
return "FAULTED"
|
|
case "zfs_pool_scrub_in_progress":
|
|
if metric.Value == 1.0 {
|
|
return "In Progress"
|
|
}
|
|
return "Idle"
|
|
case "smart_health":
|
|
if metric.Value == 1.0 {
|
|
return "PASSED"
|
|
}
|
|
return "FAILED"
|
|
case "service_state":
|
|
if metric.Value == 1.0 {
|
|
return "Running"
|
|
}
|
|
return "Stopped"
|
|
case "host_load1", "host_load5", "host_load15":
|
|
return fmt.Sprintf("%.2f", metric.Value)
|
|
case "host_memory_total_bytes", "host_memory_free_bytes", "host_memory_available_bytes":
|
|
return formatBytes(metric.Value)
|
|
default:
|
|
return fmt.Sprintf("%.2f", metric.Value)
|
|
}
|
|
}
|
|
|
|
func formatBytes(bytes float64) string {
|
|
units := []string{"B", "KB", "MB", "GB", "TB"}
|
|
value := bytes
|
|
unit := 0
|
|
for value >= 1024 && unit < len(units)-1 {
|
|
value /= 1024
|
|
unit++
|
|
}
|
|
return fmt.Sprintf("%.2f %s", value, units[unit])
|
|
}
|
|
|