mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-06-03 20:12:58 +00:00
small fix, don't worry about it
This commit is contained in:
@@ -1,473 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"containr/internal/deployment"
|
||||
)
|
||||
|
||||
// MetricsCollector collects and aggregates metrics from nodes and services
|
||||
type MetricsCollector struct {
|
||||
nodes map[string]*NodeMetrics
|
||||
services map[string]*ServiceMetrics
|
||||
scheduler *deployment.Scheduler
|
||||
mu sync.RWMutex
|
||||
collectInterval time.Duration
|
||||
storage MetricsStorage
|
||||
}
|
||||
|
||||
// NodeMetrics represents metrics for a node
|
||||
type NodeMetrics struct {
|
||||
NodeID string `json:"node_id"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
CPU CPUMetrics `json:"cpu"`
|
||||
Memory MemoryMetrics `json:"memory"`
|
||||
Storage StorageMetrics `json:"storage"`
|
||||
Network NetworkMetrics `json:"network"`
|
||||
Containers []ContainerMetrics `json:"containers"`
|
||||
System SystemMetrics `json:"system"`
|
||||
}
|
||||
|
||||
// ServiceMetrics represents metrics for a service
|
||||
type ServiceMetrics struct {
|
||||
ServiceID string `json:"service_id"`
|
||||
ServiceName string `json:"service_name"`
|
||||
ProjectID string `json:"project_id"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Instances []InstanceMetrics `json:"instances"`
|
||||
Requests RequestMetrics `json:"requests"`
|
||||
Errors ErrorMetrics `json:"errors"`
|
||||
Performance PerformanceMetrics `json:"performance"`
|
||||
Resources ResourceMetrics `json:"resources"`
|
||||
}
|
||||
|
||||
// InstanceMetrics represents metrics for a service instance
|
||||
type InstanceMetrics struct {
|
||||
InstanceID string `json:"instance_id"`
|
||||
NodeID string `json:"node_id"`
|
||||
Status string `json:"status"`
|
||||
CPU float64 `json:"cpu"` // CPU usage percentage
|
||||
Memory int64 `json:"memory"` // Memory usage in bytes
|
||||
Network NetworkMetrics `json:"network"`
|
||||
StartTime time.Time `json:"start_time"`
|
||||
LastSeen time.Time `json:"last_seen"`
|
||||
Health HealthMetrics `json:"health"`
|
||||
}
|
||||
|
||||
// CPUMetrics represents CPU metrics
|
||||
type CPUMetrics struct {
|
||||
UsagePercent float64 `json:"usage_percent"`
|
||||
UsageCores float64 `json:"usage_cores"`
|
||||
LoadAverage1 float64 `json:"load_average_1"`
|
||||
LoadAverage5 float64 `json:"load_average_5"`
|
||||
LoadAverage15 float64 `json:"load_average_15"`
|
||||
}
|
||||
|
||||
// MemoryMetrics represents memory metrics
|
||||
type MemoryMetrics struct {
|
||||
Total int64 `json:"total"`
|
||||
Used int64 `json:"used"`
|
||||
Available int64 `json:"available"`
|
||||
UsagePercent float64 `json:"usage_percent"`
|
||||
SwapTotal int64 `json:"swap_total"`
|
||||
SwapUsed int64 `json:"swap_used"`
|
||||
}
|
||||
|
||||
// StorageMetrics represents storage metrics
|
||||
type StorageMetrics struct {
|
||||
Total int64 `json:"total"`
|
||||
Used int64 `json:"used"`
|
||||
Available int64 `json:"available"`
|
||||
UsagePercent float64 `json:"usage_percent"`
|
||||
IOPS int64 `json:"iops"`
|
||||
Throughput int64 `json:"throughput"`
|
||||
}
|
||||
|
||||
// NetworkMetrics represents network metrics
|
||||
type NetworkMetrics struct {
|
||||
BytesIn int64 `json:"bytes_in"`
|
||||
BytesOut int64 `json:"bytes_out"`
|
||||
PacketsIn int64 `json:"packets_in"`
|
||||
PacketsOut int64 `json:"packets_out"`
|
||||
ConnectionsIn int64 `json:"connections_in"`
|
||||
ConnectionsOut int64 `json:"connections_out"`
|
||||
ErrorsIn int64 `json:"errors_in"`
|
||||
ErrorsOut int64 `json:"errors_out"`
|
||||
}
|
||||
|
||||
// ContainerMetrics represents metrics for containers
|
||||
type ContainerMetrics struct {
|
||||
ContainerID string `json:"container_id"`
|
||||
Name string `json:"name"`
|
||||
State string `json:"state"`
|
||||
CPU float64 `json:"cpu"`
|
||||
Memory int64 `json:"memory"`
|
||||
Network NetworkMetrics `json:"network"`
|
||||
StartTime time.Time `json:"start_time"`
|
||||
}
|
||||
|
||||
// SystemMetrics represents system-level metrics
|
||||
type SystemMetrics struct {
|
||||
Uptime time.Duration `json:"uptime"`
|
||||
Processes int `json:"processes"`
|
||||
OS string `json:"os"`
|
||||
Kernel string `json:"kernel"`
|
||||
Architecture string `json:"architecture"`
|
||||
}
|
||||
|
||||
// RequestMetrics represents HTTP/request metrics
|
||||
type RequestMetrics struct {
|
||||
Total int64 `json:"total"`
|
||||
Success int64 `json:"success"`
|
||||
Errors int64 `json:"errors"`
|
||||
AvgLatency float64 `json:"avg_latency"`
|
||||
P95Latency float64 `json:"p95_latency"`
|
||||
P99Latency float64 `json:"p99_latency"`
|
||||
Throughput float64 `json:"throughput"`
|
||||
}
|
||||
|
||||
// ErrorMetrics represents error metrics
|
||||
type ErrorMetrics struct {
|
||||
Total int64 `json:"total"`
|
||||
ByType map[string]int64 `json:"by_type"`
|
||||
ByStatusCode map[string]int64 `json:"by_status_code"`
|
||||
Rate float64 `json:"rate"`
|
||||
}
|
||||
|
||||
// PerformanceMetrics represents performance metrics
|
||||
type PerformanceMetrics struct {
|
||||
ResponseTime float64 `json:"response_time"`
|
||||
Throughput float64 `json:"throughput"`
|
||||
Concurrency int64 `json:"concurrency"`
|
||||
Saturation float64 `json:"saturation"`
|
||||
Utilization float64 `json:"utilization"`
|
||||
}
|
||||
|
||||
// ResourceMetrics represents resource utilization metrics
|
||||
type ResourceMetrics struct {
|
||||
CPUUsage float64 `json:"cpu_usage"`
|
||||
MemoryUsage int64 `json:"memory_usage"`
|
||||
StorageUsage int64 `json:"storage_usage"`
|
||||
NetworkUsage int64 `json:"network_usage"`
|
||||
ResourceScore float64 `json:"resource_score"`
|
||||
}
|
||||
|
||||
// HealthMetrics represents health metrics
|
||||
type HealthMetrics struct {
|
||||
Status string `json:"status"`
|
||||
LastCheck time.Time `json:"last_check"`
|
||||
CheckCount int `json:"check_count"`
|
||||
FailureCount int `json:"failure_count"`
|
||||
Uptime time.Duration `json:"uptime"`
|
||||
}
|
||||
|
||||
// MetricsStorage defines the interface for metrics storage
|
||||
type MetricsStorage interface {
|
||||
StoreNodeMetrics(ctx context.Context, metrics *NodeMetrics) error
|
||||
StoreServiceMetrics(ctx context.Context, metrics *ServiceMetrics) error
|
||||
GetNodeMetrics(ctx context.Context, nodeID string, from, to time.Time) ([]*NodeMetrics, error)
|
||||
GetServiceMetrics(ctx context.Context, serviceID string, from, to time.Time) ([]*ServiceMetrics, error)
|
||||
GetAggregatedMetrics(ctx context.Context, query MetricsQuery) (*AggregatedMetrics, error)
|
||||
}
|
||||
|
||||
// MetricsQuery represents a query for aggregated metrics
|
||||
type MetricsQuery struct {
|
||||
Type string `json:"type"` // node, service, project
|
||||
ID string `json:"id"` // node_id, service_id, project_id
|
||||
Metrics []string `json:"metrics"` // cpu, memory, network, etc.
|
||||
From time.Time `json:"from"`
|
||||
To time.Time `json:"to"`
|
||||
Interval time.Duration `json:"interval"`
|
||||
GroupBy []string `json:"group_by"`
|
||||
Filters map[string]string `json:"filters"`
|
||||
}
|
||||
|
||||
// AggregatedMetrics represents aggregated metrics data
|
||||
type AggregatedMetrics struct {
|
||||
Query MetricsQuery `json:"query"`
|
||||
TimeSeries []TimeSeriesPoint `json:"time_series"`
|
||||
Summary map[string]MetricSummary `json:"summary"`
|
||||
}
|
||||
|
||||
// TimeSeriesPoint represents a point in a time series
|
||||
type TimeSeriesPoint struct {
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Values map[string]float64 `json:"values"`
|
||||
}
|
||||
|
||||
// MetricSummary represents summary statistics for a metric
|
||||
type MetricSummary struct {
|
||||
Min float64 `json:"min"`
|
||||
Max float64 `json:"max"`
|
||||
Avg float64 `json:"avg"`
|
||||
P50 float64 `json:"p50"`
|
||||
P95 float64 `json:"p95"`
|
||||
P99 float64 `json:"p99"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
// NewMetricsCollector creates a new metrics collector
|
||||
func NewMetricsCollector(scheduler *deployment.Scheduler, storage MetricsStorage) *MetricsCollector {
|
||||
return &MetricsCollector{
|
||||
nodes: make(map[string]*NodeMetrics),
|
||||
services: make(map[string]*ServiceMetrics),
|
||||
scheduler: scheduler,
|
||||
collectInterval: 30 * time.Second,
|
||||
storage: storage,
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts the metrics collection process
|
||||
func (mc *MetricsCollector) Start(ctx context.Context) error {
|
||||
ticker := time.NewTicker(mc.collectInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-ticker.C:
|
||||
if err := mc.collectMetrics(ctx); err != nil {
|
||||
fmt.Printf("Error collecting metrics: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// collectMetrics collects metrics from all nodes and services
|
||||
func (mc *MetricsCollector) collectMetrics(ctx context.Context) error {
|
||||
// Collect node metrics
|
||||
nodes := mc.scheduler.GetNodes()
|
||||
for _, node := range nodes {
|
||||
metrics, err := mc.collectNodeMetrics(ctx, node)
|
||||
if err != nil {
|
||||
fmt.Printf("Error collecting metrics for node %s: %v\n", node.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
mc.mu.Lock()
|
||||
mc.nodes[node.ID] = metrics
|
||||
mc.mu.Unlock()
|
||||
|
||||
// Store metrics
|
||||
if err := mc.storage.StoreNodeMetrics(ctx, metrics); err != nil {
|
||||
fmt.Printf("Error storing node metrics: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Collect service metrics
|
||||
// This would involve querying service instances and collecting their metrics
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// collectNodeMetrics collects metrics from a specific node
|
||||
func (mc *MetricsCollector) collectNodeMetrics(ctx context.Context, node *deployment.Node) (*NodeMetrics, error) {
|
||||
// In a real implementation, this would collect actual metrics from the node
|
||||
// For now, we'll simulate metrics collection
|
||||
now := time.Now()
|
||||
|
||||
metrics := &NodeMetrics{
|
||||
NodeID: node.ID,
|
||||
Timestamp: now,
|
||||
CPU: CPUMetrics{
|
||||
UsagePercent: node.Usage.CPU,
|
||||
UsageCores: node.Usage.CPU * float64(node.Capacity.CPU) / 100,
|
||||
LoadAverage1: 1.5,
|
||||
LoadAverage5: 1.8,
|
||||
LoadAverage15: 2.1,
|
||||
},
|
||||
Memory: MemoryMetrics{
|
||||
Total: node.Capacity.Memory,
|
||||
Used: node.Usage.Memory,
|
||||
Available: node.Capacity.Memory - node.Usage.Memory,
|
||||
UsagePercent: float64(node.Usage.Memory) / float64(node.Capacity.Memory) * 100,
|
||||
SwapTotal: 1024 * 1024 * 1024, // 1GB
|
||||
SwapUsed: 512 * 1024 * 1024, // 512MB
|
||||
},
|
||||
Storage: StorageMetrics{
|
||||
Total: node.Capacity.Storage,
|
||||
Used: node.Usage.Storage,
|
||||
Available: node.Capacity.Storage - node.Usage.Storage,
|
||||
UsagePercent: float64(node.Usage.Storage) / float64(node.Capacity.Storage) * 100,
|
||||
IOPS: 1000,
|
||||
Throughput: 1024 * 1024 * 100, // 100MB/s
|
||||
},
|
||||
Network: NetworkMetrics{
|
||||
BytesIn: node.Usage.Network,
|
||||
BytesOut: node.Usage.Network,
|
||||
PacketsIn: 10000,
|
||||
PacketsOut: 8000,
|
||||
ConnectionsIn: 50,
|
||||
ConnectionsOut: 30,
|
||||
ErrorsIn: 0,
|
||||
ErrorsOut: 0,
|
||||
},
|
||||
Containers: []ContainerMetrics{},
|
||||
System: SystemMetrics{
|
||||
Uptime: time.Since(node.LastHeartbeat),
|
||||
Processes: 150,
|
||||
OS: "linux",
|
||||
Kernel: "5.15.0",
|
||||
Architecture: "x86_64",
|
||||
},
|
||||
}
|
||||
|
||||
// Collect container metrics for this node
|
||||
for _, containerID := range node.Containers {
|
||||
containerMetrics := mc.collectContainerMetrics(containerID)
|
||||
metrics.Containers = append(metrics.Containers, containerMetrics)
|
||||
}
|
||||
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
// collectContainerMetrics collects metrics for a specific container
|
||||
func (mc *MetricsCollector) collectContainerMetrics(containerID string) ContainerMetrics {
|
||||
// In a real implementation, this would query Docker/container runtime
|
||||
return ContainerMetrics{
|
||||
ContainerID: containerID,
|
||||
Name: fmt.Sprintf("container-%s", containerID[:8]),
|
||||
State: "running",
|
||||
CPU: 25.5,
|
||||
Memory: 512 * 1024 * 1024, // 512MB
|
||||
Network: NetworkMetrics{
|
||||
BytesIn: 1024 * 1024 * 10, // 10MB
|
||||
BytesOut: 1024 * 1024 * 8, // 8MB
|
||||
PacketsIn: 1000,
|
||||
PacketsOut: 800,
|
||||
},
|
||||
StartTime: time.Now().Add(-1 * time.Hour),
|
||||
}
|
||||
}
|
||||
|
||||
// GetNodeMetrics returns the latest metrics for a node
|
||||
func (mc *MetricsCollector) GetNodeMetrics(nodeID string) (*NodeMetrics, error) {
|
||||
mc.mu.RLock()
|
||||
defer mc.mu.RUnlock()
|
||||
|
||||
metrics, exists := mc.nodes[nodeID]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("no metrics found for node: %s", nodeID)
|
||||
}
|
||||
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
// GetAllNodeMetrics returns metrics for all nodes
|
||||
func (mc *MetricsCollector) GetAllNodeMetrics() map[string]*NodeMetrics {
|
||||
mc.mu.RLock()
|
||||
defer mc.mu.RUnlock()
|
||||
|
||||
// Return a copy to avoid race conditions
|
||||
result := make(map[string]*NodeMetrics)
|
||||
for id, metrics := range mc.nodes {
|
||||
result[id] = metrics
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// GetServiceMetrics returns the latest metrics for a service
|
||||
func (mc *MetricsCollector) GetServiceMetrics(serviceID string) (*ServiceMetrics, error) {
|
||||
mc.mu.RLock()
|
||||
defer mc.mu.RUnlock()
|
||||
|
||||
metrics, exists := mc.services[serviceID]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("no metrics found for service: %s", serviceID)
|
||||
}
|
||||
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
// GetAggregatedMetrics returns aggregated metrics based on a query
|
||||
func (mc *MetricsCollector) GetAggregatedMetrics(ctx context.Context, query MetricsQuery) (*AggregatedMetrics, error) {
|
||||
return mc.storage.GetAggregatedMetrics(ctx, query)
|
||||
}
|
||||
|
||||
// GetMetricsSummary returns a summary of all metrics
|
||||
func (mc *MetricsCollector) GetMetricsSummary() map[string]interface{} {
|
||||
mc.mu.RLock()
|
||||
defer mc.mu.RUnlock()
|
||||
|
||||
totalNodes := len(mc.nodes)
|
||||
totalServices := len(mc.services)
|
||||
healthyNodes := 0
|
||||
totalCPU := 0.0
|
||||
totalMemory := int64(0)
|
||||
|
||||
for _, metrics := range mc.nodes {
|
||||
if metrics.CPU.UsagePercent < 80 {
|
||||
healthyNodes++
|
||||
}
|
||||
totalCPU += metrics.CPU.UsagePercent
|
||||
totalMemory += metrics.Memory.Used
|
||||
}
|
||||
|
||||
avgCPU := float64(0)
|
||||
if totalNodes > 0 {
|
||||
avgCPU = totalCPU / float64(totalNodes)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"total_nodes": totalNodes,
|
||||
"healthy_nodes": healthyNodes,
|
||||
"total_services": totalServices,
|
||||
"avg_cpu_usage": avgCPU,
|
||||
"total_memory": totalMemory,
|
||||
"collect_interval": mc.collectInterval.String(),
|
||||
"last_collection": time.Now().Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
// ExportMetrics exports metrics in various formats
|
||||
func (mc *MetricsCollector) ExportMetrics(format string) ([]byte, error) {
|
||||
mc.mu.RLock()
|
||||
defer mc.mu.RUnlock()
|
||||
|
||||
data := map[string]interface{}{
|
||||
"nodes": mc.nodes,
|
||||
"services": mc.services,
|
||||
"timestamp": time.Now(),
|
||||
}
|
||||
|
||||
switch format {
|
||||
case "json":
|
||||
return json.MarshalIndent(data, "", " ")
|
||||
case "prometheus":
|
||||
return mc.exportPrometheusFormat()
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported export format: %s", format)
|
||||
}
|
||||
}
|
||||
|
||||
// exportPrometheusFormat exports metrics in Prometheus format
|
||||
func (mc *MetricsCollector) exportPrometheusFormat() ([]byte, error) {
|
||||
var output []string
|
||||
|
||||
for nodeID, metrics := range mc.nodes {
|
||||
// Node CPU metrics
|
||||
output = append(output, fmt.Sprintf("# HELP node_cpu_usage_percent CPU usage percentage for node"))
|
||||
output = append(output, fmt.Sprintf("# TYPE node_cpu_usage_percent gauge"))
|
||||
output = append(output, fmt.Sprintf("node_cpu_usage_percent{node=\"%s\"} %f", nodeID, metrics.CPU.UsagePercent))
|
||||
|
||||
// Node memory metrics
|
||||
output = append(output, fmt.Sprintf("# HELP node_memory_usage_bytes Memory usage in bytes for node"))
|
||||
output = append(output, fmt.Sprintf("# TYPE node_memory_usage_bytes gauge"))
|
||||
output = append(output, fmt.Sprintf("node_memory_usage_bytes{node=\"%s\"} %d", nodeID, metrics.Memory.Used))
|
||||
|
||||
// Node network metrics
|
||||
output = append(output, fmt.Sprintf("# HELP node_network_bytes_in Total bytes received for node"))
|
||||
output = append(output, fmt.Sprintf("# TYPE node_network_bytes_in counter"))
|
||||
output = append(output, fmt.Sprintf("node_network_bytes_in{node=\"%s\"} %d", nodeID, metrics.Network.BytesIn))
|
||||
}
|
||||
|
||||
result := []byte(strings.Join(output, "\n"))
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,553 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
// PostgreSQLMetricsStorage implements MetricsStorage using PostgreSQL
|
||||
type PostgreSQLMetricsStorage struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// NewPostgreSQLMetricsStorage creates a new PostgreSQL metrics storage
|
||||
func NewPostgreSQLMetricsStorage(db *sql.DB) *PostgreSQLMetricsStorage {
|
||||
return &PostgreSQLMetricsStorage{db: db}
|
||||
}
|
||||
|
||||
// StoreNodeMetrics stores node metrics in the database
|
||||
func (s *PostgreSQLMetricsStorage) StoreNodeMetrics(ctx context.Context, metrics *NodeMetrics) error {
|
||||
query := `
|
||||
INSERT INTO node_metrics (
|
||||
node_id, timestamp, cpu_usage, cpu_cores, load_avg_1, load_avg_5, load_avg_15,
|
||||
memory_total, memory_used, memory_available, memory_usage_percent,
|
||||
storage_total, storage_used, storage_available, storage_usage_percent,
|
||||
network_bytes_in, network_bytes_out, network_packets_in, network_packets_out,
|
||||
network_connections_in, network_connections_out, network_errors_in, network_errors_out,
|
||||
uptime, processes, os, kernel, architecture
|
||||
) VALUES ($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)
|
||||
ON CONFLICT (node_id, timestamp) DO UPDATE SET
|
||||
cpu_usage = EXCLUDED.cpu_usage,
|
||||
cpu_cores = EXCLUDED.cpu_cores,
|
||||
load_avg_1 = EXCLUDED.load_avg_1,
|
||||
load_avg_5 = EXCLUDED.load_avg_5,
|
||||
load_avg_15 = EXCLUDED.load_avg_15,
|
||||
memory_total = EXCLUDED.memory_total,
|
||||
memory_used = EXCLUDED.memory_used,
|
||||
memory_available = EXCLUDED.memory_available,
|
||||
memory_usage_percent = EXCLUDED.memory_usage_percent,
|
||||
storage_total = EXCLUDED.storage_total,
|
||||
storage_used = EXCLUDED.storage_used,
|
||||
storage_available = EXCLUDED.storage_available,
|
||||
storage_usage_percent = EXCLUDED.storage_usage_percent,
|
||||
network_bytes_in = EXCLUDED.network_bytes_in,
|
||||
network_bytes_out = EXCLUDED.network_bytes_out,
|
||||
network_packets_in = EXCLUDED.network_packets_in,
|
||||
network_packets_out = EXCLUDED.network_packets_out,
|
||||
network_connections_in = EXCLUDED.network_connections_in,
|
||||
network_connections_out = EXCLUDED.network_connections_out,
|
||||
network_errors_in = EXCLUDED.network_errors_in,
|
||||
network_errors_out = EXCLUDED.network_errors_out,
|
||||
uptime = EXCLUDED.uptime,
|
||||
processes = EXCLUDED.processes,
|
||||
os = EXCLUDED.os,
|
||||
kernel = EXCLUDED.kernel,
|
||||
architecture = EXCLUDED.architecture
|
||||
`
|
||||
|
||||
_, err := s.db.ExecContext(ctx, query,
|
||||
metrics.NodeID, metrics.Timestamp, metrics.CPU.UsagePercent, metrics.CPU.UsageCores,
|
||||
metrics.CPU.LoadAverage1, metrics.CPU.LoadAverage5, metrics.CPU.LoadAverage15,
|
||||
metrics.Memory.Total, metrics.Memory.Used, metrics.Memory.Available, metrics.Memory.UsagePercent,
|
||||
metrics.Storage.Total, metrics.Storage.Used, metrics.Storage.Available, metrics.Storage.UsagePercent,
|
||||
metrics.Network.BytesIn, metrics.Network.BytesOut, metrics.Network.PacketsIn, metrics.Network.PacketsOut,
|
||||
metrics.Network.ConnectionsIn, metrics.Network.ConnectionsOut, metrics.Network.ErrorsIn, metrics.Network.ErrorsOut,
|
||||
metrics.System.Uptime, metrics.System.Processes, metrics.System.OS, metrics.System.Kernel, metrics.System.Architecture,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to store node metrics: %w", err)
|
||||
}
|
||||
|
||||
// Store container metrics
|
||||
for _, container := range metrics.Containers {
|
||||
if err := s.storeContainerMetrics(ctx, metrics.NodeID, metrics.Timestamp, container); err != nil {
|
||||
return fmt.Errorf("failed to store container metrics: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StoreServiceMetrics stores service metrics in the database
|
||||
func (s *PostgreSQLMetricsStorage) StoreServiceMetrics(ctx context.Context, metrics *ServiceMetrics) error {
|
||||
query := `
|
||||
INSERT INTO service_metrics (
|
||||
service_id, service_name, project_id, timestamp,
|
||||
requests_total, requests_success, requests_errors, requests_avg_latency,
|
||||
requests_p95_latency, requests_p99_latency, requests_throughput,
|
||||
errors_total, errors_rate, performance_response_time, performance_throughput,
|
||||
performance_concurrency, performance_saturation, performance_utilization,
|
||||
resource_cpu_usage, resource_memory_usage, resource_storage_usage,
|
||||
resource_network_usage, resource_score
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)
|
||||
ON CONFLICT (service_id, timestamp) DO UPDATE SET
|
||||
requests_total = EXCLUDED.requests_total,
|
||||
requests_success = EXCLUDED.requests_success,
|
||||
requests_errors = EXCLUDED.requests_errors,
|
||||
requests_avg_latency = EXCLUDED.requests_avg_latency,
|
||||
requests_p95_latency = EXCLUDED.requests_p95_latency,
|
||||
requests_p99_latency = EXCLUDED.requests_p99_latency,
|
||||
requests_throughput = EXCLUDED.requests_throughput,
|
||||
errors_total = EXCLUDED.errors_total,
|
||||
errors_rate = EXCLUDED.errors_rate,
|
||||
performance_response_time = EXCLUDED.performance_response_time,
|
||||
performance_throughput = EXCLUDED.performance_throughput,
|
||||
performance_concurrency = EXCLUDED.performance_concurrency,
|
||||
performance_saturation = EXCLUDED.performance_saturation,
|
||||
performance_utilization = EXCLUDED.performance_utilization,
|
||||
resource_cpu_usage = EXCLUDED.resource_cpu_usage,
|
||||
resource_memory_usage = EXCLUDED.resource_memory_usage,
|
||||
resource_storage_usage = EXCLUDED.resource_storage_usage,
|
||||
resource_network_usage = EXCLUDED.resource_network_usage,
|
||||
resource_score = EXCLUDED.resource_score
|
||||
`
|
||||
|
||||
_, err := s.db.ExecContext(ctx, query,
|
||||
metrics.ServiceID, metrics.ServiceName, metrics.ProjectID, metrics.Timestamp,
|
||||
metrics.Requests.Total, metrics.Requests.Success, metrics.Requests.Errors,
|
||||
metrics.Requests.AvgLatency, metrics.Requests.P95Latency, metrics.Requests.P99Latency,
|
||||
metrics.Requests.Throughput, metrics.Errors.Total, metrics.Errors.Rate,
|
||||
metrics.Performance.ResponseTime, metrics.Performance.Throughput,
|
||||
metrics.Performance.Concurrency, metrics.Performance.Saturation, metrics.Performance.Utilization,
|
||||
metrics.Resources.CPUUsage, metrics.Resources.MemoryUsage, metrics.Resources.StorageUsage,
|
||||
metrics.Resources.NetworkUsage, metrics.Resources.ResourceScore,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to store service metrics: %w", err)
|
||||
}
|
||||
|
||||
// Store instance metrics
|
||||
for _, instance := range metrics.Instances {
|
||||
if err := s.storeInstanceMetrics(ctx, metrics.ServiceID, metrics.Timestamp, instance); err != nil {
|
||||
return fmt.Errorf("failed to store instance metrics: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetNodeMetrics retrieves node metrics from the database
|
||||
func (s *PostgreSQLMetricsStorage) GetNodeMetrics(ctx context.Context, nodeID string, from, to time.Time) ([]*NodeMetrics, error) {
|
||||
query := `
|
||||
SELECT node_id, timestamp, cpu_usage, cpu_cores, load_avg_1, load_avg_5, load_avg_15,
|
||||
memory_total, memory_used, memory_available, memory_usage_percent,
|
||||
storage_total, storage_used, storage_available, storage_usage_percent,
|
||||
network_bytes_in, network_bytes_out, network_packets_in, network_packets_out,
|
||||
network_connections_in, network_connections_out, network_errors_in, network_errors_out,
|
||||
uptime, processes, os, kernel, architecture
|
||||
FROM node_metrics
|
||||
WHERE node_id = $1 AND timestamp BETWEEN $2 AND $3
|
||||
ORDER BY timestamp ASC
|
||||
`
|
||||
|
||||
rows, err := s.db.QueryContext(ctx, query, nodeID, from, to)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query node metrics: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var metrics []*NodeMetrics
|
||||
for rows.Next() {
|
||||
var m NodeMetrics
|
||||
err := rows.Scan(
|
||||
&m.NodeID, &m.Timestamp, &m.CPU.UsagePercent, &m.CPU.UsageCores,
|
||||
&m.CPU.LoadAverage1, &m.CPU.LoadAverage5, &m.CPU.LoadAverage15,
|
||||
&m.Memory.Total, &m.Memory.Used, &m.Memory.Available, &m.Memory.UsagePercent,
|
||||
&m.Storage.Total, &m.Storage.Used, &m.Storage.Available, &m.Storage.UsagePercent,
|
||||
&m.Network.BytesIn, &m.Network.BytesOut, &m.Network.PacketsIn, &m.Network.PacketsOut,
|
||||
&m.Network.ConnectionsIn, &m.Network.ConnectionsOut, &m.Network.ErrorsIn, &m.Network.ErrorsOut,
|
||||
&m.System.Uptime, &m.System.Processes, &m.System.OS, &m.System.Kernel, &m.System.Architecture,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to scan node metrics: %w", err)
|
||||
}
|
||||
|
||||
// Get container metrics for this timestamp
|
||||
containers, err := s.getContainerMetrics(ctx, nodeID, m.Timestamp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get container metrics: %w", err)
|
||||
}
|
||||
m.Containers = containers
|
||||
|
||||
metrics = append(metrics, &m)
|
||||
}
|
||||
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
// GetServiceMetrics retrieves service metrics from the database
|
||||
func (s *PostgreSQLMetricsStorage) GetServiceMetrics(ctx context.Context, serviceID string, from, to time.Time) ([]*ServiceMetrics, error) {
|
||||
query := `
|
||||
SELECT service_id, service_name, project_id, timestamp,
|
||||
requests_total, requests_success, requests_errors, requests_avg_latency,
|
||||
requests_p95_latency, requests_p99_latency, requests_throughput,
|
||||
errors_total, errors_rate, performance_response_time, performance_throughput,
|
||||
performance_concurrency, performance_saturation, performance_utilization,
|
||||
resource_cpu_usage, resource_memory_usage, resource_storage_usage,
|
||||
resource_network_usage, resource_score
|
||||
FROM service_metrics
|
||||
WHERE service_id = $1 AND timestamp BETWEEN $2 AND $3
|
||||
ORDER BY timestamp ASC
|
||||
`
|
||||
|
||||
rows, err := s.db.QueryContext(ctx, query, serviceID, from, to)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query service metrics: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var metrics []*ServiceMetrics
|
||||
for rows.Next() {
|
||||
var m ServiceMetrics
|
||||
err := rows.Scan(
|
||||
&m.ServiceID, &m.ServiceName, &m.ProjectID, &m.Timestamp,
|
||||
&m.Requests.Total, &m.Requests.Success, &m.Requests.Errors,
|
||||
&m.Requests.AvgLatency, &m.Requests.P95Latency, &m.Requests.P99Latency,
|
||||
&m.Requests.Throughput, &m.Errors.Total, &m.Errors.Rate,
|
||||
&m.Performance.ResponseTime, &m.Performance.Throughput,
|
||||
&m.Performance.Concurrency, &m.Performance.Saturation, &m.Performance.Utilization,
|
||||
&m.Resources.CPUUsage, &m.Resources.MemoryUsage, &m.Resources.StorageUsage,
|
||||
&m.Resources.NetworkUsage, &m.Resources.ResourceScore,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to scan service metrics: %w", err)
|
||||
}
|
||||
|
||||
// Get instance metrics for this timestamp
|
||||
instances, err := s.getInstanceMetrics(ctx, serviceID, m.Timestamp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get instance metrics: %w", err)
|
||||
}
|
||||
m.Instances = instances
|
||||
|
||||
metrics = append(metrics, &m)
|
||||
}
|
||||
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
// GetAggregatedMetrics retrieves aggregated metrics based on a query
|
||||
func (s *PostgreSQLMetricsStorage) GetAggregatedMetrics(ctx context.Context, query MetricsQuery) (*AggregatedMetrics, error) {
|
||||
// This is a simplified implementation
|
||||
// In a real system, you'd build dynamic SQL based on the query
|
||||
|
||||
var timeSeries []TimeSeriesPoint
|
||||
var summary map[string]MetricSummary
|
||||
|
||||
switch query.Type {
|
||||
case "node":
|
||||
// Aggregate node metrics
|
||||
nodeQuery := `
|
||||
SELECT
|
||||
time_bucket($1, timestamp) AS bucket,
|
||||
AVG(cpu_usage) as avg_cpu,
|
||||
AVG(memory_usage_percent) as avg_memory,
|
||||
AVG(storage_usage_percent) as avg_storage
|
||||
FROM node_metrics
|
||||
WHERE node_id = $2 AND timestamp BETWEEN $3 AND $4
|
||||
GROUP BY bucket
|
||||
ORDER BY bucket ASC
|
||||
`
|
||||
|
||||
rows, err := s.db.QueryContext(ctx, nodeQuery, query.Interval, query.ID, query.From, query.To)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query aggregated node metrics: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var bucket time.Time
|
||||
var avgCPU, avgMemory, avgStorage float64
|
||||
if err := rows.Scan(&bucket, &avgCPU, &avgMemory, &avgStorage); err != nil {
|
||||
return nil, fmt.Errorf("failed to scan aggregated metrics: %w", err)
|
||||
}
|
||||
|
||||
point := TimeSeriesPoint{
|
||||
Timestamp: bucket,
|
||||
Values: map[string]float64{
|
||||
"cpu_usage": avgCPU,
|
||||
"memory_usage": avgMemory,
|
||||
"storage_usage": avgStorage,
|
||||
},
|
||||
}
|
||||
timeSeries = append(timeSeries, point)
|
||||
}
|
||||
|
||||
// Calculate summary statistics
|
||||
summary = map[string]MetricSummary{
|
||||
"cpu_usage": calculateSummary(timeSeries, "cpu_usage"),
|
||||
"memory_usage": calculateSummary(timeSeries, "memory_usage"),
|
||||
"storage_usage": calculateSummary(timeSeries, "storage_usage"),
|
||||
}
|
||||
}
|
||||
|
||||
return &AggregatedMetrics{
|
||||
Query: query,
|
||||
TimeSeries: timeSeries,
|
||||
Summary: summary,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
func (s *PostgreSQLMetricsStorage) storeContainerMetrics(ctx context.Context, nodeID string, timestamp time.Time, container ContainerMetrics) error {
|
||||
query := `
|
||||
INSERT INTO container_metrics (
|
||||
node_id, timestamp, container_id, name, state, cpu, memory,
|
||||
network_bytes_in, network_bytes_out, network_packets_in, network_packets_out, start_time
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
||||
ON CONFLICT (node_id, timestamp, container_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
state = EXCLUDED.state,
|
||||
cpu = EXCLUDED.cpu,
|
||||
memory = EXCLUDED.memory,
|
||||
network_bytes_in = EXCLUDED.network_bytes_in,
|
||||
network_bytes_out = EXCLUDED.network_bytes_out,
|
||||
network_packets_in = EXCLUDED.network_packets_in,
|
||||
network_packets_out = EXCLUDED.network_packets_out,
|
||||
start_time = EXCLUDED.start_time
|
||||
`
|
||||
|
||||
_, err := s.db.ExecContext(ctx, query,
|
||||
nodeID, timestamp, container.ContainerID, container.Name, container.State,
|
||||
container.CPU, container.Memory, container.Network.BytesIn, container.Network.BytesOut,
|
||||
container.Network.PacketsIn, container.Network.PacketsOut, container.StartTime,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PostgreSQLMetricsStorage) storeInstanceMetrics(ctx context.Context, serviceID string, timestamp time.Time, instance InstanceMetrics) error {
|
||||
query := `
|
||||
INSERT INTO instance_metrics (
|
||||
service_id, timestamp, instance_id, node_id, status, cpu, memory,
|
||||
network_bytes_in, network_bytes_out, network_packets_in, network_packets_out,
|
||||
network_connections_in, network_connections_out, network_errors_in, network_errors_out,
|
||||
start_time, last_seen, health_status, health_last_check, health_check_count, health_failure_count
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)
|
||||
ON CONFLICT (service_id, timestamp, instance_id) DO UPDATE SET
|
||||
node_id = EXCLUDED.node_id,
|
||||
status = EXCLUDED.status,
|
||||
cpu = EXCLUDED.cpu,
|
||||
memory = EXCLUDED.memory,
|
||||
network_bytes_in = EXCLUDED.network_bytes_in,
|
||||
network_bytes_out = EXCLUDED.network_bytes_out,
|
||||
network_packets_in = EXCLUDED.network_packets_in,
|
||||
network_packets_out = EXCLUDED.network_packets_out,
|
||||
network_connections_in = EXCLUDED.network_connections_in,
|
||||
network_connections_out = EXCLUDED.network_connections_out,
|
||||
network_errors_in = EXCLUDED.network_errors_in,
|
||||
network_errors_out = EXCLUDED.network_errors_out,
|
||||
start_time = EXCLUDED.start_time,
|
||||
last_seen = EXCLUDED.last_seen,
|
||||
health_status = EXCLUDED.health_status,
|
||||
health_last_check = EXCLUDED.health_last_check,
|
||||
health_check_count = EXCLUDED.health_check_count,
|
||||
health_failure_count = EXCLUDED.health_failure_count
|
||||
`
|
||||
|
||||
_, err := s.db.ExecContext(ctx, query,
|
||||
serviceID, timestamp, instance.InstanceID, instance.NodeID, instance.Status,
|
||||
instance.CPU, instance.Memory, instance.Network.BytesIn, instance.Network.BytesOut,
|
||||
instance.Network.PacketsIn, instance.Network.PacketsOut, instance.Network.ConnectionsIn,
|
||||
instance.Network.ConnectionsOut, instance.Network.ErrorsIn, instance.Network.ErrorsOut,
|
||||
instance.StartTime, instance.LastSeen, instance.Health.Status, instance.Health.LastCheck,
|
||||
instance.Health.CheckCount, instance.Health.FailureCount,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PostgreSQLMetricsStorage) getContainerMetrics(ctx context.Context, nodeID string, timestamp time.Time) ([]ContainerMetrics, error) {
|
||||
query := `
|
||||
SELECT container_id, name, state, cpu, memory,
|
||||
network_bytes_in, network_bytes_out, network_packets_in, network_packets_out, start_time
|
||||
FROM container_metrics
|
||||
WHERE node_id = $1 AND timestamp = $2
|
||||
`
|
||||
|
||||
rows, err := s.db.QueryContext(ctx, query, nodeID, timestamp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var containers []ContainerMetrics
|
||||
for rows.Next() {
|
||||
var c ContainerMetrics
|
||||
err := rows.Scan(
|
||||
&c.ContainerID, &c.Name, &c.State, &c.CPU, &c.Memory,
|
||||
&c.Network.BytesIn, &c.Network.BytesOut, &c.Network.PacketsIn, &c.Network.PacketsOut, &c.StartTime,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containers = append(containers, c)
|
||||
}
|
||||
|
||||
return containers, nil
|
||||
}
|
||||
|
||||
func (s *PostgreSQLMetricsStorage) getInstanceMetrics(ctx context.Context, serviceID string, timestamp time.Time) ([]InstanceMetrics, error) {
|
||||
query := `
|
||||
SELECT instance_id, node_id, status, cpu, memory,
|
||||
network_bytes_in, network_bytes_out, network_packets_in, network_packets_out,
|
||||
network_connections_in, network_connections_out, network_errors_in, network_errors_out,
|
||||
start_time, last_seen, health_status, health_last_check, health_check_count, health_failure_count
|
||||
FROM instance_metrics
|
||||
WHERE service_id = $1 AND timestamp = $2
|
||||
`
|
||||
|
||||
rows, err := s.db.QueryContext(ctx, query, serviceID, timestamp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var instances []InstanceMetrics
|
||||
for rows.Next() {
|
||||
var i InstanceMetrics
|
||||
err := rows.Scan(
|
||||
&i.InstanceID, &i.NodeID, &i.Status, &i.CPU, &i.Memory,
|
||||
&i.Network.BytesIn, &i.Network.BytesOut, &i.Network.PacketsIn, &i.Network.PacketsOut,
|
||||
&i.Network.ConnectionsIn, &i.Network.ConnectionsOut, &i.Network.ErrorsIn, &i.Network.ErrorsOut,
|
||||
&i.StartTime, &i.LastSeen, &i.Health.Status, &i.Health.LastCheck, &i.Health.CheckCount, &i.Health.FailureCount,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instances = append(instances, i)
|
||||
}
|
||||
|
||||
return instances, nil
|
||||
}
|
||||
|
||||
func calculateSummary(timeSeries []TimeSeriesPoint, metricName string) MetricSummary {
|
||||
if len(timeSeries) == 0 {
|
||||
return MetricSummary{}
|
||||
}
|
||||
|
||||
var values []float64
|
||||
for _, point := range timeSeries {
|
||||
if val, exists := point.Values[metricName]; exists {
|
||||
values = append(values, val)
|
||||
}
|
||||
}
|
||||
|
||||
if len(values) == 0 {
|
||||
return MetricSummary{}
|
||||
}
|
||||
|
||||
// Simple calculation - in production, use proper statistics
|
||||
min := values[0]
|
||||
max := values[0]
|
||||
sum := 0.0
|
||||
|
||||
for _, val := range values {
|
||||
if val < min {
|
||||
min = val
|
||||
}
|
||||
if val > max {
|
||||
max = val
|
||||
}
|
||||
sum += val
|
||||
}
|
||||
|
||||
avg := sum / float64(len(values))
|
||||
|
||||
return MetricSummary{
|
||||
Min: min,
|
||||
Max: max,
|
||||
Avg: avg,
|
||||
Count: int64(len(values)),
|
||||
// P50, P95, P99 would require sorting and percentile calculation
|
||||
P50: avg,
|
||||
P95: avg,
|
||||
P99: avg,
|
||||
}
|
||||
}
|
||||
|
||||
// InMemoryMetricsStorage provides an in-memory implementation for testing
|
||||
type InMemoryMetricsStorage struct {
|
||||
nodeMetrics map[string][]*NodeMetrics
|
||||
serviceMetrics map[string][]*ServiceMetrics
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewInMemoryMetricsStorage creates a new in-memory metrics storage
|
||||
func NewInMemoryMetricsStorage() *InMemoryMetricsStorage {
|
||||
return &InMemoryMetricsStorage{
|
||||
nodeMetrics: make(map[string][]*NodeMetrics),
|
||||
serviceMetrics: make(map[string][]*ServiceMetrics),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *InMemoryMetricsStorage) StoreNodeMetrics(ctx context.Context, metrics *NodeMetrics) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.nodeMetrics[metrics.NodeID] = append(s.nodeMetrics[metrics.NodeID], metrics)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *InMemoryMetricsStorage) StoreServiceMetrics(ctx context.Context, metrics *ServiceMetrics) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.serviceMetrics[metrics.ServiceID] = append(s.serviceMetrics[metrics.ServiceID], metrics)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *InMemoryMetricsStorage) GetNodeMetrics(ctx context.Context, nodeID string, from, to time.Time) ([]*NodeMetrics, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
metrics := s.nodeMetrics[nodeID]
|
||||
var result []*NodeMetrics
|
||||
for _, m := range metrics {
|
||||
if m.Timestamp.After(from) && m.Timestamp.Before(to) {
|
||||
result = append(result, m)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *InMemoryMetricsStorage) GetServiceMetrics(ctx context.Context, serviceID string, from, to time.Time) ([]*ServiceMetrics, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
metrics := s.serviceMetrics[serviceID]
|
||||
var result []*ServiceMetrics
|
||||
for _, m := range metrics {
|
||||
if m.Timestamp.After(from) && m.Timestamp.Before(to) {
|
||||
result = append(result, m)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *InMemoryMetricsStorage) GetAggregatedMetrics(ctx context.Context, query MetricsQuery) (*AggregatedMetrics, error) {
|
||||
// Simplified implementation
|
||||
return &AggregatedMetrics{
|
||||
Query: query,
|
||||
TimeSeries: []TimeSeriesPoint{},
|
||||
Summary: map[string]MetricSummary{},
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user