Home | History | Annotate | Download | only in pprof
      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 )
     10 
     11 type label struct {
     12 	key   string
     13 	value string
     14 }
     15 
     16 // LabelSet is a set of labels.
     17 type LabelSet struct {
     18 	list []label
     19 }
     20 
     21 // labelContextKey is the type of contextKeys used for profiler labels.
     22 type labelContextKey struct{}
     23 
     24 func labelValue(ctx context.Context) labelMap {
     25 	labels, _ := ctx.Value(labelContextKey{}).(*labelMap)
     26 	if labels == nil {
     27 		return labelMap(nil)
     28 	}
     29 	return *labels
     30 }
     31 
     32 // labelMap is the representation of the label set held in the context type.
     33 // This is an initial implementation, but it will be replaced with something
     34 // that admits incremental immutable modification more efficiently.
     35 type labelMap map[string]string
     36 
     37 // WithLabels returns a new context.Context with the given labels added.
     38 // A label overwrites a prior label with the same key.
     39 func WithLabels(ctx context.Context, labels LabelSet) context.Context {
     40 	childLabels := make(labelMap)
     41 	parentLabels := labelValue(ctx)
     42 	// TODO(matloob): replace the map implementation with something
     43 	// more efficient so creating a child context WithLabels doesn't need
     44 	// to clone the map.
     45 	for k, v := range parentLabels {
     46 		childLabels[k] = v
     47 	}
     48 	for _, label := range labels.list {
     49 		childLabels[label.key] = label.value
     50 	}
     51 	return context.WithValue(ctx, labelContextKey{}, &childLabels)
     52 }
     53 
     54 // Labels takes an even number of strings representing key-value pairs
     55 // and makes a LabelSet containing them.
     56 // A label overwrites a prior label with the same key.
     57 func Labels(args ...string) LabelSet {
     58 	if len(args)%2 != 0 {
     59 		panic("uneven number of arguments to pprof.Labels")
     60 	}
     61 	labels := LabelSet{}
     62 	for i := 0; i+1 < len(args); i += 2 {
     63 		labels.list = append(labels.list, label{key: args[i], value: args[i+1]})
     64 	}
     65 	return labels
     66 }
     67 
     68 // Label returns the value of the label with the given key on ctx, and a boolean indicating
     69 // whether that label exists.
     70 func Label(ctx context.Context, key string) (string, bool) {
     71 	ctxLabels := labelValue(ctx)
     72 	v, ok := ctxLabels[key]
     73 	return v, ok
     74 }
     75 
     76 // ForLabels invokes f with each label set on the context.
     77 // The function f should return true to continue iteration or false to stop iteration early.
     78 func ForLabels(ctx context.Context, f func(key, value string) bool) {
     79 	ctxLabels := labelValue(ctx)
     80 	for k, v := range ctxLabels {
     81 		if !f(k, v) {
     82 			break
     83 		}
     84 	}
     85 }
     86