-
Notifications
You must be signed in to change notification settings - Fork 53
/
desc.go
113 lines (102 loc) · 3.72 KB
/
desc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package desc
import (
"reflect"
sync "sync"
"unsafe"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"github.com/samber/lo"
"golang.org/x/exp/slices"
)
// Prometheus Desc Clone Memory Model
//
// Clone
// ┌─────────────────┐
// │ state │
// Prometheus Desc │ sizeCache │
// ┌─────────────────┐ │ unknownFields │
// │ fqName │ │ FQName │
// │ help │ │ Help │
// │ constLabelPairs │ │ ConstLabelPairs │
// │ variableLabels │ │ VariableLabels │
// │ id │ │ ID │
// │ dimHash │ │ DimHash │
// │ err │ │ padding │
// └─────────────────┘ └─────────────────┘
//
var (
contentOffset uintptr
contentSize uintptr
once sync.Once
)
// preliminary type-checking
func init() {
msg := "the definition of prometheus.Desc has changed; update pkg/metrics/desc"
protoType := reflect.TypeOf(Desc{})
promType := reflect.TypeOf(prometheus.Desc{})
// Find the offset of the first exported field in the proto message.
firstExportedFieldIndex := -1
for i := 0; i < protoType.NumField(); i++ {
field := protoType.Field(i)
if protoType.Field(i).IsExported() {
contentSize += field.Type.Size()
once.Do(func() {
// save the offset for later use
contentOffset = field.Offset
firstExportedFieldIndex = i
})
}
}
// Make sure the alignments match
wrongAlign := protoType.Align() != promType.Align()
// make sure the content sizes match
wrongContentSize := contentSize != promType.Size()
// prometheus.Desc has an error field at the end which we ignore
missingErr := promType.Field(promType.NumField()-1).Type != reflect.TypeOf((*error)(nil)).Elem()
// +1 to account for the two 8-byte padding fields to match error (16 bytes)
wrongFieldCount := protoType.NumField()-firstExportedFieldIndex != promType.NumField()+1
if wrongAlign || wrongContentSize || missingErr || wrongFieldCount {
panic(msg)
}
for i := 0; i < promType.NumField()-1; i++ {
if protoType.Field(i+firstExportedFieldIndex).Type != promType.Field(i).Type {
panic(msg)
}
}
}
// ToPrometheusDescUnsafe returns a desc.Desc reinterpreted as a prometheus.Desc.
// It is *not* safe to use the original object after calling this function.
func (d *Desc) ToPrometheusDescUnsafe() *prometheus.Desc {
return (*prometheus.Desc)(unsafe.Add(unsafe.Pointer(d), contentOffset))
}
// ToPrometheusDesc converts a deep-copy of a desc.Desc to a prometheus.Desc.
// It is safe to use the original object after calling this function.
func (d *Desc) ToPrometheusDesc() *prometheus.Desc {
cloned := &Desc{
FQName: d.FQName,
Help: d.Help,
ConstLabelPairs: CloneLabelPairs(d.ConstLabelPairs),
VariableLabels: slices.Clone(d.VariableLabels),
ID: d.ID,
DimHash: d.DimHash,
}
return cloned.ToPrometheusDescUnsafe()
}
// FromPrometheusDesc returns a prometheus.Desc reinterpreted as a desc.Desc.
// This function performs a shallow-copy, so it may not be safe to use the
// original object afterwards.
func FromPrometheusDesc(desc *prometheus.Desc) *Desc {
d := &Desc{}
*(*prometheus.Desc)(unsafe.Add(unsafe.Pointer(d), contentOffset)) = *desc
return d
}
func CloneLabelPairs(pairs []*dto.LabelPair) []*dto.LabelPair {
res := make([]*dto.LabelPair, len(pairs))
for i, p := range pairs {
res[i] = &dto.LabelPair{
Name: lo.ToPtr(p.GetName()),
Value: lo.ToPtr(p.GetValue()),
}
}
return res
}