420 lines
12 KiB
Go
420 lines
12 KiB
Go
// File: /home/meninjar/goprint/service/internal/infrastructure/monitoring/metrics.go
|
|
package monitoring
|
|
|
|
import (
|
|
"time"
|
|
|
|
"service/pkg/logger"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
|
)
|
|
|
|
// Metrics defines all Prometheus metrics for the GoPrint service
|
|
type Metrics struct {
|
|
// HTTP metrics
|
|
HttpRequestsTotal *prometheus.CounterVec
|
|
HttpRequestDuration *prometheus.HistogramVec
|
|
HttpResponseSize *prometheus.HistogramVec
|
|
HttpRequestsInFlight prometheus.Gauge
|
|
|
|
// Database metrics
|
|
DbConnections prometheus.Gauge
|
|
DbQueryDuration *prometheus.HistogramVec
|
|
DbQueryErrors *prometheus.CounterVec
|
|
DbActiveConnections *prometheus.GaugeVec
|
|
|
|
// Cache metrics
|
|
CacheHits prometheus.Counter
|
|
CacheMisses prometheus.Counter
|
|
CacheOperations *prometheus.CounterVec
|
|
CacheDuration *prometheus.HistogramVec
|
|
|
|
// Business logic metrics
|
|
EthnicOperations *prometheus.CounterVec
|
|
AuthOperations *prometheus.CounterVec
|
|
PersonOperations *prometheus.CounterVec
|
|
|
|
// Service health metrics
|
|
ServiceUptime prometheus.Counter
|
|
ServiceHealthStatus prometheus.Gauge
|
|
ExternalServiceStatus *prometheus.GaugeVec
|
|
|
|
// Resource usage metrics
|
|
MemoryUsage prometheus.Gauge
|
|
CPUUsage prometheus.Gauge
|
|
Goroutines prometheus.Gauge
|
|
|
|
// Logger untuk monitoring
|
|
logger logger.Logger
|
|
serviceName string
|
|
startTime time.Time
|
|
}
|
|
|
|
// NewMetrics creates a new instance of Prometheus metrics
|
|
func NewMetrics(serviceName string) *Metrics {
|
|
log := logger.Default().WithFields(
|
|
logger.String("component", "monitoring"),
|
|
logger.String("service", serviceName),
|
|
)
|
|
|
|
labels := []string{"method", "endpoint", "status"}
|
|
dbLabels := []string{"operation", "table", "database"}
|
|
cacheLabels := []string{"operation", "result"}
|
|
businessLabels := []string{"operation", "status", "entity"}
|
|
externalLabels := []string{"service", "status"}
|
|
|
|
metrics := &Metrics{
|
|
serviceName: serviceName,
|
|
logger: log,
|
|
startTime: time.Now(),
|
|
|
|
// HTTP metrics
|
|
HttpRequestsTotal: promauto.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "http_requests_total",
|
|
Help: "Total number of HTTP requests",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
labels,
|
|
),
|
|
HttpRequestDuration: promauto.NewHistogramVec(
|
|
prometheus.HistogramOpts{
|
|
Name: "http_request_duration_seconds",
|
|
Help: "HTTP request duration in seconds",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
Buckets: prometheus.DefBuckets,
|
|
},
|
|
labels,
|
|
),
|
|
HttpResponseSize: promauto.NewHistogramVec(
|
|
prometheus.HistogramOpts{
|
|
Name: "http_response_size_bytes",
|
|
Help: "HTTP response size in bytes",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
Buckets: prometheus.ExponentialBuckets(100, 10, 8),
|
|
},
|
|
labels,
|
|
),
|
|
HttpRequestsInFlight: promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "http_requests_in_flight",
|
|
Help: "Number of HTTP requests currently being processed",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
),
|
|
|
|
// Database metrics
|
|
DbConnections: promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "db_connections_active",
|
|
Help: "Number of active database connections",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
),
|
|
DbActiveConnections: promauto.NewGaugeVec(
|
|
prometheus.GaugeOpts{
|
|
Name: "db_connections_active_by_db",
|
|
Help: "Number of active database connections by database",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
[]string{"database"},
|
|
),
|
|
DbQueryDuration: promauto.NewHistogramVec(
|
|
prometheus.HistogramOpts{
|
|
Name: "db_query_duration_seconds",
|
|
Help: "Database query duration in seconds",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
Buckets: prometheus.DefBuckets,
|
|
},
|
|
dbLabels,
|
|
),
|
|
DbQueryErrors: promauto.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "db_query_errors_total",
|
|
Help: "Total number of database query errors",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
dbLabels,
|
|
),
|
|
|
|
// Cache metrics
|
|
CacheHits: promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "cache_hits_total",
|
|
Help: "Total number of cache hits",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
),
|
|
CacheMisses: promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "cache_misses_total",
|
|
Help: "Total number of cache misses",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
),
|
|
CacheOperations: promauto.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "cache_operations_total",
|
|
Help: "Total number of cache operations",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
cacheLabels,
|
|
),
|
|
CacheDuration: promauto.NewHistogramVec(
|
|
prometheus.HistogramOpts{
|
|
Name: "cache_operation_duration_seconds",
|
|
Help: "Cache operation duration in seconds",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
Buckets: prometheus.DefBuckets,
|
|
},
|
|
cacheLabels,
|
|
),
|
|
|
|
// Business logic metrics
|
|
EthnicOperations: promauto.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "ethnic_operations_total",
|
|
Help: "Total number of ethnic operations",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
businessLabels,
|
|
),
|
|
AuthOperations: promauto.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "auth_operations_total",
|
|
Help: "Total number of authentication operations",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
businessLabels,
|
|
),
|
|
PersonOperations: promauto.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "person_operations_total",
|
|
Help: "Total number of person operations",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
businessLabels,
|
|
),
|
|
|
|
// Service health metrics
|
|
ServiceUptime: promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "service_uptime_seconds",
|
|
Help: "Service uptime in seconds",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
),
|
|
ServiceHealthStatus: promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "service_health_status",
|
|
Help: "Service health status (1 = healthy, 0 = unhealthy)",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
),
|
|
ExternalServiceStatus: promauto.NewGaugeVec(
|
|
prometheus.GaugeOpts{
|
|
Name: "external_service_status",
|
|
Help: "External service status (1 = up, 0 = down)",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
externalLabels,
|
|
),
|
|
|
|
// Resource usage metrics
|
|
MemoryUsage: promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "memory_usage_bytes",
|
|
Help: "Memory usage in bytes",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
),
|
|
CPUUsage: promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "cpu_usage_percent",
|
|
Help: "CPU usage percentage",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
),
|
|
Goroutines: promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "goroutines_count",
|
|
Help: "Number of goroutines",
|
|
ConstLabels: prometheus.Labels{"service": serviceName},
|
|
},
|
|
),
|
|
}
|
|
|
|
log.Info("Prometheus metrics initialized successfully",
|
|
logger.String("service", serviceName),
|
|
)
|
|
|
|
return metrics
|
|
}
|
|
|
|
// RecordHTTPRequest records HTTP request metrics
|
|
func (m *Metrics) RecordHTTPRequest(method, endpoint, status string, duration time.Duration, responseSize int64) {
|
|
labels := prometheus.Labels{
|
|
"method": method,
|
|
"endpoint": endpoint,
|
|
"status": status,
|
|
}
|
|
|
|
m.HttpRequestsTotal.With(labels).Inc()
|
|
m.HttpRequestDuration.With(labels).Observe(duration.Seconds())
|
|
m.HttpResponseSize.With(labels).Observe(float64(responseSize))
|
|
|
|
m.logger.Debug("HTTP request recorded",
|
|
logger.String("method", method),
|
|
logger.String("endpoint", endpoint),
|
|
logger.String("status", status),
|
|
logger.Float64("duration_seconds", duration.Seconds()),
|
|
logger.Int64("response_size", responseSize),
|
|
)
|
|
}
|
|
|
|
// RecordDBQuery records database query metrics
|
|
func (m *Metrics) RecordDBQuery(operation, table, database string, duration time.Duration, err error) {
|
|
labels := prometheus.Labels{
|
|
"operation": operation,
|
|
"table": table,
|
|
"database": database,
|
|
}
|
|
|
|
m.DbQueryDuration.With(labels).Observe(duration.Seconds())
|
|
if err != nil {
|
|
m.DbQueryErrors.With(labels).Inc()
|
|
m.logger.Error("Database query error recorded",
|
|
logger.String("operation", operation),
|
|
logger.String("table", table),
|
|
logger.String("database", database),
|
|
logger.ErrorField(err),
|
|
)
|
|
} else {
|
|
m.logger.Debug("Database query recorded",
|
|
logger.String("operation", operation),
|
|
logger.String("table", table),
|
|
logger.String("database", database),
|
|
logger.Float64("duration_seconds", duration.Seconds()),
|
|
)
|
|
}
|
|
}
|
|
|
|
// RecordCacheOperation records cache operation metrics
|
|
func (m *Metrics) RecordCacheOperation(operation string, hit bool, duration time.Duration) {
|
|
if hit {
|
|
m.CacheHits.Inc()
|
|
} else {
|
|
m.CacheMisses.Inc()
|
|
}
|
|
|
|
result := "hit"
|
|
if !hit {
|
|
result = "miss"
|
|
}
|
|
|
|
labels := prometheus.Labels{
|
|
"operation": operation,
|
|
"result": result,
|
|
}
|
|
|
|
m.CacheOperations.With(labels).Inc()
|
|
m.CacheDuration.With(labels).Observe(duration.Seconds())
|
|
|
|
m.logger.Debug("Cache operation recorded",
|
|
logger.String("operation", operation),
|
|
logger.String("result", result),
|
|
logger.Float64("duration_seconds", duration.Seconds()),
|
|
)
|
|
}
|
|
|
|
// RecordBusinessOperation records business logic operation metrics
|
|
func (m *Metrics) RecordBusinessOperation(operationType, operation, status string) {
|
|
var counter *prometheus.CounterVec
|
|
|
|
switch operationType {
|
|
case "ethnic":
|
|
counter = m.EthnicOperations
|
|
case "auth":
|
|
counter = m.AuthOperations
|
|
case "person":
|
|
counter = m.PersonOperations
|
|
default:
|
|
m.logger.Warn("Unknown business operation type",
|
|
logger.String("type", operationType),
|
|
logger.String("operation", operation),
|
|
)
|
|
return
|
|
}
|
|
|
|
labels := prometheus.Labels{
|
|
"operation": operation,
|
|
"status": status,
|
|
"entity": operationType,
|
|
}
|
|
|
|
counter.With(labels).Inc()
|
|
|
|
m.logger.Debug("Business operation recorded",
|
|
logger.String("type", operationType),
|
|
logger.String("operation", operation),
|
|
logger.String("status", status),
|
|
)
|
|
}
|
|
|
|
// UpdateServiceHealth updates service health status
|
|
func (m *Metrics) UpdateServiceHealth(healthy bool) {
|
|
if healthy {
|
|
m.ServiceHealthStatus.Set(1)
|
|
m.logger.Info("Service health status updated to healthy")
|
|
} else {
|
|
m.ServiceHealthStatus.Set(0)
|
|
m.logger.Error("Service health status updated to unhealthy")
|
|
}
|
|
}
|
|
|
|
// UpdateExternalServiceStatus updates external service status
|
|
func (m *Metrics) UpdateExternalServiceStatus(service string, status bool) {
|
|
value := 0.0
|
|
statusStr := "down"
|
|
if status {
|
|
value = 1.0
|
|
statusStr = "up"
|
|
}
|
|
|
|
labels := prometheus.Labels{
|
|
"service": service,
|
|
"status": statusStr,
|
|
}
|
|
|
|
m.ExternalServiceStatus.With(labels).Set(value)
|
|
|
|
m.logger.Info("External service status updated",
|
|
logger.String("service", service),
|
|
logger.String("status", statusStr),
|
|
)
|
|
}
|
|
|
|
// UpdateResourceUsage updates resource usage metrics
|
|
func (m *Metrics) UpdateResourceUsage(memory, cpu float64, goroutines int) {
|
|
m.MemoryUsage.Set(memory)
|
|
m.CPUUsage.Set(cpu)
|
|
m.Goroutines.Set(float64(goroutines))
|
|
|
|
m.logger.Debug("Resource usage updated",
|
|
logger.Float64("memory_mb", memory),
|
|
logger.Float64("cpu_percent", cpu),
|
|
logger.Int("goroutines", goroutines),
|
|
)
|
|
}
|
|
|
|
// IncrementUptime increments service uptime
|
|
func (m *Metrics) IncrementUptime(seconds float64) {
|
|
m.ServiceUptime.Add(seconds)
|
|
}
|
|
|
|
// GetUptime returns current uptime in seconds
|
|
func (m *Metrics) GetUptime() float64 {
|
|
return time.Since(m.startTime).Seconds()
|
|
}
|