From d74a7fb0b6229d8d9fd96c221d55ff78af576722 Mon Sep 17 00:00:00 2001 From: Arianna Vespri Date: Sun, 26 Nov 2023 14:49:09 +0100 Subject: [PATCH] start adding support for units Signed-off-by: Arianna Vespri --- go.mod | 4 ++++ go.sum | 8 +++---- prometheus/build_info_collector.go | 1 + prometheus/collectors/dbstats_collector.go | 9 ++++++++ prometheus/counter.go | 3 +++ prometheus/desc.go | 15 ++++++++---- prometheus/desc_test.go | 1 + prometheus/example_clustermanager_test.go | 2 ++ prometheus/example_metricvec_test.go | 5 ++-- prometheus/examples_test.go | 9 ++++++-- prometheus/expvar_collector_test.go | 3 +++ prometheus/gauge.go | 3 +++ prometheus/gauge_test.go | 2 +- prometheus/go_collector.go | 27 ++++++++++++++++++++++ prometheus/go_collector_latest.go | 1 + prometheus/histogram.go | 5 ++++ prometheus/metric.go | 3 +++ prometheus/metric_test.go | 2 +- prometheus/process_collector.go | 7 ++++++ prometheus/promhttp/http_test.go | 10 ++++---- prometheus/registry_test.go | 2 +- prometheus/summary.go | 5 ++++ prometheus/testutil/testutil_test.go | 4 ++-- prometheus/untyped.go | 1 + prometheus/value_test.go | 2 ++ prometheus/wrap.go | 3 ++- 26 files changed, 113 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index a70491263..88ae88504 100644 --- a/go.mod +++ b/go.mod @@ -30,3 +30,7 @@ require ( ) exclude github.com/prometheus/client_golang v1.12.1 + +replace github.com/prometheus/common => github.com/vesari/common v0.0.0-20231121140958-784d3aad4c30 + +replace github.com/prometheus/client_model => github.com/vesari/client_model v0.0.0-20231118150741-19723af61627 diff --git a/go.sum b/go.sum index 7e031b561..c8f442a49 100644 --- a/go.sum +++ b/go.sum @@ -33,10 +33,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -44,6 +40,10 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/vesari/client_model v0.0.0-20231118150741-19723af61627 h1:pJsecGZFkJIN3ipp7fS8hLDK0Dcnk2JVxXds3Dev3dQ= +github.com/vesari/client_model v0.0.0-20231118150741-19723af61627/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/vesari/common v0.0.0-20231121140958-784d3aad4c30 h1:WaoSRlUM9CilXfZwJ5WIsFJKLnwJ6/WZjyT1oiiRO7s= +github.com/vesari/common v0.0.0-20231121140958-784d3aad4c30/go.mod h1:F2CatmaM24xsPNg4EqskJKMF+Tl27WbRF+Exgus+vOw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= diff --git a/prometheus/build_info_collector.go b/prometheus/build_info_collector.go index 450189f35..3f1fe169a 100644 --- a/prometheus/build_info_collector.go +++ b/prometheus/build_info_collector.go @@ -30,6 +30,7 @@ func NewBuildInfoCollector() Collector { NewDesc( "go_build_info", "Build information about the main Go module.", + "", nil, Labels{"path": path, "version": version, "checksum": sum}, ), GaugeValue, 1)} diff --git a/prometheus/collectors/dbstats_collector.go b/prometheus/collectors/dbstats_collector.go index d5a7279fb..22ab51139 100644 --- a/prometheus/collectors/dbstats_collector.go +++ b/prometheus/collectors/dbstats_collector.go @@ -46,46 +46,55 @@ func NewDBStatsCollector(db *sql.DB, dbName string) prometheus.Collector { maxOpenConnections: prometheus.NewDesc( fqName("max_open_connections"), "Maximum number of open connections to the database.", + "", nil, prometheus.Labels{"db_name": dbName}, ), openConnections: prometheus.NewDesc( fqName("open_connections"), "The number of established connections both in use and idle.", + "", nil, prometheus.Labels{"db_name": dbName}, ), inUseConnections: prometheus.NewDesc( fqName("in_use_connections"), "The number of connections currently in use.", + "", nil, prometheus.Labels{"db_name": dbName}, ), idleConnections: prometheus.NewDesc( fqName("idle_connections"), "The number of idle connections.", + "", nil, prometheus.Labels{"db_name": dbName}, ), waitCount: prometheus.NewDesc( fqName("wait_count_total"), "The total number of connections waited for.", + "", nil, prometheus.Labels{"db_name": dbName}, ), waitDuration: prometheus.NewDesc( fqName("wait_duration_seconds_total"), "The total time blocked waiting for a new connection.", + "seconds", nil, prometheus.Labels{"db_name": dbName}, ), maxIdleClosed: prometheus.NewDesc( fqName("max_idle_closed_total"), "The total number of connections closed due to SetMaxIdleConns.", + "", nil, prometheus.Labels{"db_name": dbName}, ), maxIdleTimeClosed: prometheus.NewDesc( fqName("max_idle_time_closed_total"), "The total number of connections closed due to SetConnMaxIdleTime.", + "", nil, prometheus.Labels{"db_name": dbName}, ), maxLifetimeClosed: prometheus.NewDesc( fqName("max_lifetime_closed_total"), "The total number of connections closed due to SetConnMaxLifetime.", + "", nil, prometheus.Labels{"db_name": dbName}, ), } diff --git a/prometheus/counter.go b/prometheus/counter.go index 4ce84e7a8..eef38bc30 100644 --- a/prometheus/counter.go +++ b/prometheus/counter.go @@ -88,6 +88,7 @@ func NewCounter(opts CounterOpts) Counter { desc := NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, nil, opts.ConstLabels, ) @@ -203,6 +204,7 @@ func (v2) NewCounterVec(opts CounterVecOpts) *CounterVec { desc := V2.NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, opts.VariableLabels, opts.ConstLabels, ) @@ -352,6 +354,7 @@ func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc { return newValueFunc(NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, nil, opts.ConstLabels, ), CounterValue, function) diff --git a/prometheus/desc.go b/prometheus/desc.go index 68ffe3c24..c32dbf63e 100644 --- a/prometheus/desc.go +++ b/prometheus/desc.go @@ -47,6 +47,8 @@ type Desc struct { fqName string // help provides some helpful information about this metric. help string + // unit provides the unit of this metric. + unit string // constLabelPairs contains precalculated DTO label pairs based on // the constant labels. constLabelPairs []*dto.LabelPair @@ -75,8 +77,8 @@ type Desc struct { // // For constLabels, the label values are constant. Therefore, they are fully // specified in the Desc. See the Collector example for a usage pattern. -func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *Desc { - return V2.NewDesc(fqName, help, UnconstrainedLabels(variableLabels), constLabels) +func NewDesc(fqName, help, unit string, variableLabels []string, constLabels Labels) *Desc { + return V2.NewDesc(fqName, help, unit, UnconstrainedLabels(variableLabels), constLabels) } // NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc @@ -89,10 +91,11 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * // // For constLabels, the label values are constant. Therefore, they are fully // specified in the Desc. See the Collector example for a usage pattern. -func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels) *Desc { +func (v2) NewDesc(fqName, help, unit string, variableLabels ConstrainableLabels, constLabels Labels) *Desc { d := &Desc{ fqName: fqName, help: help, + unit: unit, variableLabels: variableLabels.compile(), } if !model.IsValidMetricName(model.LabelValue(fqName)) { @@ -149,10 +152,11 @@ func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, const d.id = xxh.Sum64() // Sort labelNames so that order doesn't matter for the hash. sort.Strings(labelNames) - // Now hash together (in this order) the help string and the sorted + // Now hash together (in this order) the help string, the unit string and the sorted // label names. xxh.Reset() xxh.WriteString(help) + xxh.WriteString(unit) xxh.Write(separatorByteSlice) for _, labelName := range labelNames { xxh.WriteString(labelName) @@ -198,9 +202,10 @@ func (d *Desc) String() string { } } return fmt.Sprintf( - "Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: {%s}}", + "Desc{fqName: %q, help: %q, unit: %q, constLabels: {%s}, variableLabels: {%s}}", d.fqName, d.help, + d.unit, strings.Join(lpStrings, ","), strings.Join(vlStrings, ","), ) diff --git a/prometheus/desc_test.go b/prometheus/desc_test.go index 5f854db0b..6443318f6 100644 --- a/prometheus/desc_test.go +++ b/prometheus/desc_test.go @@ -21,6 +21,7 @@ func TestNewDescInvalidLabelValues(t *testing.T) { desc := NewDesc( "sample_label", "sample label", + "", nil, Labels{"a": "\xFF"}, ) diff --git a/prometheus/example_clustermanager_test.go b/prometheus/example_clustermanager_test.go index 92b61ca85..b995677fa 100644 --- a/prometheus/example_clustermanager_test.go +++ b/prometheus/example_clustermanager_test.go @@ -66,11 +66,13 @@ var ( oomCountDesc = prometheus.NewDesc( "clustermanager_oom_crashes_total", "Number of OOM crashes.", + "", []string{"host"}, nil, ) ramUsageDesc = prometheus.NewDesc( "clustermanager_ram_usage_bytes", "RAM usage as reported to the cluster manager.", + "bytes", []string{"host"}, nil, ) ) diff --git a/prometheus/example_metricvec_test.go b/prometheus/example_metricvec_test.go index 59e43f8f8..8bf8e9739 100644 --- a/prometheus/example_metricvec_test.go +++ b/prometheus/example_metricvec_test.go @@ -52,8 +52,8 @@ type InfoVec struct { *prometheus.MetricVec } -func NewInfoVec(name, help string, labelNames []string) *InfoVec { - desc := prometheus.NewDesc(name, help, labelNames, nil) +func NewInfoVec(name, help, unit string, labelNames []string) *InfoVec { + desc := prometheus.NewDesc(name, help, unit, labelNames, nil) return &InfoVec{ MetricVec: prometheus.NewMetricVec(desc, func(lvs ...string) prometheus.Metric { if len(lvs) != len(labelNames) { @@ -110,6 +110,7 @@ func ExampleMetricVec() { infoVec := NewInfoVec( "library_version_info", "Versions of the libraries used in this binary.", + "", []string{"library", "version"}, ) diff --git a/prometheus/examples_test.go b/prometheus/examples_test.go index e4fed3e95..c4c06851b 100644 --- a/prometheus/examples_test.go +++ b/prometheus/examples_test.go @@ -308,9 +308,9 @@ func ExampleRegister() { // Output: // taskCounter registered. - // taskCounterVec not registered: a previously registered descriptor with the same fully-qualified name as Desc{fqName: "worker_pool_completed_tasks_total", help: "Total number of tasks completed.", constLabels: {}, variableLabels: {worker_id}} has different label names or a different help string + // taskCounterVec not registered: a previously registered descriptor with the same fully-qualified name as Desc{fqName: "worker_pool_completed_tasks_total", help: "Total number of tasks completed.", unit: "", constLabels: {}, variableLabels: {worker_id}} has different label names or a different help string // taskCounter unregistered. - // taskCounterVec not registered: a previously registered descriptor with the same fully-qualified name as Desc{fqName: "worker_pool_completed_tasks_total", help: "Total number of tasks completed.", constLabels: {}, variableLabels: {worker_id}} has different label names or a different help string + // taskCounterVec not registered: a previously registered descriptor with the same fully-qualified name as Desc{fqName: "worker_pool_completed_tasks_total", help: "Total number of tasks completed.", unit: "", constLabels: {}, variableLabels: {worker_id}} has different label names or a different help string // taskCounterVec registered. // Worker initialization failed: inconsistent label cardinality: expected 1 label values but got 2 in []string{"42", "spurious arg"} // notMyCounter is nil. @@ -382,6 +382,7 @@ func ExampleNewConstSummary() { desc := prometheus.NewDesc( "http_request_duration_seconds", "A summary of the HTTP request durations.", + "seconds", []string{"code", "method"}, prometheus.Labels{"owner": "example"}, ) @@ -433,6 +434,7 @@ func ExampleNewConstHistogram() { desc := prometheus.NewDesc( "http_request_duration_seconds", "A histogram of the HTTP request durations.", + "seconds", []string{"code", "method"}, prometheus.Labels{"owner": "example"}, ) @@ -460,6 +462,7 @@ func ExampleNewConstHistogram_WithExemplar() { desc := prometheus.NewDesc( "http_request_duration_seconds", "A histogram of the HTTP request durations.", + "seconds", []string{"code", "method"}, prometheus.Labels{"owner": "example"}, ) @@ -630,6 +633,7 @@ func ExampleNewMetricWithTimestamp() { desc := prometheus.NewDesc( "temperature_kelvin", "Current temperature in Kelvin.", + "kelvin", nil, nil, ) @@ -663,6 +667,7 @@ func ExampleNewConstMetricWithCreatedTimestamp() { desc := prometheus.NewDesc( "time_since_epoch_seconds", "Current epoch time in seconds.", + "seconds", nil, nil, ) diff --git a/prometheus/expvar_collector_test.go b/prometheus/expvar_collector_test.go index a8d0ed294..88d25019a 100644 --- a/prometheus/expvar_collector_test.go +++ b/prometheus/expvar_collector_test.go @@ -29,16 +29,19 @@ func ExampleNewExpvarCollector() { "memstats": prometheus.NewDesc( "expvar_memstats", "All numeric memstats as one metric family. Not a good role-model, actually... ;-)", + "", []string{"type"}, nil, ), "lone-int": prometheus.NewDesc( "expvar_lone_int", "Just an expvar int as an example.", + "", nil, nil, ), "http-request-map": prometheus.NewDesc( "expvar_http_request_total", "How many http requests processed, partitioned by status code and http method.", + "", []string{"code", "method"}, nil, ), }) diff --git a/prometheus/gauge.go b/prometheus/gauge.go index dd2eac940..f643509bc 100644 --- a/prometheus/gauge.go +++ b/prometheus/gauge.go @@ -79,6 +79,7 @@ func NewGauge(opts GaugeOpts) Gauge { desc := NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, nil, opts.ConstLabels, ) @@ -161,6 +162,7 @@ func (v2) NewGaugeVec(opts GaugeVecOpts) *GaugeVec { desc := V2.NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, opts.VariableLabels, opts.ConstLabels, ) @@ -305,6 +307,7 @@ func NewGaugeFunc(opts GaugeOpts, function func() float64) GaugeFunc { return newValueFunc(NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, nil, opts.ConstLabels, ), GaugeValue, function) diff --git a/prometheus/gauge_test.go b/prometheus/gauge_test.go index 26759fbbc..3e2285b7c 100644 --- a/prometheus/gauge_test.go +++ b/prometheus/gauge_test.go @@ -171,7 +171,7 @@ func TestGaugeFunc(t *testing.T) { func() float64 { return 3.1415 }, ) - if expected, got := `Desc{fqName: "test_name", help: "test help", constLabels: {a="1",b="2"}, variableLabels: {}}`, gf.Desc().String(); expected != got { + if expected, got := `Desc{fqName: "test_name", help: "test help", unit: "", constLabels: {a="1",b="2"}, variableLabels: {}}`, gf.Desc().String(); expected != got { t.Errorf("expected %q, got %q", expected, got) } diff --git a/prometheus/go_collector.go b/prometheus/go_collector.go index ad9a71a5e..000842aa1 100644 --- a/prometheus/go_collector.go +++ b/prometheus/go_collector.go @@ -29,6 +29,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("alloc_bytes"), "Number of bytes allocated and still in use.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) }, @@ -37,6 +38,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("alloc_bytes_total"), "Total number of bytes allocated, even if freed.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) }, @@ -45,6 +47,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("sys_bytes"), "Number of bytes obtained from system.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) }, @@ -53,6 +56,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("lookups_total"), "Total number of pointer lookups.", + "", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) }, @@ -61,6 +65,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("mallocs_total"), "Total number of mallocs.", + "", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) }, @@ -69,6 +74,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("frees_total"), "Total number of frees.", + "", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.Frees) }, @@ -77,6 +83,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("heap_alloc_bytes"), "Number of heap bytes allocated and still in use.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) }, @@ -85,6 +92,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("heap_sys_bytes"), "Number of heap bytes obtained from system.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) }, @@ -93,6 +101,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("heap_idle_bytes"), "Number of heap bytes waiting to be used.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) }, @@ -101,6 +110,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("heap_inuse_bytes"), "Number of heap bytes that are in use.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) }, @@ -109,6 +119,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("heap_released_bytes"), "Number of heap bytes released to OS.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) }, @@ -117,6 +128,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("heap_objects"), "Number of allocated objects.", + "", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) }, @@ -125,6 +137,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("stack_inuse_bytes"), "Number of bytes in use by the stack allocator.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) }, @@ -133,6 +146,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("stack_sys_bytes"), "Number of bytes obtained from system for stack allocator.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) }, @@ -141,6 +155,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("mspan_inuse_bytes"), "Number of bytes in use by mspan structures.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) }, @@ -149,6 +164,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("mspan_sys_bytes"), "Number of bytes used for mspan structures obtained from system.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) }, @@ -157,6 +173,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("mcache_inuse_bytes"), "Number of bytes in use by mcache structures.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) }, @@ -165,6 +182,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("mcache_sys_bytes"), "Number of bytes used for mcache structures obtained from system.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) }, @@ -173,6 +191,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("buck_hash_sys_bytes"), "Number of bytes used by the profiling bucket hash table.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) }, @@ -181,6 +200,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("gc_sys_bytes"), "Number of bytes used for garbage collection system metadata.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) }, @@ -189,6 +209,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("other_sys_bytes"), "Number of bytes used for other system allocations.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) }, @@ -197,6 +218,7 @@ func goRuntimeMemStats() memStatsMetrics { desc: NewDesc( memstatNamespace("next_gc_bytes"), "Number of heap bytes when next garbage collection will take place.", + "bytes", nil, nil, ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) }, @@ -218,22 +240,27 @@ func newBaseGoCollector() baseGoCollector { goroutinesDesc: NewDesc( "go_goroutines", "Number of goroutines that currently exist.", + "", nil, nil), threadsDesc: NewDesc( "go_threads", "Number of OS threads created.", + "", nil, nil), gcDesc: NewDesc( "go_gc_duration_seconds", "A summary of the pause duration of garbage collection cycles.", + "seconds", nil, nil), gcLastTimeDesc: NewDesc( "go_memstats_last_gc_time_seconds", "Number of seconds since 1970 of last garbage collection.", + "seconds", nil, nil), goInfoDesc: NewDesc( "go_info", "Information about the Go environment.", + "", nil, Labels{"version": runtime.Version()}), } } diff --git a/prometheus/go_collector_latest.go b/prometheus/go_collector_latest.go index 2d8d9f64f..ab4b34766 100644 --- a/prometheus/go_collector_latest.go +++ b/prometheus/go_collector_latest.go @@ -215,6 +215,7 @@ func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector { NewDesc( BuildFQName(namespace, subsystem, name), d.Description.Description, + "", nil, nil, ), diff --git a/prometheus/histogram.go b/prometheus/histogram.go index b5c8bcb39..696ce1af7 100644 --- a/prometheus/histogram.go +++ b/prometheus/histogram.go @@ -372,6 +372,9 @@ type HistogramOpts struct { // string. Help string + // Unit provides the unit of this Histogram. + Unit string + // ConstLabels are used to attach fixed labels to this metric. Metrics // with the same fully-qualified name must have the same label names in // their ConstLabels. @@ -503,6 +506,7 @@ func NewHistogram(opts HistogramOpts) Histogram { NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, nil, opts.ConstLabels, ), @@ -1127,6 +1131,7 @@ func (v2) NewHistogramVec(opts HistogramVecOpts) *HistogramVec { desc := V2.NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, opts.VariableLabels, opts.ConstLabels, ) diff --git a/prometheus/metric.go b/prometheus/metric.go index f018e5723..d24ac2395 100644 --- a/prometheus/metric.go +++ b/prometheus/metric.go @@ -81,6 +81,9 @@ type Opts struct { // string. Help string + // Unit provides the unit of this metric. + Unit string + // ConstLabels are used to attach fixed labels to this metric. Metrics // with the same fully-qualified name must have the same label names in // their ConstLabels. diff --git a/prometheus/metric_test.go b/prometheus/metric_test.go index 629aa4f84..8186567a5 100644 --- a/prometheus/metric_test.go +++ b/prometheus/metric_test.go @@ -45,7 +45,7 @@ func TestWithExemplarsMetric(t *testing.T) { t.Run("histogram", func(t *testing.T) { // Create a constant histogram from values we got from a 3rd party telemetry system. h := MustNewConstHistogram( - NewDesc("http_request_duration_seconds", "A histogram of the HTTP request durations.", nil, nil), + NewDesc("http_request_duration_seconds", "A histogram of the HTTP request durations.", "seconds", nil, nil), 4711, 403.34, // Four buckets, but we expect five as the +Inf bucket will be created if we see value outside of those buckets. map[float64]uint64{25: 121, 50: 2403, 100: 3221, 200: 4233}, diff --git a/prometheus/process_collector.go b/prometheus/process_collector.go index 8548dd18e..97f28e18e 100644 --- a/prometheus/process_collector.go +++ b/prometheus/process_collector.go @@ -68,36 +68,43 @@ func NewProcessCollector(opts ProcessCollectorOpts) Collector { cpuTotal: NewDesc( ns+"process_cpu_seconds_total", "Total user and system CPU time spent in seconds.", + "seconds", nil, nil, ), openFDs: NewDesc( ns+"process_open_fds", "Number of open file descriptors.", + "", nil, nil, ), maxFDs: NewDesc( ns+"process_max_fds", "Maximum number of open file descriptors.", + "", nil, nil, ), vsize: NewDesc( ns+"process_virtual_memory_bytes", "Virtual memory size in bytes.", + "bytes", nil, nil, ), maxVsize: NewDesc( ns+"process_virtual_memory_max_bytes", "Maximum amount of virtual memory available in bytes.", + "bytes", nil, nil, ), rss: NewDesc( ns+"process_resident_memory_bytes", "Resident memory size in bytes.", + "bytes", nil, nil, ), startTime: NewDesc( ns+"process_start_time_seconds", "Start time of the process since unix epoch in seconds.", + "seconds", nil, nil, ), } diff --git a/prometheus/promhttp/http_test.go b/prometheus/promhttp/http_test.go index 8ca192748..726a5708d 100644 --- a/prometheus/promhttp/http_test.go +++ b/prometheus/promhttp/http_test.go @@ -32,12 +32,12 @@ import ( type errorCollector struct{} func (e errorCollector) Describe(ch chan<- *prometheus.Desc) { - ch <- prometheus.NewDesc("invalid_metric", "not helpful", nil, nil) + ch <- prometheus.NewDesc("invalid_metric", "not helpful", "", nil, nil) } func (e errorCollector) Collect(ch chan<- prometheus.Metric) { ch <- prometheus.NewInvalidMetric( - prometheus.NewDesc("invalid_metric", "not helpful", nil, nil), + prometheus.NewDesc("invalid_metric", "not helpful", "", nil, nil), errors.New("collect error"), ) } @@ -47,7 +47,7 @@ type blockingCollector struct { } func (b blockingCollector) Describe(ch chan<- *prometheus.Desc) { - ch <- prometheus.NewDesc("dummy_desc", "not helpful", nil, nil) + ch <- prometheus.NewDesc("dummy_desc", "not helpful", "", nil, nil) } func (b blockingCollector) Collect(ch chan<- prometheus.Metric) { @@ -128,11 +128,11 @@ func TestHandlerErrorHandling(t *testing.T) { t.Fatalf("unexpected number of done invokes, want 0, got %d", got) } - wantMsg := `error gathering metrics: error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", constLabels: {}, variableLabels: {}}: collect error + wantMsg := `error gathering metrics: error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", unit: "", constLabels: {}, variableLabels: {}}: collect error ` wantErrorBody := `An error has occurred while serving metrics: -error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", constLabels: {}, variableLabels: {}}: collect error +error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", unit: "", constLabels: {}, variableLabels: {}}: collect error ` wantOKBody1 := `# HELP name docstring # TYPE name counter diff --git a/prometheus/registry_test.go b/prometheus/registry_test.go index dca36fe58..415972185 100644 --- a/prometheus/registry_test.go +++ b/prometheus/registry_test.go @@ -1309,7 +1309,7 @@ func TestCheckMetricConsistency(t *testing.T) { reg := prometheus.NewRegistry() timestamp := time.Now() - desc := prometheus.NewDesc("metric_a", "", nil, nil) + desc := prometheus.NewDesc("metric_a", "", "", nil, nil) metric := prometheus.MustNewConstMetric(desc, prometheus.CounterValue, 1) validCollector := &customCollector{ diff --git a/prometheus/summary.go b/prometheus/summary.go index 146270444..c9259008e 100644 --- a/prometheus/summary.go +++ b/prometheus/summary.go @@ -101,6 +101,9 @@ type SummaryOpts struct { // string. Help string + // Unit provides the unit of this Summary. + Unit string + // ConstLabels are used to attach fixed labels to this metric. Metrics // with the same fully-qualified name must have the same label names in // their ConstLabels. @@ -184,6 +187,7 @@ func NewSummary(opts SummaryOpts) Summary { NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, nil, opts.ConstLabels, ), @@ -573,6 +577,7 @@ func (v2) NewSummaryVec(opts SummaryVecOpts) *SummaryVec { desc := V2.NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, opts.VariableLabels, opts.ConstLabels, ) diff --git a/prometheus/testutil/testutil_test.go b/prometheus/testutil/testutil_test.go index f2e1cbaff..70c33561c 100644 --- a/prometheus/testutil/testutil_test.go +++ b/prometheus/testutil/testutil_test.go @@ -26,12 +26,12 @@ import ( type untypedCollector struct{} func (u untypedCollector) Describe(c chan<- *prometheus.Desc) { - c <- prometheus.NewDesc("name", "help", nil, nil) + c <- prometheus.NewDesc("name", "help", "", nil, nil) } func (u untypedCollector) Collect(c chan<- prometheus.Metric) { c <- prometheus.MustNewConstMetric( - prometheus.NewDesc("name", "help", nil, nil), + prometheus.NewDesc("name", "help", "", nil, nil), prometheus.UntypedValue, 2001, ) diff --git a/prometheus/untyped.go b/prometheus/untyped.go index 0f9ce63f4..c9ea7d4bb 100644 --- a/prometheus/untyped.go +++ b/prometheus/untyped.go @@ -36,6 +36,7 @@ func NewUntypedFunc(opts UntypedOpts, function func() float64) UntypedFunc { return newValueFunc(NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, + opts.Unit, nil, opts.ConstLabels, ), UntypedValue, function) diff --git a/prometheus/value_test.go b/prometheus/value_test.go index 004c3bb35..53d213faf 100644 --- a/prometheus/value_test.go +++ b/prometheus/value_test.go @@ -45,6 +45,7 @@ func TestNewConstMetricInvalidLabelValues(t *testing.T) { metricDesc := NewDesc( "sample_value", "sample value", + "", []string{"a"}, Labels{}, ) @@ -88,6 +89,7 @@ func TestNewConstMetricWithCreatedTimestamp(t *testing.T) { metricDesc := NewDesc( "sample_value", "sample value", + "", nil, nil, ) diff --git a/prometheus/wrap.go b/prometheus/wrap.go index 25da157f1..fb9a38861 100644 --- a/prometheus/wrap.go +++ b/prometheus/wrap.go @@ -196,6 +196,7 @@ func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc { return &Desc{ fqName: desc.fqName, help: desc.help, + unit: desc.unit, variableLabels: desc.variableLabels, constLabelPairs: desc.constLabelPairs, err: fmt.Errorf("attempted wrapping with already existing label name %q", ln), @@ -204,7 +205,7 @@ func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc { constLabels[ln] = lv } // NewDesc will do remaining validations. - newDesc := V2.NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels) + newDesc := V2.NewDesc(prefix+desc.fqName, desc.help, desc.unit, desc.variableLabels, constLabels) // Propagate errors if there was any. This will override any errer // created by NewDesc above, i.e. earlier errors get precedence. if desc.err != nil {