mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-06-05 23:03:48 +00:00
6a69694ab3
* Tackling the CPU / memory spikes after some time. * Update admin dashboard, fix the circuit breaker and request coalescing.
218 lines
7.5 KiB
Go
218 lines
7.5 KiB
Go
package libpack_monitoring
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/VictoriaMetrics/metrics"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/gookit/goutil/envutil"
|
|
libpack_config "github.com/lukaszraczylo/graphql-monitoring-proxy/config"
|
|
libpack_logger "github.com/lukaszraczylo/graphql-monitoring-proxy/logging"
|
|
)
|
|
|
|
type MetricsSetup struct {
|
|
metrics_set *metrics.Set
|
|
metrics_set_custom *metrics.Set
|
|
ic *InitConfig
|
|
metrics_prefix string
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
}
|
|
|
|
var log = libpack_logger.New().SetMinLogLevel(libpack_logger.LEVEL_INFO)
|
|
|
|
type InitConfig struct {
|
|
PurgeOnCrawl bool
|
|
PurgeEvery int
|
|
}
|
|
|
|
func NewMonitoring(ic *InitConfig) *MetricsSetup {
|
|
return NewMonitoringWithContext(context.Background(), ic)
|
|
}
|
|
|
|
// NewMonitoringWithContext creates a new monitoring instance with context for graceful shutdown
|
|
func NewMonitoringWithContext(ctx context.Context, ic *InitConfig) *MetricsSetup {
|
|
monCtx, cancel := context.WithCancel(ctx)
|
|
ms := &MetricsSetup{
|
|
ic: ic,
|
|
metrics_set: metrics.NewSet(),
|
|
metrics_set_custom: metrics.NewSet(),
|
|
ctx: monCtx,
|
|
cancel: cancel,
|
|
}
|
|
|
|
if flag.Lookup("test.v") == nil {
|
|
go ms.startPrometheusEndpoint()
|
|
|
|
if ic.PurgeEvery > 0 {
|
|
ticker := time.NewTicker(time.Duration(ic.PurgeEvery) * time.Second)
|
|
go func() {
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ms.ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
ms.PurgeMetrics()
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
return ms
|
|
}
|
|
|
|
// Shutdown stops the monitoring goroutines
|
|
func (ms *MetricsSetup) Shutdown() {
|
|
if ms.cancel != nil {
|
|
ms.cancel()
|
|
}
|
|
}
|
|
|
|
func (ms *MetricsSetup) startPrometheusEndpoint() {
|
|
app := fiber.New(fiber.Config{
|
|
DisableStartupMessage: true,
|
|
AppName: fmt.Sprintf("GraphQL Monitoring Proxy - %s v%s", libpack_config.PKG_NAME, libpack_config.PKG_VERSION),
|
|
})
|
|
app.Get("/metrics", ms.metricsEndpoint)
|
|
if err := app.Listen(fmt.Sprintf(":%d", envutil.GetInt("MONITORING_PORT", 9393))); err != nil {
|
|
log.Critical(&libpack_logger.LogMessage{
|
|
Message: "Can't start the MONITORING service",
|
|
Pairs: map[string]interface{}{"error": err},
|
|
})
|
|
}
|
|
}
|
|
|
|
func (ms *MetricsSetup) metricsEndpoint(c *fiber.Ctx) error {
|
|
ms.metrics_set.WritePrometheus(c.Response().BodyWriter())
|
|
ms.metrics_set_custom.WritePrometheus(c.Response().BodyWriter())
|
|
|
|
if ms.ic.PurgeOnCrawl && ms.ic.PurgeEvery == 0 {
|
|
ms.PurgeMetrics()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ms *MetricsSetup) AddMetricsPrefix(prefix string) {
|
|
ms.metrics_prefix = prefix
|
|
}
|
|
|
|
func (ms *MetricsSetup) ListActiveMetrics() []string {
|
|
return ms.metrics_set.ListMetricNames()
|
|
}
|
|
|
|
func (ms *MetricsSetup) RegisterMetricsGauge(metric_name string, labels map[string]string, val float64) *metrics.Gauge {
|
|
if err := validate_metrics_name(metric_name); err != nil {
|
|
log.Error(&libpack_logger.LogMessage{
|
|
Message: "RegisterMetricsGauge() error - invalid metric name",
|
|
Pairs: map[string]interface{}{"error": err.Error(), "metric_name": metric_name},
|
|
})
|
|
// Return a dummy gauge instead of nil to prevent panics
|
|
return &metrics.Gauge{}
|
|
}
|
|
return ms.metrics_set_custom.GetOrCreateGauge(ms.get_metrics_name(metric_name, labels), func() float64 {
|
|
return val
|
|
})
|
|
}
|
|
|
|
// RegisterMetricsGaugeFunc registers a gauge with a callback function that is called on every scrape
|
|
// This is useful for metrics that need to return a dynamic value
|
|
func (ms *MetricsSetup) RegisterMetricsGaugeFunc(metric_name string, labels map[string]string, fn func() float64) *metrics.Gauge {
|
|
if err := validate_metrics_name(metric_name); err != nil {
|
|
log.Error(&libpack_logger.LogMessage{
|
|
Message: "RegisterMetricsGaugeFunc() error - invalid metric name",
|
|
Pairs: map[string]interface{}{"error": err.Error(), "metric_name": metric_name},
|
|
})
|
|
// Return a dummy gauge instead of nil to prevent panics
|
|
return &metrics.Gauge{}
|
|
}
|
|
return ms.metrics_set_custom.GetOrCreateGauge(ms.get_metrics_name(metric_name, labels), fn)
|
|
}
|
|
|
|
func (ms *MetricsSetup) RegisterMetricsCounter(metric_name string, labels map[string]string) *metrics.Counter {
|
|
if err := validate_metrics_name(metric_name); err != nil {
|
|
log.Error(&libpack_logger.LogMessage{
|
|
Message: "RegisterMetricsCounter() error - invalid metric name",
|
|
Pairs: map[string]interface{}{"error": err.Error(), "metric_name": metric_name},
|
|
})
|
|
// Return a dummy counter instead of nil to prevent panics
|
|
return &metrics.Counter{}
|
|
}
|
|
if metric_name == MetricsSucceeded || metric_name == MetricsFailed || metric_name == MetricsSkipped {
|
|
return ms.metrics_set.GetOrCreateCounter(ms.get_metrics_name(metric_name, labels))
|
|
}
|
|
return ms.metrics_set_custom.GetOrCreateCounter(ms.get_metrics_name(metric_name, labels))
|
|
}
|
|
|
|
func (ms *MetricsSetup) RegisterFloatCounter(metric_name string, labels map[string]string) *metrics.FloatCounter {
|
|
if err := validate_metrics_name(metric_name); err != nil {
|
|
log.Error(&libpack_logger.LogMessage{
|
|
Message: "RegisterFloatCounter() error - invalid metric name",
|
|
Pairs: map[string]interface{}{"error": err.Error(), "metric_name": metric_name},
|
|
})
|
|
// Return a dummy float counter instead of nil to prevent panics
|
|
return &metrics.FloatCounter{}
|
|
}
|
|
return ms.metrics_set_custom.GetOrCreateFloatCounter(ms.get_metrics_name(metric_name, labels))
|
|
}
|
|
|
|
func (ms *MetricsSetup) RegisterMetricsSummary(metric_name string, labels map[string]string) *metrics.Summary {
|
|
if err := validate_metrics_name(metric_name); err != nil {
|
|
log.Error(&libpack_logger.LogMessage{
|
|
Message: "RegisterMetricsSummary() error - invalid metric name",
|
|
Pairs: map[string]interface{}{"error": err.Error(), "metric_name": metric_name},
|
|
})
|
|
// Return a dummy summary instead of nil to prevent panics
|
|
return &metrics.Summary{}
|
|
}
|
|
return ms.metrics_set_custom.GetOrCreateSummary(ms.get_metrics_name(metric_name, labels))
|
|
}
|
|
|
|
func (ms *MetricsSetup) RegisterMetricsHistogram(metric_name string, labels map[string]string) *metrics.Histogram {
|
|
if err := validate_metrics_name(metric_name); err != nil {
|
|
log.Error(&libpack_logger.LogMessage{
|
|
Message: "RegisterMetricsHistogram() error - invalid metric name",
|
|
Pairs: map[string]interface{}{"error": err.Error(), "metric_name": metric_name},
|
|
})
|
|
// Return a dummy histogram instead of nil to prevent panics
|
|
return &metrics.Histogram{}
|
|
}
|
|
return ms.metrics_set_custom.GetOrCreateHistogram(ms.get_metrics_name(metric_name, labels))
|
|
}
|
|
|
|
func (ms *MetricsSetup) Increment(metric_name string, labels map[string]string) {
|
|
ms.RegisterMetricsCounter(metric_name, labels).Inc()
|
|
}
|
|
|
|
func (ms *MetricsSetup) IncrementFloat(metric_name string, labels map[string]string, value float64) {
|
|
ms.RegisterFloatCounter(metric_name, labels).Add(value)
|
|
}
|
|
|
|
func (ms *MetricsSetup) Set(metric_name string, labels map[string]string, value uint64) {
|
|
ms.RegisterMetricsCounter(metric_name, labels).Set(value)
|
|
}
|
|
|
|
func (ms *MetricsSetup) Update(metric_name string, labels map[string]string, value float64) {
|
|
ms.RegisterMetricsHistogram(metric_name, labels).Update(value)
|
|
}
|
|
|
|
func (ms *MetricsSetup) UpdateDuration(metric_name string, labels map[string]string, value time.Time) {
|
|
ms.RegisterMetricsHistogram(metric_name, labels).UpdateDuration(value)
|
|
}
|
|
|
|
func (ms *MetricsSetup) UpdateSummary(metric_name string, labels map[string]string, value float64) {
|
|
ms.RegisterMetricsSummary(metric_name, labels).Update(value)
|
|
}
|
|
|
|
func (ms *MetricsSetup) RemoveMetrics(metric_name string, labels map[string]string) {
|
|
ms.metrics_set_custom.UnregisterMetric(ms.get_metrics_name(metric_name, labels))
|
|
}
|
|
|
|
func (ms *MetricsSetup) PurgeMetrics() {
|
|
ms.metrics_set_custom.UnregisterAllMetrics()
|
|
}
|