mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-01-09 13:04:24 +00:00
feat(packages): ✨ Prometheus publish events
This commit is contained in:
@@ -53,6 +53,24 @@ metrics.SetProvider(provider)
|
||||
|
||||
**Default DB Query Buckets:** `[0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5]`
|
||||
|
||||
### Pushgateway Configuration (Optional)
|
||||
|
||||
For batch jobs, cron tasks, or short-lived processes, you can push metrics to Prometheus Pushgateway:
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `PushgatewayURL` | `string` | `""` | URL of Pushgateway (e.g., "http://pushgateway:9091") |
|
||||
| `PushgatewayJobName` | `string` | `"resolvespec"` | Job name for pushed metrics |
|
||||
| `PushgatewayInterval` | `int` | `0` | Auto-push interval in seconds (0 = disabled) |
|
||||
|
||||
```go
|
||||
config := &metrics.Config{
|
||||
PushgatewayURL: "http://pushgateway:9091",
|
||||
PushgatewayJobName: "batch-job",
|
||||
PushgatewayInterval: 30, // Push every 30 seconds
|
||||
}
|
||||
```
|
||||
|
||||
## Provider Interface
|
||||
|
||||
The package uses a provider interface, allowing you to plug in different metric systems:
|
||||
@@ -188,6 +206,122 @@ func (c *CustomProvider) Handler() http.Handler {
|
||||
metrics.SetProvider(&CustomProvider{})
|
||||
```
|
||||
|
||||
## Pushgateway Usage
|
||||
|
||||
### Automatic Push (Batch Jobs)
|
||||
|
||||
For jobs that run periodically, use automatic pushing:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/bitechdev/ResolveSpec/pkg/metrics"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configure with automatic pushing every 30 seconds
|
||||
config := &metrics.Config{
|
||||
Enabled: true,
|
||||
Provider: "prometheus",
|
||||
Namespace: "batch_job",
|
||||
PushgatewayURL: "http://pushgateway:9091",
|
||||
PushgatewayJobName: "data-processor",
|
||||
PushgatewayInterval: 30, // Push every 30 seconds
|
||||
}
|
||||
|
||||
provider := metrics.NewPrometheusProvider(config)
|
||||
metrics.SetProvider(provider)
|
||||
|
||||
// Ensure cleanup on exit
|
||||
defer provider.StopAutoPush()
|
||||
|
||||
// Your batch job logic here
|
||||
processBatchData()
|
||||
}
|
||||
```
|
||||
|
||||
### Manual Push (Short-lived Processes)
|
||||
|
||||
For one-time jobs or when you want manual control:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/bitechdev/ResolveSpec/pkg/metrics"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configure without automatic pushing
|
||||
config := &metrics.Config{
|
||||
Enabled: true,
|
||||
Provider: "prometheus",
|
||||
PushgatewayURL: "http://pushgateway:9091",
|
||||
PushgatewayJobName: "migration-job",
|
||||
// PushgatewayInterval: 0 (default - no auto-push)
|
||||
}
|
||||
|
||||
provider := metrics.NewPrometheusProvider(config)
|
||||
metrics.SetProvider(provider)
|
||||
|
||||
// Run your job
|
||||
err := runMigration()
|
||||
|
||||
// Push metrics at the end
|
||||
if pushErr := provider.Push(); pushErr != nil {
|
||||
log.Printf("Failed to push metrics: %v", pushErr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Docker Compose with Pushgateway
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
services:
|
||||
batch-job:
|
||||
build: .
|
||||
environment:
|
||||
PUSHGATEWAY_URL: "http://pushgateway:9091"
|
||||
|
||||
pushgateway:
|
||||
image: prom/pushgateway
|
||||
ports:
|
||||
- "9091:9091"
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
```
|
||||
|
||||
**prometheus.yml for Pushgateway:**
|
||||
|
||||
```yaml
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
# Scrape the pushgateway
|
||||
- job_name: 'pushgateway'
|
||||
honor_labels: true # Important: preserve job labels from pushed metrics
|
||||
static_configs:
|
||||
- targets: ['pushgateway:9091']
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
### Basic Usage
|
||||
@@ -337,3 +471,8 @@ scrape_configs:
|
||||
4. **Performance**: Metrics collection is lock-free and highly performant
|
||||
- Safe for high-throughput applications
|
||||
- Minimal overhead (<1% in most cases)
|
||||
|
||||
5. **Pull vs Push**:
|
||||
- **Use Pull (default)**: Long-running services, web servers, microservices
|
||||
- **Use Push (Pushgateway)**: Batch jobs, cron tasks, short-lived processes, serverless functions
|
||||
- Pull is preferred for most applications as it allows Prometheus to detect if your service is down
|
||||
|
||||
@@ -18,6 +18,20 @@ type Config struct {
|
||||
// DBQueryBuckets defines histogram buckets for database query duration (in seconds)
|
||||
// Default: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5]
|
||||
DBQueryBuckets []float64 `mapstructure:"db_query_buckets"`
|
||||
|
||||
// PushgatewayURL is the URL of the Prometheus Pushgateway (optional)
|
||||
// If set, metrics will be pushed to this gateway instead of only being scraped
|
||||
// Example: "http://pushgateway:9091"
|
||||
PushgatewayURL string `mapstructure:"pushgateway_url"`
|
||||
|
||||
// PushgatewayJobName is the job name to use when pushing metrics to Pushgateway
|
||||
// Default: "resolvespec"
|
||||
PushgatewayJobName string `mapstructure:"pushgateway_job_name"`
|
||||
|
||||
// PushgatewayInterval is the interval at which to push metrics to Pushgateway
|
||||
// Only used if PushgatewayURL is set. If 0, automatic pushing is disabled.
|
||||
// Default: 0 (no automatic pushing)
|
||||
PushgatewayInterval int `mapstructure:"pushgateway_interval"`
|
||||
}
|
||||
|
||||
// DefaultConfig returns a Config with sensible defaults
|
||||
@@ -43,4 +57,8 @@ func (c *Config) ApplyDefaults() {
|
||||
if len(c.DBQueryBuckets) == 0 {
|
||||
c.DBQueryBuckets = []float64{0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5}
|
||||
}
|
||||
// Set default job name if pushgateway is configured but job name is empty
|
||||
if c.PushgatewayURL != "" && c.PushgatewayJobName == "" {
|
||||
c.PushgatewayJobName = "resolvespec"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/prometheus/client_golang/prometheus/push"
|
||||
)
|
||||
|
||||
// PrometheusProvider implements the Provider interface using Prometheus
|
||||
@@ -25,6 +26,13 @@ type PrometheusProvider struct {
|
||||
eventDuration *prometheus.HistogramVec
|
||||
eventQueueSize prometheus.Gauge
|
||||
panicsTotal *prometheus.CounterVec
|
||||
|
||||
// Pushgateway fields (optional)
|
||||
pushgatewayURL string
|
||||
pushgatewayJobName string
|
||||
pusher *push.Pusher
|
||||
pushTicker *time.Ticker
|
||||
pushStop chan bool
|
||||
}
|
||||
|
||||
// NewPrometheusProvider creates a new Prometheus metrics provider
|
||||
@@ -46,7 +54,7 @@ func NewPrometheusProvider(cfg *Config) *PrometheusProvider {
|
||||
return name
|
||||
}
|
||||
|
||||
return &PrometheusProvider{
|
||||
p := &PrometheusProvider{
|
||||
requestDuration: promauto.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: metricName("http_request_duration_seconds"),
|
||||
@@ -140,7 +148,25 @@ func NewPrometheusProvider(cfg *Config) *PrometheusProvider {
|
||||
},
|
||||
[]string{"method"},
|
||||
),
|
||||
|
||||
pushgatewayURL: cfg.PushgatewayURL,
|
||||
pushgatewayJobName: cfg.PushgatewayJobName,
|
||||
}
|
||||
|
||||
// Initialize pushgateway if configured
|
||||
if cfg.PushgatewayURL != "" {
|
||||
p.pusher = push.New(cfg.PushgatewayURL, cfg.PushgatewayJobName).
|
||||
Gatherer(prometheus.DefaultGatherer)
|
||||
|
||||
// Start automatic pushing if interval is configured
|
||||
if cfg.PushgatewayInterval > 0 {
|
||||
p.pushStop = make(chan bool)
|
||||
p.pushTicker = time.NewTicker(time.Duration(cfg.PushgatewayInterval) * time.Second)
|
||||
go p.startAutoPush()
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// ResponseWriter wraps http.ResponseWriter to capture status code
|
||||
@@ -250,3 +276,37 @@ func (p *PrometheusProvider) Middleware(next http.Handler) http.Handler {
|
||||
p.RecordHTTPRequest(r.Method, r.URL.Path, status, duration)
|
||||
})
|
||||
}
|
||||
|
||||
// Push manually pushes metrics to the configured Pushgateway
|
||||
// Returns an error if pushing fails or if Pushgateway is not configured
|
||||
func (p *PrometheusProvider) Push() error {
|
||||
if p.pusher == nil {
|
||||
return nil // Pushgateway not configured, silently skip
|
||||
}
|
||||
return p.pusher.Push()
|
||||
}
|
||||
|
||||
// startAutoPush runs in a goroutine and periodically pushes metrics to Pushgateway
|
||||
func (p *PrometheusProvider) startAutoPush() {
|
||||
for {
|
||||
select {
|
||||
case <-p.pushTicker.C:
|
||||
if err := p.Push(); err != nil {
|
||||
// Log error but continue pushing
|
||||
// Note: In production, you might want to use a proper logger
|
||||
_ = err
|
||||
}
|
||||
case <-p.pushStop:
|
||||
p.pushTicker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StopAutoPush stops the automatic push goroutine
|
||||
// This should be called when shutting down the application
|
||||
func (p *PrometheusProvider) StopAutoPush() {
|
||||
if p.pushStop != nil {
|
||||
close(p.pushStop)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user