From 7a3bcd920784e552af07f719c7acdc4c108a6e8d Mon Sep 17 00:00:00 2001 From: Eugene Date: Thu, 28 Nov 2024 23:22:42 +0200 Subject: [PATCH] up --- prometheus/promsafe/safe.go | 141 ++++++++++++++++--------------- prometheus/promsafe/safe_test.go | 6 +- 2 files changed, 75 insertions(+), 72 deletions(-) diff --git a/prometheus/promsafe/safe.go b/prometheus/promsafe/safe.go index bd7dc8624..1fa02d550 100644 --- a/prometheus/promsafe/safe.go +++ b/prometheus/promsafe/safe.go @@ -21,75 +21,78 @@ // The following example demonstrates how to create and use a CounterVec with // type-safe labels (compared to how it's done in a regular way): // -// package main -// -// import ( -// "strconv" -// -// "github.com/prometheus/client_golang/prometheus" -// "github.com/prometheus/client_golang/prometheus/promsafe" -// ) -// -// // Original unsafe way (no type safety) -// func originalUnsafeWay() { -// counterVec := prometheus.NewCounterVec( -// prometheus.CounterOpts{ -// Name: "http_requests_total", -// Help: "Total number of HTTP requests by status code and method.", -// }, -// []string{"code", "method"}, / / Labels defined as raw strings -// ) -// -// // No compile-time checks; label order and types must be correct -// // You have to know which and how many labels are expected (in proper order) -// counterVec.WithLabelValues("200", "GET").Inc() -// -// // or you can use map, that is even more fragile -// counterVect.WithLabels(prometheus.Labels{"code": "200", "method": "GET"}).Inc() -// } -// -// // Safe way (Quick implementation, reflect-based under-the-hood) -// type Labels1 struct { -// promsafe.StructLabelProvider -// Code int -// Method string -// } -// -// func safeReflectWay() { -// counterVec := promsafe.NewCounterVec[Labels1](prometheus.CounterOpts{ -// Name: "http_requests_total_reflection", -// Help: "Total number of HTTP requests by status code and method (reflection-based).", -// }) -// -// // Compile-time safe and readable; Will be converted into properly ordered list: "200", "GET" -// counterVec.With(Labels1{Method: "GET", Code: 200}).Inc() -// } -// -// // Safe way with manual implementation (no reflection overhead, as fast as original) -// type Labels2 struct { -// promsafe.StructLabelProvider -// Code int -// Method string -// } -// -// func (c Labels2) ToPrometheusLabels() prometheus.Labels { -// return prometheus.Labels{ -// "code": strconv.Itoa(c.Code), // Convert int to string -// "method": c.Method, -// } -// } -// -// func (c Labels2) ToLabelNames() []string { -// return []string{"code", "method"} -// } -// -// func safeManualWay() { -// counterVec := promsafe.NewCounterVec[Labels2](prometheus.CounterOpts{ -// Name: "http_requests_total_custom", -// Help: "Total number of HTTP requests by status code and method (manual implementation).", -// }) -// counterVec.With(Labels2{Code: 404, Method: "POST"}).Inc() -// } +// package main +// +// import ( +// "strconv" +// +// "github.com/prometheus/client_golang/prometheus" +// "github.com/prometheus/client_golang/prometheus/promsafe" +// ) +// +// // Original unsafe way (no type safety) +// +// func originalUnsafeWay() { +// counterVec := prometheus.NewCounterVec( +// prometheus.CounterOpts{ +// Name: "http_requests_total", +// Help: "Total number of HTTP requests by status code and method.", +// }, +// []string{"code", "method"}, // Labels defined as raw strings +// ) +// +// // No compile-time checks; label order and types must be correct +// // You have to know which and how many labels are expected (in proper order) +// counterVec.WithLabelValues("200", "GET").Inc() +// +// // or you can use map, that is even more fragile +// counterVec.With(prometheus.Labels{"code": "200", "method": "GET"}).Inc() +// } +// +// // Safe way (Quick implementation, reflect-based under-the-hood) +// +// type Labels1 struct { +// promsafe.StructLabelProvider +// Code int +// Method string +// } +// +// func safeReflectWay() { +// counterVec := promsafe.NewCounterVec[Labels1](prometheus.CounterOpts{ +// Name: "http_requests_total_reflection", +// Help: "Total number of HTTP requests by status code and method (reflection-based).", +// }) +// +// // Compile-time safe and readable; Will be converted into properly ordered list: "200", "GET" +// counterVec.With(Labels1{Method: "GET", Code: 200}).Inc() +// } +// +// // Safe way with manual implementation (no reflection overhead, as fast as original) +// +// type Labels2 struct { +// promsafe.StructLabelProvider +// Code int +// Method string +// } +// +// func (c Labels2) ToPrometheusLabels() prometheus.Labels { +// return prometheus.Labels{ +// "code": strconv.Itoa(c.Code), // Convert int to string +// "method": c.Method, +// } +// } +// +// func (c Labels2) ToLabelNames() []string { +// return []string{"code", "method"} +// } +// +// func safeManualWay() { +// counterVec := promsafe.NewCounterVec[Labels2](prometheus.CounterOpts{ +// Name: "http_requests_total_custom", +// Help: "Total number of HTTP requests by status code and method (manual implementation).", +// }) +// counterVec.With(Labels2{Code: 404, Method: "POST"}).Inc() +// } // // Package promsafe also provides compatibility adapter for integration with Prometheus's // `promauto` package, ensuring seamless adoption while preserving type-safety. diff --git a/prometheus/promsafe/safe_test.go b/prometheus/promsafe/safe_test.go index 3dce2925f..0b2eabb37 100644 --- a/prometheus/promsafe/safe_test.go +++ b/prometheus/promsafe/safe_test.go @@ -25,7 +25,7 @@ import ( // These are Examples that can be treated as basic smoke tests -func ExampleNewCounterVecT_multiple_labels_manual() { +func ExampleNewCounterVec_multiple_labels_manual() { // Manually registering with multiple labels type MyCounterLabels struct { @@ -72,7 +72,7 @@ func (f FastMyLabels) ToLabelNames() []string { return []string{"event_type", "source"} } -func ExampleNewCounterVecT_fast_safe_labels_provider() { +func ExampleNewCounterVec_fast_safe_labels_provider() { // Note: fast labels provider has a drawback: they can't be declared as inline structs // as we need methods @@ -118,12 +118,12 @@ func (t TestLabelsFast) ToPrometheusLabels() prometheus.Labels { "label3": strconv.FormatBool(t.Label3), } } + func (t TestLabelsFast) ToLabelNames() []string { return []string{"label1", "label2", "label3"} } func BenchmarkCompareCreatingMetric(b *testing.B) { - // Note: on stage of creation metrics, Unique metric names are not required, // but let it be for consistency