]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/pprof/label.go
d39e0ad58e21d0bc6bd60d36621d78d1ca5fa91e
[gostls13.git] / src / runtime / pprof / label.go
1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package pprof
6
7 import (
8         "context"
9         "fmt"
10         "sort"
11         "strings"
12 )
13
14 type label struct {
15         key   string
16         value string
17 }
18
19 // LabelSet is a set of labels.
20 type LabelSet struct {
21         list []label
22 }
23
24 // labelContextKey is the type of contextKeys used for profiler labels.
25 type labelContextKey struct{}
26
27 func labelValue(ctx context.Context) labelMap {
28         labels, _ := ctx.Value(labelContextKey{}).(*labelMap)
29         if labels == nil {
30                 return labelMap(nil)
31         }
32         return *labels
33 }
34
35 // labelMap is the representation of the label set held in the context type.
36 // This is an initial implementation, but it will be replaced with something
37 // that admits incremental immutable modification more efficiently.
38 type labelMap map[string]string
39
40 // String satisfies Stringer and returns key, value pairs in a consistent
41 // order.
42 func (l *labelMap) String() string {
43         if l == nil {
44                 return ""
45         }
46         keyVals := make([]string, 0, len(*l))
47
48         for k, v := range *l {
49                 keyVals = append(keyVals, fmt.Sprintf("%q:%q", k, v))
50         }
51
52         sort.Strings(keyVals)
53
54         return "{" + strings.Join(keyVals, ", ") + "}"
55 }
56
57 // WithLabels returns a new context.Context with the given labels added.
58 // A label overwrites a prior label with the same key.
59 func WithLabels(ctx context.Context, labels LabelSet) context.Context {
60         parentLabels := labelValue(ctx)
61         childLabels := make(labelMap, len(parentLabels))
62         // TODO(matloob): replace the map implementation with something
63         // more efficient so creating a child context WithLabels doesn't need
64         // to clone the map.
65         for k, v := range parentLabels {
66                 childLabels[k] = v
67         }
68         for _, label := range labels.list {
69                 childLabels[label.key] = label.value
70         }
71         return context.WithValue(ctx, labelContextKey{}, &childLabels)
72 }
73
74 // Labels takes an even number of strings representing key-value pairs
75 // and makes a LabelSet containing them.
76 // A label overwrites a prior label with the same key.
77 // Currently only the CPU and goroutine profiles utilize any labels
78 // information.
79 // See https://golang.org/issue/23458 for details.
80 func Labels(args ...string) LabelSet {
81         if len(args)%2 != 0 {
82                 panic("uneven number of arguments to pprof.Labels")
83         }
84         list := make([]label, 0, len(args)/2)
85         for i := 0; i+1 < len(args); i += 2 {
86                 list = append(list, label{key: args[i], value: args[i+1]})
87         }
88         return LabelSet{list: list}
89 }
90
91 // Label returns the value of the label with the given key on ctx, and a boolean indicating
92 // whether that label exists.
93 func Label(ctx context.Context, key string) (string, bool) {
94         ctxLabels := labelValue(ctx)
95         v, ok := ctxLabels[key]
96         return v, ok
97 }
98
99 // ForLabels invokes f with each label set on the context.
100 // The function f should return true to continue iteration or false to stop iteration early.
101 func ForLabels(ctx context.Context, f func(key, value string) bool) {
102         ctxLabels := labelValue(ctx)
103         for k, v := range ctxLabels {
104                 if !f(k, v) {
105                         break
106                 }
107         }
108 }