1
2
3
4
5 package pprof
6
7 import (
8 "context"
9 "fmt"
10 "internal/runtime/pprof/label"
11 "slices"
12 "strings"
13 )
14
15
16 type LabelSet struct {
17 list []label.Label
18 }
19
20
21 type labelContextKey struct{}
22
23 func labelValue(ctx context.Context) labelMap {
24 labels, _ := ctx.Value(labelContextKey{}).(*labelMap)
25 if labels == nil {
26 return labelMap{}
27 }
28 return *labels
29 }
30
31
32
33
34 type labelMap struct {
35 label.Set
36 }
37
38
39
40 func (l *labelMap) String() string {
41 if l == nil {
42 return ""
43 }
44 keyVals := make([]string, 0, len(l.Set.List))
45
46 for _, lbl := range l.Set.List {
47 keyVals = append(keyVals, fmt.Sprintf("%q:%q", lbl.Key, lbl.Value))
48 }
49
50 slices.Sort(keyVals)
51 return "{" + strings.Join(keyVals, ", ") + "}"
52 }
53
54
55
56 func WithLabels(ctx context.Context, labels LabelSet) context.Context {
57 parentLabels := labelValue(ctx)
58 return context.WithValue(ctx, labelContextKey{}, &labelMap{mergeLabelSets(parentLabels.Set, labels)})
59 }
60
61 func mergeLabelSets(left label.Set, right LabelSet) label.Set {
62 if len(left.List) == 0 {
63 return label.NewSet(right.list)
64 } else if len(right.list) == 0 {
65 return left
66 }
67
68 lList, rList := left.List, right.list
69 l, r := 0, 0
70 result := make([]label.Label, 0, len(rList))
71 for l < len(lList) && r < len(rList) {
72 switch strings.Compare(lList[l].Key, rList[r].Key) {
73 case -1:
74 result = append(result, lList[l])
75 l++
76 case 1:
77 result = append(result, rList[r])
78 r++
79 case 0:
80 result = append(result, rList[r])
81 l++
82 r++
83 }
84 }
85
86
87 result = append(result, lList[l:]...)
88 result = append(result, rList[r:]...)
89
90 return label.NewSet(result)
91 }
92
93
94
95
96
97
98
99 func Labels(args ...string) LabelSet {
100 if len(args)%2 != 0 {
101 panic("uneven number of arguments to pprof.Labels")
102 }
103 list := make([]label.Label, 0, len(args)/2)
104 sortedNoDupes := true
105 for i := 0; i+1 < len(args); i += 2 {
106 list = append(list, label.Label{Key: args[i], Value: args[i+1]})
107 sortedNoDupes = sortedNoDupes && (i < 2 || args[i] > args[i-2])
108 }
109 if !sortedNoDupes {
110
111 slices.SortStableFunc(list, func(a, b label.Label) int {
112 return strings.Compare(a.Key, b.Key)
113 })
114 deduped := make([]label.Label, 0, len(list))
115 for i, lbl := range list {
116 if i == 0 || lbl.Key != list[i-1].Key {
117 deduped = append(deduped, lbl)
118 } else {
119 deduped[len(deduped)-1] = lbl
120 }
121 }
122 list = deduped
123 }
124 return LabelSet{list: list}
125 }
126
127
128
129 func Label(ctx context.Context, key string) (string, bool) {
130 ctxLabels := labelValue(ctx)
131 for _, lbl := range ctxLabels.Set.List {
132 if lbl.Key == key {
133 return lbl.Value, true
134 }
135 }
136 return "", false
137 }
138
139
140
141 func ForLabels(ctx context.Context, f func(key, value string) bool) {
142 ctxLabels := labelValue(ctx)
143 for _, lbl := range ctxLabels.Set.List {
144 if !f(lbl.Key, lbl.Value) {
145 break
146 }
147 }
148 }
149
View as plain text