2023-07-03 00:16:08 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-06-05 21:07:25 +02:00
|
|
|
"log"
|
2023-07-03 00:16:08 +02:00
|
|
|
"runtime"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
)
|
|
|
|
|
|
|
|
type multiCollectorMember interface {
|
|
|
|
describe(chan<- *prometheus.Desc)
|
|
|
|
collect(context.Context, chan<- prometheus.Metric) error
|
|
|
|
}
|
|
|
|
|
|
|
|
type multiCollector struct {
|
|
|
|
// Impose a timeout on collection if non-zero.
|
|
|
|
timeout time.Duration
|
|
|
|
|
|
|
|
members []multiCollectorMember
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ prometheus.Collector = (*multiCollector)(nil)
|
|
|
|
|
|
|
|
func newMultiCollector(m ...multiCollectorMember) *multiCollector {
|
|
|
|
return &multiCollector{
|
|
|
|
members: m,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *multiCollector) Describe(ch chan<- *prometheus.Desc) {
|
|
|
|
for _, i := range c.members {
|
|
|
|
i.describe(ch)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *multiCollector) Collect(ch chan<- prometheus.Metric) {
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
if c.timeout != 0 {
|
|
|
|
var cancel context.CancelFunc
|
|
|
|
ctx, cancel = context.WithTimeout(ctx, c.timeout)
|
|
|
|
defer cancel()
|
|
|
|
}
|
|
|
|
|
|
|
|
g, ctx := errgroup.WithContext(ctx)
|
|
|
|
g.SetLimit(runtime.GOMAXPROCS(0))
|
|
|
|
|
|
|
|
for _, i := range c.members {
|
|
|
|
collect := i.collect
|
|
|
|
g.Go(func() error { return collect(ctx, ch) })
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := g.Wait(); err != nil {
|
2024-06-05 21:07:25 +02:00
|
|
|
log.Printf("Metrics collection failed: %v", err.Error())
|
2023-07-03 00:16:08 +02:00
|
|
|
ch <- prometheus.NewInvalidMetric(
|
|
|
|
prometheus.NewDesc("paperless_error", "Metrics collection failed", nil, nil),
|
|
|
|
err)
|
|
|
|
}
|
|
|
|
}
|