|
11 | 11 | // See the License for the specific language governing permissions and
|
12 | 12 | // limitations under the License.
|
13 | 13 |
|
14 |
| -// Package promsafe provides safe labeling - strongly typed labels in prometheus metrics. |
15 |
| -// Enjoy promsafe as you wish! |
| 14 | +// Package promsafe provides a layer of type-safety for label management in Prometheus metrics. |
| 15 | +// |
| 16 | +// Promsafe introduces type-safe labels, ensuring that the labels used with |
| 17 | +// Prometheus metrics are explicitly defined and validated at compile-time. This |
| 18 | +// eliminates common runtime errors caused by mislabeling, such as typos or |
| 19 | +// incorrect label orders. |
| 20 | +// |
| 21 | +// The following example demonstrates how to create and use a CounterVec with |
| 22 | +// type-safe labels (compared to how it's done in a regular way): |
| 23 | +// |
| 24 | +// package main |
| 25 | +// |
| 26 | +// import ( |
| 27 | +// "strconv" |
| 28 | +// |
| 29 | +// "github.com/prometheus/client_golang/prometheus" |
| 30 | +// "github.com/prometheus/client_golang/prometheus/promsafe" |
| 31 | +// ) |
| 32 | +// |
| 33 | +// // Original unsafe way (no type safety) |
| 34 | +// func originalUnsafeWay() { |
| 35 | +// counterVec := prometheus.NewCounterVec( |
| 36 | +// prometheus.CounterOpts{ |
| 37 | +// Name: "http_requests_total", |
| 38 | +// Help: "Total number of HTTP requests by status code and method.", |
| 39 | +// }, |
| 40 | +// []string{"code", "method"}, // Labels defined as raw strings |
| 41 | +// ) |
| 42 | +// |
| 43 | +// // No compile-time checks; label order and types must be correct |
| 44 | +// // You have to know which and how many labels are expected (in proper order) |
| 45 | +// counterVec.WithLabelValues("200", "GET").Inc() |
| 46 | +// |
| 47 | +// // or you can use map, that is even more fragile |
| 48 | +// counterVect.WithLabels(prometheus.Labels{"code": "200", "method": "GET"}).Inc() |
| 49 | +// } |
| 50 | +// |
| 51 | +// // Safe way (Quick implementation, reflect-based under-the-hood) |
| 52 | +// type Labels1 struct { |
| 53 | +// promsafe.StructLabelProvider |
| 54 | +// Code int |
| 55 | +// Method string |
| 56 | +// } |
| 57 | +// |
| 58 | +// func safeReflectWay() { |
| 59 | +// counterVec := promsafe.NewCounterVec[Labels1](prometheus.CounterOpts{ |
| 60 | +// Name: "http_requests_total_reflection", |
| 61 | +// Help: "Total number of HTTP requests by status code and method (reflection-based).", |
| 62 | +// }) |
| 63 | +// |
| 64 | +// // Compile-time safe and readable; Will be converted into properly ordered list: "200", "GET" |
| 65 | +// counterVec.With(Labels1{Method: "GET", Code: 200}).Inc() |
| 66 | +// } |
| 67 | +// |
| 68 | +// // Safe way with manual implementation (no reflection overhead, as fast as original) |
| 69 | +// type Labels2 struct { |
| 70 | +// promsafe.StructLabelProvider |
| 71 | +// Code int |
| 72 | +// Method string |
| 73 | +// } |
| 74 | +// |
| 75 | +// func (c Labels2) ToPrometheusLabels() prometheus.Labels { |
| 76 | +// return prometheus.Labels{ |
| 77 | +// "code": strconv.Itoa(c.Code), // Convert int to string |
| 78 | +// "method": c.Method, |
| 79 | +// } |
| 80 | +// } |
| 81 | +// |
| 82 | +// func (c Labels2) ToLabelNames() []string { |
| 83 | +// return []string{"code", "method"} |
| 84 | +// } |
| 85 | +// |
| 86 | +// func safeManualWay() { |
| 87 | +// counterVec := promsafe.NewCounterVec[Labels2](prometheus.CounterOpts{ |
| 88 | +// Name: "http_requests_total_custom", |
| 89 | +// Help: "Total number of HTTP requests by status code and method (manual implementation).", |
| 90 | +// }) |
| 91 | +// counterVec.With(Labels2{Code: 404, Method: "POST"}).Inc() |
| 92 | +// } |
| 93 | +// |
| 94 | +// Promsafe also provides compatibility adapter for integration with Prometheus's |
| 95 | +// `promauto` package, ensuring seamless adoption while preserving type-safety. |
| 96 | +// Methods that cannot guarantee type safety, such as those using raw `[]string` |
| 97 | +// label values, are explicitly deprecated and will raise runtime errors. |
| 98 | +// |
| 99 | +// A separate package allows conservative users to entirely ignore it. And |
| 100 | +// whoever wants to use it will do so explicitly, with an opportunity to read |
| 101 | +// this warning. |
| 102 | +// |
| 103 | +// Enjoy promsafe as it's safe! |
16 | 104 | package promsafe
|
17 | 105 |
|
18 | 106 | import (
|
@@ -91,3 +179,5 @@ func NewCounter(opts prometheus.CounterOpts) prometheus.Counter {
|
91 | 179 | func NewCounterFunc(opts prometheus.CounterOpts, function func() float64) prometheus.CounterFunc {
|
92 | 180 | return prometheus.NewCounterFunc(opts, function)
|
93 | 181 | }
|
| 182 | + |
| 183 | +// TODO: other methods (Gauge, Histogram, Summary, etc.) |
0 commit comments