github.com/lzy4123/fabric@v2.1.1+incompatible/common/metrics/internal/namer/namer.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package namer
     8  
     9  import (
    10  	"fmt"
    11  	"regexp"
    12  	"strings"
    13  
    14  	"github.com/hyperledger/fabric/common/metrics"
    15  )
    16  
    17  type Namer struct {
    18  	namespace  string
    19  	subsystem  string
    20  	name       string
    21  	nameFormat string
    22  	labelNames map[string]struct{}
    23  }
    24  
    25  func NewCounterNamer(c metrics.CounterOpts) *Namer {
    26  	return &Namer{
    27  		namespace:  c.Namespace,
    28  		subsystem:  c.Subsystem,
    29  		name:       c.Name,
    30  		nameFormat: c.StatsdFormat,
    31  		labelNames: sliceToSet(c.LabelNames),
    32  	}
    33  }
    34  
    35  func NewGaugeNamer(g metrics.GaugeOpts) *Namer {
    36  	return &Namer{
    37  		namespace:  g.Namespace,
    38  		subsystem:  g.Subsystem,
    39  		name:       g.Name,
    40  		nameFormat: g.StatsdFormat,
    41  		labelNames: sliceToSet(g.LabelNames),
    42  	}
    43  }
    44  
    45  func NewHistogramNamer(h metrics.HistogramOpts) *Namer {
    46  	return &Namer{
    47  		namespace:  h.Namespace,
    48  		subsystem:  h.Subsystem,
    49  		name:       h.Name,
    50  		nameFormat: h.StatsdFormat,
    51  		labelNames: sliceToSet(h.LabelNames),
    52  	}
    53  }
    54  
    55  func (n *Namer) validateKey(name string) {
    56  	if _, ok := n.labelNames[name]; !ok {
    57  		panic("invalid label name: " + name)
    58  	}
    59  }
    60  
    61  func (n *Namer) FullyQualifiedName() string {
    62  	switch {
    63  	case n.namespace != "" && n.subsystem != "":
    64  		return strings.Join([]string{n.namespace, n.subsystem, n.name}, ".")
    65  	case n.namespace != "":
    66  		return strings.Join([]string{n.namespace, n.name}, ".")
    67  	case n.subsystem != "":
    68  		return strings.Join([]string{n.subsystem, n.name}, ".")
    69  	default:
    70  		return n.name
    71  	}
    72  }
    73  
    74  func (n *Namer) labelsToMap(labelValues []string) map[string]string {
    75  	labels := map[string]string{}
    76  	for i := 0; i < len(labelValues); i += 2 {
    77  		key := labelValues[i]
    78  		n.validateKey(key)
    79  		if i == len(labelValues)-1 {
    80  			labels[key] = "unknown"
    81  		} else {
    82  			labels[key] = labelValues[i+1]
    83  		}
    84  	}
    85  	return labels
    86  }
    87  
    88  var formatRegexp = regexp.MustCompile(`%{([#?[:alnum:]_]+)}`)
    89  var invalidLabelValueRegexp = regexp.MustCompile(`[.|:\s]`)
    90  
    91  func (n *Namer) Format(labelValues ...string) string {
    92  	labels := n.labelsToMap(labelValues)
    93  
    94  	cursor := 0
    95  	var segments []string
    96  	// iterate over the regex groups and convert to formatters
    97  	matches := formatRegexp.FindAllStringSubmatchIndex(n.nameFormat, -1)
    98  	for _, m := range matches {
    99  		start, end := m[0], m[1]
   100  		labelStart, labelEnd := m[2], m[3]
   101  
   102  		if start > cursor {
   103  			segments = append(segments, n.nameFormat[cursor:start])
   104  		}
   105  
   106  		key := n.nameFormat[labelStart:labelEnd]
   107  		var value string
   108  		switch key {
   109  		case "#namespace":
   110  			value = n.namespace
   111  		case "#subsystem":
   112  			value = n.subsystem
   113  		case "#name":
   114  			value = n.name
   115  		case "#fqname":
   116  			value = n.FullyQualifiedName()
   117  		default:
   118  			var ok bool
   119  			value, ok = labels[key]
   120  			if !ok {
   121  				panic(fmt.Sprintf("invalid label in name format: %s", key))
   122  			}
   123  			value = invalidLabelValueRegexp.ReplaceAllString(value, "_")
   124  		}
   125  		segments = append(segments, value)
   126  
   127  		cursor = end
   128  	}
   129  
   130  	// handle any trailing suffix
   131  	if cursor != len(n.nameFormat) {
   132  		segments = append(segments, n.nameFormat[cursor:])
   133  	}
   134  
   135  	return strings.Join(segments, "")
   136  }
   137  
   138  func sliceToSet(set []string) map[string]struct{} {
   139  	labelSet := map[string]struct{}{}
   140  	for _, s := range set {
   141  		labelSet[s] = struct{}{}
   142  	}
   143  	return labelSet
   144  }