Files
checkcle/server/service-operation/uptime-monitoring/client.go
T
Tola Leng 933e70a3f6 feat: Implement comprehensive multi-channel notification system with templating and SSL monitoring
- Add robust notification system supporting 7+ communication channels with intelligent message templating, resource monitoring, and SSL certificate alerts. Notification Channels: (Telegram, Discord, Slack, Signal, Email, Google Chat, Webhooks).

- This notification system provides enterprise-grade alerting capabilities with extensive customization options and multi-channel redundancy for critical service monitoring.
2025-08-14 20:50:31 +07:00

113 lines
3.4 KiB
Go

package uptimemonitoring
import (
"encoding/json"
"fmt"
"net/http"
"time"
"service-operation/pocketbase"
)
// UptimeClient handles uptime service operations
type UptimeClient struct {
pbClient *pocketbase.PocketBaseClient
}
// MetricRecord represents a metric record from any collection
type MetricRecord struct {
ID string `json:"id"`
ServiceID string `json:"service_id"`
Status string `json:"status"`
ResponseTime int `json:"response_time"`
ErrorMessage string `json:"error_message"` // Added missing ErrorMessage field
Timestamp time.Time `json:"timestamp"`
Created time.Time `json:"created"`
}
// NewUptimeClient creates a new uptime client
func NewUptimeClient(pbClient *pocketbase.PocketBaseClient) *UptimeClient {
return &UptimeClient{
pbClient: pbClient,
}
}
// GetServices retrieves all services for monitoring
func (uc *UptimeClient) GetServices() ([]UptimeService, error) {
url := fmt.Sprintf("%s/api/collections/services/records", uc.pbClient.GetBaseURL())
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("failed to fetch services: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch services, status: %d", resp.StatusCode)
}
var response struct {
Items []UptimeService `json:"items"`
}
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, fmt.Errorf("failed to decode services: %v", err)
}
// log.Printf("✅ Fetched %d services for monitoring", len(response.Items))
return response.Items, nil
}
// GetLatestMetricRecord gets the latest metric record for a service from specified collection
func (uc *UptimeClient) GetLatestMetricRecord(serviceID, collection string) ([]MetricRecord, error) {
url := fmt.Sprintf("%s/api/collections/%s/records?filter=service_id='%s'&sort=-timestamp&perPage=1",
uc.pbClient.GetBaseURL(), collection, serviceID)
// log.Printf("🔍 [METRICS-QUERY] Getting latest record for service %s from %s", serviceID, collection)
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("failed to fetch metric record: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch metric record, status: %d", resp.StatusCode)
}
var response struct {
Items []struct {
ID string `json:"id"`
ServiceID string `json:"service_id"`
Status string `json:"status"`
ResponseTime int `json:"response_time"`
ErrorMessage string `json:"error_message"` // Added missing ErrorMessage field
Timestamp string `json:"timestamp"`
Created string `json:"created"`
} `json:"items"`
}
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, fmt.Errorf("failed to decode metric record: %v", err)
}
var records []MetricRecord
for _, item := range response.Items {
timestamp, _ := time.Parse(time.RFC3339, item.Timestamp)
created, _ := time.Parse(time.RFC3339, item.Created)
records = append(records, MetricRecord{
ID: item.ID,
ServiceID: item.ServiceID,
Status: item.Status,
ResponseTime: item.ResponseTime,
ErrorMessage: item.ErrorMessage, // Include ErrorMessage in the record
Timestamp: timestamp,
Created: created,
})
}
// log.Printf("📊 [METRICS-RESULT] Found %d records for service %s in %s", len(records), serviceID, collection)
return records, nil
}