mirror of
https://github.com/smallstep/certificates.git
synced 2024-10-31 03:20:16 +00:00
dd1ff9c15b
Implementation of the http://{metricsAddress}/metrics Prometheus endpoint.
197 lines
5.2 KiB
Go
197 lines
5.2 KiB
Go
// Package metrix implements stats-related functionality.
|
|
package metrix
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/smallstep/certificates/authority/provisioner"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
)
|
|
|
|
// New initializes and returns a new [Meter].
|
|
func New() (m *Meter) {
|
|
initializedAt := time.Now()
|
|
|
|
m = &Meter{
|
|
uptime: prometheus.NewGaugeFunc(
|
|
prometheus.GaugeOpts(opts(
|
|
"",
|
|
"uptime_seconds",
|
|
"Number of seconds since service start",
|
|
)),
|
|
func() float64 {
|
|
return float64(time.Since(initializedAt) / time.Second)
|
|
},
|
|
),
|
|
ssh: newProvisionerInstruments("ssh"),
|
|
x509: newProvisionerInstruments("x509"),
|
|
kms: &kms{
|
|
signed: prometheus.NewCounter(prometheus.CounterOpts(opts("kms", "signed", "Number of KMS-backed signatures"))),
|
|
errors: prometheus.NewCounter(prometheus.CounterOpts(opts("kms", "errors", "Number of KMS-related errors"))),
|
|
},
|
|
}
|
|
|
|
reg := prometheus.NewRegistry()
|
|
|
|
reg.MustRegister(
|
|
m.uptime,
|
|
m.ssh.rekeyed,
|
|
m.ssh.renewed,
|
|
m.ssh.signed,
|
|
m.x509.rekeyed,
|
|
m.x509.renewed,
|
|
m.x509.signed,
|
|
m.kms.signed,
|
|
m.kms.errors,
|
|
)
|
|
|
|
h := promhttp.HandlerFor(reg, promhttp.HandlerOpts{
|
|
Registry: reg,
|
|
Timeout: 5 * time.Second,
|
|
MaxRequestsInFlight: 10,
|
|
})
|
|
|
|
mux := http.NewServeMux()
|
|
mux.Handle("/metrics", h)
|
|
m.Handler = mux
|
|
|
|
return
|
|
}
|
|
|
|
// Meter wraps the functionality of a Prometheus-compatible HTTP handler.
|
|
type Meter struct {
|
|
http.Handler
|
|
|
|
uptime prometheus.GaugeFunc
|
|
ssh *provisionerInstruments
|
|
x509 *provisionerInstruments
|
|
kms *kms
|
|
}
|
|
|
|
// SSHRekeyed implements [authority.Meter] for [Meter].
|
|
func (m *Meter) SSHRekeyed(p provisioner.Interface, err error) {
|
|
incrProvisionerCounter(m.ssh.rekeyed, p, err)
|
|
}
|
|
|
|
// SSHRenewed implements [authority.Meter] for [Meter].
|
|
func (m *Meter) SSHRenewed(p provisioner.Interface, err error) {
|
|
incrProvisionerCounter(m.ssh.renewed, p, err)
|
|
}
|
|
|
|
// SSHSigned implements [authority.Meter] for [Meter].
|
|
func (m *Meter) SSHSigned(p provisioner.Interface, err error) {
|
|
incrProvisionerCounter(m.ssh.signed, p, err)
|
|
}
|
|
|
|
// SSHAuthorized implements [authority.Meter] for [Meter].
|
|
func (m *Meter) SSHWebhookAuthorized(p provisioner.Interface, err error) {
|
|
incrProvisionerCounter(m.ssh.webhookAuthorized, p, err)
|
|
}
|
|
|
|
// SSHEnriched implements [authority.Meter] for [Meter].
|
|
func (m *Meter) SSHWebhookEnriched(p provisioner.Interface, err error) {
|
|
incrProvisionerCounter(m.ssh.webhookEnriched, p, err)
|
|
}
|
|
|
|
// X509Rekeyed implements [authority.Meter] for [Meter].
|
|
func (m *Meter) X509Rekeyed(p provisioner.Interface, err error) {
|
|
incrProvisionerCounter(m.x509.rekeyed, p, err)
|
|
}
|
|
|
|
// X509Renewed implements [authority.Meter] for [Meter].
|
|
func (m *Meter) X509Renewed(p provisioner.Interface, err error) {
|
|
incrProvisionerCounter(m.x509.renewed, p, err)
|
|
}
|
|
|
|
// X509Signed implements [authority.Meter] for [Meter].
|
|
func (m *Meter) X509Signed(p provisioner.Interface, err error) {
|
|
incrProvisionerCounter(m.x509.signed, p, err)
|
|
}
|
|
|
|
// X509Authorized implements [authority.Meter] for [Meter].
|
|
func (m *Meter) X509WebhookAuthorized(p provisioner.Interface, err error) {
|
|
incrProvisionerCounter(m.x509.webhookAuthorized, p, err)
|
|
}
|
|
|
|
// X509Enriched implements [authority.Meter] for [Meter].
|
|
func (m *Meter) X509WebhookEnriched(p provisioner.Interface, err error) {
|
|
incrProvisionerCounter(m.x509.webhookEnriched, p, err)
|
|
}
|
|
|
|
func incrProvisionerCounter(cv *prometheus.CounterVec, p provisioner.Interface, err error) {
|
|
var name string
|
|
if p != nil {
|
|
name = p.GetName()
|
|
}
|
|
|
|
cv.WithLabelValues(name, strconv.FormatBool(err == nil)).Inc()
|
|
}
|
|
|
|
// KMSSigned implements [authority.Meter] for [Meter].
|
|
func (m *Meter) KMSSigned(err error) {
|
|
if err == nil {
|
|
m.kms.signed.Inc()
|
|
} else {
|
|
m.kms.errors.Inc()
|
|
}
|
|
}
|
|
|
|
// provisionerInstruments wraps the counters exported by provisioners.
|
|
type provisionerInstruments struct {
|
|
rekeyed *prometheus.CounterVec
|
|
renewed *prometheus.CounterVec
|
|
signed *prometheus.CounterVec
|
|
|
|
webhookAuthorized *prometheus.CounterVec
|
|
webhookEnriched *prometheus.CounterVec
|
|
}
|
|
|
|
func newProvisionerInstruments(subsystem string) *provisionerInstruments {
|
|
return &provisionerInstruments{
|
|
rekeyed: newCounterVec(subsystem, "rekeyed_total", "Number of certificates rekeyed",
|
|
"provisioner",
|
|
"success",
|
|
),
|
|
renewed: newCounterVec(subsystem, "renewed_total", "Number of certificates renewed",
|
|
"provisioner",
|
|
"success",
|
|
),
|
|
signed: newCounterVec(subsystem, "signed_total", "Number of certificates signed",
|
|
"provisioner",
|
|
"success",
|
|
),
|
|
webhookAuthorized: newCounterVec(subsystem, "webhook_authorized_total", "Number of authorizing webhooks called",
|
|
"provisioner",
|
|
"success",
|
|
),
|
|
webhookEnriched: newCounterVec(subsystem, "webhook_enriched_total", "Number of enriching webhooks called",
|
|
"provisioner",
|
|
"success",
|
|
),
|
|
}
|
|
}
|
|
|
|
type kms struct {
|
|
signed prometheus.Counter
|
|
errors prometheus.Counter
|
|
}
|
|
|
|
func newCounterVec(subsystem, name, help string, labels ...string) *prometheus.CounterVec {
|
|
opts := opts(subsystem, name, help)
|
|
|
|
return prometheus.NewCounterVec(prometheus.CounterOpts(opts), labels)
|
|
}
|
|
|
|
func opts(subsystem, name, help string) prometheus.Opts {
|
|
return prometheus.Opts{
|
|
Namespace: "step_ca",
|
|
Subsystem: subsystem,
|
|
Name: name,
|
|
Help: help,
|
|
}
|
|
}
|