mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2025-12-13 17:10:36 +00:00
| .. | ||
| interfaces.go | ||
| prometheus.go | ||
| README.md | ||
Metrics Package
A pluggable metrics collection system with Prometheus implementation.
Quick Start
import "github.com/bitechdev/ResolveSpec/pkg/metrics"
// Initialize Prometheus provider
provider := metrics.NewPrometheusProvider()
metrics.SetProvider(provider)
// Apply middleware to your router
router.Use(provider.Middleware)
// Expose metrics endpoint
http.Handle("/metrics", provider.Handler())
Provider Interface
The package uses a provider interface, allowing you to plug in different metric systems:
type Provider interface {
RecordHTTPRequest(method, path, status string, duration time.Duration)
IncRequestsInFlight()
DecRequestsInFlight()
RecordDBQuery(operation, table string, duration time.Duration, err error)
RecordCacheHit(provider string)
RecordCacheMiss(provider string)
UpdateCacheSize(provider string, size int64)
Handler() http.Handler
}
Recording Metrics
HTTP Metrics (Automatic)
When using the middleware, HTTP metrics are recorded automatically:
router.Use(provider.Middleware)
Collected:
- Request duration (histogram)
- Request count by method, path, and status
- Requests in flight (gauge)
Database Metrics
start := time.Now()
rows, err := db.Query("SELECT * FROM users WHERE id = ?", userID)
duration := time.Since(start)
metrics.GetProvider().RecordDBQuery("SELECT", "users", duration, err)
Cache Metrics
// Record cache hit
metrics.GetProvider().RecordCacheHit("memory")
// Record cache miss
metrics.GetProvider().RecordCacheMiss("memory")
// Update cache size
metrics.GetProvider().UpdateCacheSize("memory", 1024)
Prometheus Metrics
When using PrometheusProvider, the following metrics are available:
| Metric Name | Type | Labels | Description |
|---|---|---|---|
http_request_duration_seconds |
Histogram | method, path, status | HTTP request duration |
http_requests_total |
Counter | method, path, status | Total HTTP requests |
http_requests_in_flight |
Gauge | - | Current in-flight requests |
db_query_duration_seconds |
Histogram | operation, table | Database query duration |
db_queries_total |
Counter | operation, table, status | Total database queries |
cache_hits_total |
Counter | provider | Total cache hits |
cache_misses_total |
Counter | provider | Total cache misses |
cache_size_items |
Gauge | provider | Current cache size |
Prometheus Queries
HTTP Request Rate
rate(http_requests_total[5m])
HTTP Request Duration (95th percentile)
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
Database Query Error Rate
rate(db_queries_total{status="error"}[5m])
Cache Hit Rate
rate(cache_hits_total[5m]) / (rate(cache_hits_total[5m]) + rate(cache_misses_total[5m]))
No-Op Provider
If metrics are disabled:
// No provider set - uses no-op provider automatically
metrics.GetProvider().RecordHTTPRequest(...) // Does nothing
Custom Provider
Implement your own metrics provider:
type CustomProvider struct{}
func (c *CustomProvider) RecordHTTPRequest(method, path, status string, duration time.Duration) {
// Send to your metrics system
}
// Implement other Provider interface methods...
func (c *CustomProvider) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Return your metrics format
})
}
// Use it
metrics.SetProvider(&CustomProvider{})
Complete Example
package main
import (
"database/sql"
"log"
"net/http"
"time"
"github.com/bitechdev/ResolveSpec/pkg/metrics"
"github.com/gorilla/mux"
)
func main() {
// Initialize metrics
provider := metrics.NewPrometheusProvider()
metrics.SetProvider(provider)
// Create router
router := mux.NewRouter()
// Apply metrics middleware
router.Use(provider.Middleware)
// Expose metrics endpoint
router.Handle("/metrics", provider.Handler())
// Your API routes
router.HandleFunc("/api/users", getUsersHandler)
log.Fatal(http.ListenAndServe(":8080", router))
}
func getUsersHandler(w http.ResponseWriter, r *http.Request) {
// Record database query
start := time.Now()
users, err := fetchUsers()
duration := time.Since(start)
metrics.GetProvider().RecordDBQuery("SELECT", "users", duration, err)
if err != nil {
http.Error(w, "Internal Server Error", 500)
return
}
// Return users...
}
Docker Compose Example
version: '3'
services:
app:
build: .
ports:
- "8080:8080"
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
grafana:
image: grafana/grafana
ports:
- "3000:3000"
depends_on:
- prometheus
prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'resolvespec'
static_configs:
- targets: ['app:8080']
Best Practices
-
Label Cardinality: Keep labels low-cardinality
- ✅ Good:
method,status_code - ❌ Bad:
user_id,timestamp
- ✅ Good:
-
Path Normalization: Normalize dynamic paths
// Instead of /api/users/123 // Use /api/users/:id -
Metric Naming: Follow Prometheus conventions
- Use
_totalsuffix for counters - Use
_secondssuffix for durations - Use base units (seconds, not milliseconds)
- Use
-
Performance: Metrics collection is lock-free and highly performant
- Safe for high-throughput applications
- Minimal overhead (<1% in most cases)