Merged in feature/prometheus (pull request #52)
API instrumentation - metrics and logging * api instrumentation prometheus metrics and logging for all routes * Merge branch 'main' of bitbucket.org:aarete/query-orchestration into feature/prometheus * add log_level and sync the config initialize * docs * cleanup * add to compose:up:test * docs for prometheus testing * custom metrics * cleanup * merge main * add tests * cleanup docs * cleanup * lint * fix unit tests (attempt) * fix tests * resolvesetlogger * expose 8080 * compose changes * bugfixesformichael * don't build _test * merge in main * job_sync_runner
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
// This main.go serves as an example of how to use the custom Prometheus metrics package.
|
||||
// It demonstrates:
|
||||
// 1. Setting up metrics with proper context handling
|
||||
// 2. Configuring different types of metrics (Counter, Gauge, Histogram, Summary)
|
||||
// 3. Recording metrics safely in a concurrent environment
|
||||
// 4. Implementing graceful shutdown
|
||||
// 5. Proper error handling
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/signal"
|
||||
"queryorchestration/internal/serviceconfig/observability/prometheus"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create a context that we can cancel
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Define metrics configuration
|
||||
// This example shows all supported metric types and their configurations
|
||||
config := prometheus.MetricsConfig{
|
||||
Port: 8080,
|
||||
Namespace: "myapp",
|
||||
Subsystem: "api",
|
||||
// When ServeHttp is true, the package will start its own HTTP server
|
||||
// If you want to use your own HTTP server (e.g., with Echo middleware),
|
||||
// set this to false and configure your server to handle the /metrics endpoint
|
||||
ServeHttp: true,
|
||||
Definitions: []prometheus.MetricDefinition{
|
||||
{
|
||||
// Counter: Only increases, never decreases
|
||||
Type: prometheus.Counter,
|
||||
Name: "api_requests_total",
|
||||
Help: "Total number of API requests",
|
||||
Labels: []string{"method", "endpoint", "status"},
|
||||
},
|
||||
{
|
||||
// Gauge: Can increase and decrease
|
||||
Type: prometheus.Gauge,
|
||||
Name: "active_users",
|
||||
Help: "Number of currently active users",
|
||||
Labels: []string{"user_type"},
|
||||
},
|
||||
{
|
||||
// Histogram: Tracks distribution of values
|
||||
Type: prometheus.Histogram,
|
||||
Name: "request_duration_seconds",
|
||||
Help: "Request duration distribution",
|
||||
Labels: []string{"endpoint"},
|
||||
Buckets: []float64{0.1, 0.5, 1, 2, 5}, // Define your bucket boundaries
|
||||
},
|
||||
{
|
||||
// Summary: Calculates quantiles over a sliding time window
|
||||
Type: prometheus.Summary,
|
||||
Name: "response_size_bytes",
|
||||
Help: "Response size distribution",
|
||||
Labels: []string{"endpoint"},
|
||||
Objectives: map[float64]float64{
|
||||
0.5: 0.05, // 50th percentile with 5% error
|
||||
0.9: 0.01, // 90th percentile with 1% error
|
||||
0.99: 0.001, // 99th percentile with 0.1% error
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Create new metrics instance with context
|
||||
metrics, err := prometheus.New(ctx, config)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create metrics: %v", err)
|
||||
}
|
||||
|
||||
// Start a goroutine to simulate metric recording
|
||||
go simulateMetrics(ctx, metrics)
|
||||
|
||||
// Set up graceful shutdown
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
fmt.Println("Running... Press Ctrl+C to exit")
|
||||
|
||||
// Wait for interrupt signal
|
||||
<-sigChan
|
||||
fmt.Println("\nShutting down...")
|
||||
|
||||
// Cancel context to stop metric simulation
|
||||
cancel()
|
||||
|
||||
// Create a timeout context for shutdown
|
||||
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer shutdownCancel()
|
||||
|
||||
// Gracefully shutdown the metrics server
|
||||
if err := metrics.Shutdown(shutdownCtx); err != nil {
|
||||
log.Printf("Error shutting down metrics server: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// simulateMetrics demonstrates how to record different types of metrics
|
||||
// in a concurrent environment. It takes a context for cancellation and
|
||||
// the metrics instance.
|
||||
func simulateMetrics(ctx context.Context, metrics *prometheus.Metrics) {
|
||||
// Sample data for simulation
|
||||
endpoints := []string{"/api/users", "/api/products", "/api/orders"}
|
||||
methods := []string{"GET", "POST", "PUT", "DELETE"}
|
||||
statuses := []string{"200", "400", "500"}
|
||||
userTypes := []string{"free", "premium", "enterprise"}
|
||||
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
// Simulate request counter (Counter type)
|
||||
endpoint := endpoints[rand.Intn(len(endpoints))]
|
||||
method := methods[rand.Intn(len(methods))]
|
||||
status := statuses[rand.Intn(len(statuses))]
|
||||
|
||||
err := metrics.RecordMetric("api_requests_total", 1, map[string]string{
|
||||
"method": method,
|
||||
"endpoint": endpoint,
|
||||
"status": status,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("Error recording request metric: %v", err)
|
||||
}
|
||||
|
||||
// Simulate active users (Gauge type)
|
||||
userType := userTypes[rand.Intn(len(userTypes))]
|
||||
activeUsers := rand.Float64() * 100
|
||||
err = metrics.RecordMetric("active_users", activeUsers, map[string]string{
|
||||
"user_type": userType,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("Error recording active users metric: %v", err)
|
||||
}
|
||||
|
||||
// Simulate request duration (Histogram type)
|
||||
duration := rand.Float64() * 3 // Random duration between 0 and 3 seconds
|
||||
err = metrics.RecordMetric("request_duration_seconds", duration, map[string]string{
|
||||
"endpoint": endpoint,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("Error recording duration metric: %v", err)
|
||||
}
|
||||
|
||||
// Simulate response size (Summary type)
|
||||
responseSize := rand.Float64() * 5000 // Random size between 0 and 5000 bytes
|
||||
err = metrics.RecordMetric("response_size_bytes", responseSize, map[string]string{
|
||||
"endpoint": endpoint,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("Error recording response size metric: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user