141 lines
4.0 KiB
Go
141 lines
4.0 KiB
Go
package logr
|
|
|
|
import "time"
|
|
|
|
const (
|
|
DefMetricsUpdateFreqMillis = 15000 // 15 seconds
|
|
)
|
|
|
|
// Counter is a simple metrics sink that can only increment a value.
|
|
// Implementations are external to Logr and provided via `MetricsCollector`.
|
|
type Counter interface {
|
|
// Inc increments the counter by 1. Use Add to increment it by arbitrary non-negative values.
|
|
Inc()
|
|
// Add adds the given value to the counter. It panics if the value is < 0.
|
|
Add(float64)
|
|
}
|
|
|
|
// Gauge is a simple metrics sink that can receive values and increase or decrease.
|
|
// Implementations are external to Logr and provided via `MetricsCollector`.
|
|
type Gauge interface {
|
|
// Set sets the Gauge to an arbitrary value.
|
|
Set(float64)
|
|
// Add adds the given value to the Gauge. (The value can be negative, resulting in a decrease of the Gauge.)
|
|
Add(float64)
|
|
// Sub subtracts the given value from the Gauge. (The value can be negative, resulting in an increase of the Gauge.)
|
|
Sub(float64)
|
|
}
|
|
|
|
// MetricsCollector provides a way for users of this Logr package to have metrics pushed
|
|
// in an efficient way to any backend, e.g. Prometheus.
|
|
// For each target added to Logr, the supplied MetricsCollector will provide a Gauge
|
|
// and Counters that will be called frequently as logging occurs.
|
|
type MetricsCollector interface {
|
|
// QueueSizeGauge returns a Gauge that will be updated by the named target.
|
|
QueueSizeGauge(target string) (Gauge, error)
|
|
// LoggedCounter returns a Counter that will be incremented by the named target.
|
|
LoggedCounter(target string) (Counter, error)
|
|
// ErrorCounter returns a Counter that will be incremented by the named target.
|
|
ErrorCounter(target string) (Counter, error)
|
|
// DroppedCounter returns a Counter that will be incremented by the named target.
|
|
DroppedCounter(target string) (Counter, error)
|
|
// BlockedCounter returns a Counter that will be incremented by the named target.
|
|
BlockedCounter(target string) (Counter, error)
|
|
}
|
|
|
|
// TargetWithMetrics is a target that provides metrics.
|
|
type TargetWithMetrics interface {
|
|
EnableMetrics(collector MetricsCollector, updateFreqMillis int64) error
|
|
}
|
|
|
|
type metrics struct {
|
|
collector MetricsCollector
|
|
updateFreqMillis int64
|
|
queueSizeGauge Gauge
|
|
loggedCounter Counter
|
|
errorCounter Counter
|
|
done chan struct{}
|
|
}
|
|
|
|
// initMetrics initializes metrics collection.
|
|
func (lgr *Logr) initMetrics(collector MetricsCollector, updatefreq int64) {
|
|
lgr.stopMetricsUpdater()
|
|
|
|
if collector == nil {
|
|
lgr.metricsMux.Lock()
|
|
lgr.metrics = nil
|
|
lgr.metricsMux.Unlock()
|
|
return
|
|
}
|
|
|
|
metrics := &metrics{
|
|
collector: collector,
|
|
updateFreqMillis: updatefreq,
|
|
done: make(chan struct{}),
|
|
}
|
|
metrics.queueSizeGauge, _ = collector.QueueSizeGauge("_logr")
|
|
metrics.loggedCounter, _ = collector.LoggedCounter("_logr")
|
|
metrics.errorCounter, _ = collector.ErrorCounter("_logr")
|
|
|
|
lgr.metricsMux.Lock()
|
|
lgr.metrics = metrics
|
|
lgr.metricsMux.Unlock()
|
|
|
|
go lgr.startMetricsUpdater()
|
|
}
|
|
|
|
func (lgr *Logr) setQueueSizeGauge(val float64) {
|
|
lgr.metricsMux.RLock()
|
|
defer lgr.metricsMux.RUnlock()
|
|
|
|
if lgr.metrics != nil {
|
|
lgr.metrics.queueSizeGauge.Set(val)
|
|
}
|
|
}
|
|
|
|
func (lgr *Logr) incLoggedCounter() {
|
|
lgr.metricsMux.RLock()
|
|
defer lgr.metricsMux.RUnlock()
|
|
|
|
if lgr.metrics != nil {
|
|
lgr.metrics.loggedCounter.Inc()
|
|
}
|
|
}
|
|
|
|
func (lgr *Logr) incErrorCounter() {
|
|
lgr.metricsMux.RLock()
|
|
defer lgr.metricsMux.RUnlock()
|
|
|
|
if lgr.metrics != nil {
|
|
lgr.metrics.errorCounter.Inc()
|
|
}
|
|
}
|
|
|
|
// startMetricsUpdater updates the metrics for any polled values every `metricsUpdateFreqSecs` seconds until
|
|
// logr is closed.
|
|
func (lgr *Logr) startMetricsUpdater() {
|
|
for {
|
|
lgr.metricsMux.RLock()
|
|
metrics := lgr.metrics
|
|
c := metrics.done
|
|
lgr.metricsMux.RUnlock()
|
|
|
|
select {
|
|
case <-c:
|
|
return
|
|
case <-time.After(time.Duration(metrics.updateFreqMillis) * time.Millisecond):
|
|
lgr.setQueueSizeGauge(float64(len(lgr.in)))
|
|
}
|
|
}
|
|
}
|
|
|
|
func (lgr *Logr) stopMetricsUpdater() {
|
|
lgr.metricsMux.Lock()
|
|
defer lgr.metricsMux.Unlock()
|
|
|
|
if lgr.metrics != nil && lgr.metrics.done != nil {
|
|
close(lgr.metrics.done)
|
|
lgr.metrics.done = nil
|
|
}
|
|
}
|