Observability
Metric instruments for monitoring Vault operations.
The metrics package provides a set of metric interfaces and a pre-built Collector with 13 instruments covering all Vault operations. The interfaces are designed to be compatible with popular metric libraries (Prometheus, OpenTelemetry, StatsD) and can be bridged to any backend via the MetricFactory.
Architecture
metrics.MetricFactory (creates named Counter/Histogram instances)
└── metrics.Collector (holds all 13 Vault instruments)
metrics.NoopFactory (no-op implementation for testing/disabled metrics)
└── metrics.NewNoopCollector()The Collector is a flat struct with one field per instrument. You pass a MetricFactory to NewCollector and it creates all instruments with standardized names. Code throughout Vault increments or observes these instruments at the appropriate points.
Installation
import "github.com/xraph/vault/metrics"Interfaces
Counter
A monotonically increasing counter for tracking occurrences.
type Counter interface {
Inc()
Add(float64)
}| Method | Description |
|---|---|
Inc() | Increments by 1 |
Add(float64) | Adds an arbitrary non-negative value |
Histogram
Observes a distribution of values (typically latencies or sizes).
type Histogram interface {
Observe(float64)
}| Method | Description |
|---|---|
Observe(float64) | Records a single observation |
MetricFactory
Creates named metric instances. Implement this interface to bridge Vault metrics to your preferred monitoring backend.
type MetricFactory interface {
Counter(name string) Counter
Histogram(name string) Histogram
}Collector
The Collector holds all 13 Vault metric instruments. Each field is initialized by the factory when NewCollector is called.
type Collector struct {
SecretAccessed Counter
SecretSet Counter
SecretDeleted Counter
SecretRotated Counter
FlagEvaluated Counter
FlagEvalTime Histogram
ConfigRead Counter
ConfigWritten Counter
OverrideRead Counter
AuditRecorded Counter
Encrypted Counter
Decrypted Counter
SourceLatency Histogram
}Creating a Collector
func NewCollector(f MetricFactory) *Collectorcollector := metrics.NewCollector(myPrometheusFactory)Metric naming table
| Field | Metric name | Type | Description |
|---|---|---|---|
SecretAccessed | vault_secret_accessed_total | Counter | Secret read operations |
SecretSet | vault_secret_set_total | Counter | Secret write operations |
SecretDeleted | vault_secret_deleted_total | Counter | Secret delete operations |
SecretRotated | vault_secret_rotated_total | Counter | Secret rotation completions |
FlagEvaluated | vault_flag_evaluated_total | Counter | Flag evaluation calls |
FlagEvalTime | vault_flag_eval_duration_seconds | Histogram | Flag evaluation latency |
ConfigRead | vault_config_read_total | Counter | Config read operations |
ConfigWritten | vault_config_written_total | Counter | Config write operations |
OverrideRead | vault_override_read_total | Counter | Override resolution reads |
AuditRecorded | vault_audit_recorded_total | Counter | Audit entries recorded |
Encrypted | vault_encrypted_total | Counter | Encryption operations |
Decrypted | vault_decrypted_total | Counter | Decryption operations |
SourceLatency | vault_source_latency_seconds | Histogram | Configuration source read latency |
Using the Collector
// After a secret is read.
collector.SecretAccessed.Inc()
// After a secret is written.
collector.SecretSet.Inc()
// After a flag evaluation.
start := time.Now()
value := flagService.Bool(ctx, "my-flag", false)
collector.FlagEvaluated.Inc()
collector.FlagEvalTime.Observe(time.Since(start).Seconds())
// After an encryption operation.
collector.Encrypted.Inc()
// Observe source read latency.
start = time.Now()
val, err := source.Get(ctx, "key")
collector.SourceLatency.Observe(time.Since(start).Seconds())NoopFactory
The NoopFactory creates no-op metric instances that silently discard all observations. Use it when metrics collection is disabled or in tests.
type NoopFactory struct{}
func (NoopFactory) Counter(string) Counter { return noopCounter{} }
func (NoopFactory) Histogram(string) Histogram { return noopHistogram{} }NewNoopCollector
Convenience function that creates a Collector with all no-op instruments.
func NewNoopCollector() *Collectorcollector := metrics.NewNoopCollector()
// All operations are silently discarded.
collector.SecretAccessed.Inc() // no-opPrometheus bridge example
Bridge Vault metrics to Prometheus by implementing MetricFactory:
package prommetrics
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/xraph/vault/metrics"
)
// PrometheusFactory creates Prometheus-backed metric instances.
type PrometheusFactory struct {
registry *prometheus.Registry
}
// NewPrometheusFactory creates a factory with the given registry.
func NewPrometheusFactory(reg *prometheus.Registry) *PrometheusFactory {
return &PrometheusFactory{registry: reg}
}
// Counter creates a Prometheus counter.
func (f *PrometheusFactory) Counter(name string) metrics.Counter {
c := prometheus.NewCounter(prometheus.CounterOpts{
Name: name,
Help: name,
})
f.registry.MustRegister(c)
return &promCounter{counter: c}
}
// Histogram creates a Prometheus histogram.
func (f *PrometheusFactory) Histogram(name string) metrics.Histogram {
h := prometheus.NewHistogram(prometheus.HistogramOpts{
Name: name,
Help: name,
Buckets: prometheus.DefBuckets,
})
f.registry.MustRegister(h)
return &promHistogram{histogram: h}
}
// promCounter wraps prometheus.Counter to implement metrics.Counter.
type promCounter struct {
counter prometheus.Counter
}
func (c *promCounter) Inc() { c.counter.Inc() }
func (c *promCounter) Add(v float64) { c.counter.Add(v) }
// promHistogram wraps prometheus.Histogram to implement metrics.Histogram.
type promHistogram struct {
histogram prometheus.Histogram
}
func (h *promHistogram) Observe(v float64) { h.histogram.Observe(v) }Using the Prometheus bridge:
package main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/xraph/vault/metrics"
)
func main() {
reg := prometheus.NewRegistry()
factory := prommetrics.NewPrometheusFactory(reg)
// Create the Vault collector with Prometheus backend.
collector := metrics.NewCollector(factory)
// Use the collector throughout your application.
collector.SecretAccessed.Inc()
collector.FlagEvalTime.Observe(0.003)
// Expose metrics via HTTP.
http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
http.ListenAndServe(":9090", nil)
}Custom backend example
Implement MetricFactory for any backend (StatsD, Datadog, OpenTelemetry, etc.):
type StatsDFactory struct {
client *statsd.Client
}
func (f *StatsDFactory) Counter(name string) metrics.Counter {
return &statsdCounter{client: f.client, name: name}
}
func (f *StatsDFactory) Histogram(name string) metrics.Histogram {
return &statsdHistogram{client: f.client, name: name}
}
type statsdCounter struct {
client *statsd.Client
name string
}
func (c *statsdCounter) Inc() { c.client.Incr(c.name, nil, 1) }
func (c *statsdCounter) Add(v float64) { c.client.Count(c.name, int64(v), nil, 1) }
type statsdHistogram struct {
client *statsd.Client
name string
}
func (h *statsdHistogram) Observe(v float64) {
h.client.Histogram(h.name, v, nil, 1)
}Full example
package main
import (
"fmt"
"time"
"github.com/xraph/vault/metrics"
)
func main() {
// For production: use a real factory (Prometheus, StatsD, etc.).
// For development/testing: use the no-op collector.
collector := metrics.NewNoopCollector()
// Simulate operations.
collector.SecretAccessed.Inc()
collector.SecretSet.Inc()
collector.SecretSet.Inc()
collector.FlagEvaluated.Add(100)
// Track latency.
start := time.Now()
time.Sleep(5 * time.Millisecond) // simulate work
collector.FlagEvalTime.Observe(time.Since(start).Seconds())
fmt.Println("Metrics recorded (no-op in this example)")
}