apcupsd_exporter/apcupsdexporter.go

96 lines
2.5 KiB
Go

// Package apcupsdexporter provides the Exporter type used in the
// apcupsd_exporter Prometheus exporter.
package apcupsdexporter
import (
"context"
"fmt"
"log"
"time"
"github.com/mdlayher/apcupsd"
"github.com/prometheus/client_golang/prometheus"
)
// TODO(mdlayher): rework this with metricslite.
const (
// namespace is the top-level namespace for this apcupsd exporter.
namespace = "apcupsd"
)
// An Exporter is a Prometheus exporter for apcupsd metrics.
// It wraps all apcupsd metrics collectors and provides a single global
// exporter which can serve metrics.
//
// It implements the prometheus.Collector interface in order to register
// with Prometheus.
type Exporter struct {
clientFn ClientFunc
}
var _ prometheus.Collector = &Exporter{}
// A ClientFunc is a function which can return an apcupsd NIS client.
// ClientFuncs are invoked on each Prometheus scrape, so that connections
// can be short-lived and less likely to time out or fail.
type ClientFunc func(ctx context.Context) (*apcupsd.Client, error)
// New creates a new Exporter which collects metrics by creating a apcupsd
// client using the input ClientFunc.
func New(fn ClientFunc) *Exporter {
return &Exporter{
clientFn: fn,
}
}
// Describe sends all the descriptors of the collectors included to
// the provided channel.
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
// Don't care, we'll get this error on Collect.
_ = e.withCollectors(func(cs []prometheus.Collector) {
for _, c := range cs {
c.Describe(ch)
}
})
}
// Collect sends the collected metrics from each of the collectors to
// prometheus.
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
err := e.withCollectors(func(cs []prometheus.Collector) {
for _, c := range cs {
c.Collect(ch)
}
})
// This is a hack but it allows us to report failure to dial without
// reworking significant portions of the code.
if err != nil {
log.Println(err)
ch <- prometheus.NewInvalidMetric(NewUPSCollector(nil).Info, err)
return
}
}
// withCollectors sets up an apcupsd client and creates a set of prometheus
// collectors. It invokes the input closure and then cleans up after the
// closure returns.
func (e *Exporter) withCollectors(fn func(cs []prometheus.Collector)) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
c, err := e.clientFn(ctx)
if err != nil {
return fmt.Errorf("error creating apcupsd client: %v", err)
}
defer c.Close()
cs := []prometheus.Collector{
NewUPSCollector(c),
}
fn(cs)
return nil
}