- Add comprehensive database migrations (001-024) for schema evolution - Enhance API schema with expanded type definitions and resolvers - Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth - Implement new services: AI optimization, billing, blockchain, compliance, marketplace - Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage) - Update Crossplane provider with enhanced VM management capabilities - Add comprehensive test suite for API endpoints and services - Update frontend components with improved GraphQL subscriptions and real-time updates - Enhance security configurations and headers (CSP, CORS, etc.) - Update documentation and configuration files - Add new CI/CD workflows and validation scripts - Implement design system improvements and UI enhancements
112 lines
2.5 KiB
Go
112 lines
2.5 KiB
Go
package metrics
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// PrometheusAPIClient implements PrometheusClient using Prometheus HTTP API
|
|
type PrometheusAPIClient struct {
|
|
endpoint string
|
|
client *http.Client
|
|
}
|
|
|
|
// NewPrometheusAPIClient creates a new Prometheus API client
|
|
func NewPrometheusAPIClient(endpoint string) *PrometheusAPIClient {
|
|
return &PrometheusAPIClient{
|
|
endpoint: endpoint,
|
|
client: &http.Client{
|
|
Timeout: 30 * time.Second,
|
|
},
|
|
}
|
|
}
|
|
|
|
// QueryResponse represents a Prometheus query response
|
|
type QueryResponse struct {
|
|
Status string `json:"status"`
|
|
Data struct {
|
|
ResultType string `json:"resultType"`
|
|
Result []struct {
|
|
Metric map[string]string `json:"metric"`
|
|
Value []interface{} `json:"value"`
|
|
} `json:"result"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
// Query executes a Prometheus query
|
|
func (c *PrometheusAPIClient) Query(ctx context.Context, query string) ([]MetricValue, error) {
|
|
// Build query URL
|
|
queryURL := fmt.Sprintf("%s/api/v1/query", c.endpoint)
|
|
params := url.Values{}
|
|
params.Set("query", query)
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "GET", queryURL+"?"+params.Encode(), nil)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to create request")
|
|
}
|
|
|
|
resp, err := c.client.Do(req)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to execute request")
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
return nil, fmt.Errorf("prometheus query failed: %d %s - %s", resp.StatusCode, resp.Status, string(body))
|
|
}
|
|
|
|
var queryResp QueryResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&queryResp); err != nil {
|
|
return nil, errors.Wrap(err, "failed to decode response")
|
|
}
|
|
|
|
if queryResp.Status != "success" {
|
|
return nil, fmt.Errorf("prometheus query returned error status: %s", queryResp.Status)
|
|
}
|
|
|
|
// Convert to MetricValue slice
|
|
var values []MetricValue
|
|
for _, result := range queryResp.Data.Result {
|
|
if len(result.Value) < 2 {
|
|
continue
|
|
}
|
|
|
|
// Parse timestamp (Unix timestamp in seconds)
|
|
timestampFloat, ok := result.Value[0].(float64)
|
|
if !ok {
|
|
continue
|
|
}
|
|
timestamp := time.Unix(int64(timestampFloat), 0)
|
|
|
|
// Parse value
|
|
var value float64
|
|
switch v := result.Value[1].(type) {
|
|
case string:
|
|
if _, err := fmt.Sscanf(v, "%f", &value); err != nil {
|
|
continue
|
|
}
|
|
case float64:
|
|
value = v
|
|
default:
|
|
continue
|
|
}
|
|
|
|
values = append(values, MetricValue{
|
|
Value: value,
|
|
Timestamp: timestamp,
|
|
Labels: result.Metric,
|
|
})
|
|
}
|
|
|
|
return values, nil
|
|
}
|
|
|