// 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" "syscall" "time" "queryorchestration/internal/serviceconfig/build" "queryorchestration/internal/serviceconfig/observability/prometheus" ) func getMetricsConfig() prometheus.MetricsConfig { standardDefinitions := prometheus.NewStandardMetricDefinitions() // Define metrics configuration using StandardMetricDefinitions config := prometheus.MetricsConfig{ Port: 8080, Namespace: "myapp", Subsystem: "api", ServeHttp: true, // Start with standard metrics and append our custom one Definitions: append(standardDefinitions, prometheus.MetricDefinition{ Type: prometheus.Counter, Name: "test_custom_events_total", Help: "Total number of custom test events", Labels: []string{ "event_type", "priority", }, }, ), } return config } func main() { rawVersion := build.GetVersion() fmt.Printf("Version: %s\n", rawVersion) timeVersion := build.GetVersionTimestamp() fmt.Printf("Version Timestamp: %s\n", timeVersion.String()) ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Define metrics configuration using StandardMetricDefinitions config := getMetricsConfig() metrics, err := prometheus.New(ctx, config) if err != nil { log.Fatalf("Failed to create metrics: %v", err) } go simulateMetrics(ctx, metrics) sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) fmt.Println("Running... Press Ctrl+C to exit") <-sigChan fmt.Println("\nShutting down...") cancel() shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) defer shutdownCancel() 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 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"} errorTypes := []string{"none", "validation", "database", "timeout"} dependencies := []string{"database", "cache", "auth-service", "email-service"} cacheOperations := []string{"hit", "miss", "set", "eviction"} taskTypes := []string{"cleanup", "indexing", "backup", "sync"} taskStatuses := []string{"running", "queued", "failed"} results := []string{"success", "failure", "timeout"} components := []string{"api", "database", "cache", "auth"} queueNames := []string{"main-queue", "background-queue", "notification-queue"} resourceTypes := []string{"cpu", "memory", "disk", "network"} // Custom metric sample data eventTypes := []string{"scheduled", "triggered", "manual"} priorities := []string{"low", "medium", "high"} ticker := time.NewTicker(500 * time.Millisecond) defer ticker.Stop() for { select { case <-ctx.Done(): return case <-ticker.C: // Simulate standard metrics // 1. Requests total endpoint := endpoints[rand.Intn(len(endpoints))] method := methods[rand.Intn(len(methods))] status := statuses[rand.Intn(len(statuses))] errorType := errorTypes[rand.Intn(len(errorTypes))] err := metrics.RecordRequestsTotal(1.0, endpoint, method, endpoint, status, errorType) if err != nil { log.Printf("Error recording requests metric: %v", err) } // 2. Request duration duration := rand.Float64() * 3 // Random duration between 0 and 3 seconds err = metrics.RecordRequestDurationSeconds(duration, endpoint, method, endpoint, status) if err != nil { log.Printf("Error recording duration metric: %v", err) } // 3. Active operations activeOps := rand.Float64() * 50 err = metrics.RecordActiveOperations(activeOps, method) if err != nil { log.Printf("Error recording active operations metric: %v", err) } // 4. Resource usage resourceType := resourceTypes[rand.Intn(len(resourceTypes))] err = metrics.RecordResourceUsage(rand.Float64()*100, resourceType, "main-instance") if err != nil { log.Printf("Error recording resource usage metric: %v", err) } // 5. Dependency health dep := dependencies[rand.Intn(len(dependencies))] health := rand.Float64() // Random health score between 0 and 1 err = metrics.RecordDependencyHealth(health, dep, "external_service") if err != nil { log.Printf("Error recording dependency health metric: %v", err) } // 6. Cache operations cacheOp := cacheOperations[rand.Intn(len(cacheOperations))] result := results[rand.Intn(len(results))] err = metrics.RecordCacheOperationsTotal(1.0, cacheOp, "main-cache", result) if err != nil { log.Printf("Error recording cache operations metric: %v", err) } // 7. Cache operation duration err = metrics.RecordCacheOperationDurationSeconds(rand.Float64()*0.1, cacheOp, result) if err != nil { log.Printf("Error recording cache duration metric: %v", err) } // 8. Background tasks taskType := taskTypes[rand.Intn(len(taskTypes))] taskStatus := taskStatuses[rand.Intn(len(taskStatuses))] err = metrics.RecordBackgroundTasks(rand.Float64()*10, taskType, taskStatus) if err != nil { log.Printf("Error recording background tasks metric: %v", err) } // 9. Active connections err = metrics.RecordActiveConnections(rand.Float64()*100, "http") if err != nil { log.Printf("Error recording active connections metric: %v", err) } // 10. Queue length queueName := queueNames[rand.Intn(len(queueNames))] err = metrics.RecordQueueLength(rand.Float64()*50, queueName) if err != nil { log.Printf("Error recording queue length metric: %v", err) } // 11. Errors total component := components[rand.Intn(len(components))] err = metrics.RecordErrorsTotal(1.0, component, errorType) if err != nil { log.Printf("Error recording errors total metric: %v", err) } // 12. Items in progress err = metrics.RecordItemsInProgress(rand.Float64()*20, endpoint, component) if err != nil { log.Printf("Error recording items in progress metric: %v", err) } // Custom metric (still using RecordMetric since it's not part of the generated stubs) eventType := eventTypes[rand.Intn(len(eventTypes))] priority := priorities[rand.Intn(len(priorities))] err = metrics.RecordMetric("test_custom_events_total", 1, map[string]string{ "event_type": eventType, "priority": priority, }) if err != nil { log.Printf("Error recording custom event metric: %v", err) } } } }