Vault

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)
}
MethodDescription
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)
}
MethodDescription
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) *Collector
collector := metrics.NewCollector(myPrometheusFactory)

Metric naming table

FieldMetric nameTypeDescription
SecretAccessedvault_secret_accessed_totalCounterSecret read operations
SecretSetvault_secret_set_totalCounterSecret write operations
SecretDeletedvault_secret_deleted_totalCounterSecret delete operations
SecretRotatedvault_secret_rotated_totalCounterSecret rotation completions
FlagEvaluatedvault_flag_evaluated_totalCounterFlag evaluation calls
FlagEvalTimevault_flag_eval_duration_secondsHistogramFlag evaluation latency
ConfigReadvault_config_read_totalCounterConfig read operations
ConfigWrittenvault_config_written_totalCounterConfig write operations
OverrideReadvault_override_read_totalCounterOverride resolution reads
AuditRecordedvault_audit_recorded_totalCounterAudit entries recorded
Encryptedvault_encrypted_totalCounterEncryption operations
Decryptedvault_decrypted_totalCounterDecryption operations
SourceLatencyvault_source_latency_secondsHistogramConfiguration 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() *Collector
collector := metrics.NewNoopCollector()
// All operations are silently discarded.
collector.SecretAccessed.Inc() // no-op

Prometheus 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)")
}

On this page