NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc and will be reported on registration time. variableLabels and constLabels can be nil if no such labels should be set. fqName must not be empty. variableLabels only contain the label names and normalization functions. Thei
(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels)
| 90 | // For constLabels, the label values are constant. Therefore, they are fully |
| 91 | // specified in the Desc. See the Collector example for a usage pattern. |
| 92 | func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels) *Desc { |
| 93 | d := &Desc{ |
| 94 | fqName: fqName, |
| 95 | help: help, |
| 96 | variableLabels: variableLabels.compile(), |
| 97 | } |
| 98 | //nolint:staticcheck // TODO: Don't use deprecated model.NameValidationScheme. |
| 99 | if !model.NameValidationScheme.IsValidMetricName(fqName) { |
| 100 | d.err = fmt.Errorf("%q is not a valid metric name", fqName) |
| 101 | return d |
| 102 | } |
| 103 | // labelValues contains the label values of const labels (in order of |
| 104 | // their sorted label names) plus the fqName (at position 0). |
| 105 | labelValues := make([]string, 1, len(constLabels)+1) |
| 106 | labelValues[0] = fqName |
| 107 | labelNames := make([]string, 0, len(constLabels)+len(d.variableLabels.names)) |
| 108 | labelNameSet := map[string]struct{}{} |
| 109 | // First add only the const label names and sort them... |
| 110 | for labelName := range constLabels { |
| 111 | if !checkLabelName(labelName) { |
| 112 | d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName) |
| 113 | return d |
| 114 | } |
| 115 | labelNames = append(labelNames, labelName) |
| 116 | labelNameSet[labelName] = struct{}{} |
| 117 | } |
| 118 | sort.Strings(labelNames) |
| 119 | // ... so that we can now add const label values in the order of their names. |
| 120 | for _, labelName := range labelNames { |
| 121 | labelValues = append(labelValues, constLabels[labelName]) |
| 122 | } |
| 123 | // Validate the const label values. They can't have a wrong cardinality, so |
| 124 | // use in len(labelValues) as expectedNumberOfValues. |
| 125 | if err := validateLabelValues(labelValues, len(labelValues)); err != nil { |
| 126 | d.err = err |
| 127 | return d |
| 128 | } |
| 129 | // Now add the variable label names, but prefix them with something that |
| 130 | // cannot be in a regular label name. That prevents matching the label |
| 131 | // dimension with a different mix between preset and variable labels. |
| 132 | for _, label := range d.variableLabels.names { |
| 133 | if !checkLabelName(label) { |
| 134 | d.err = fmt.Errorf("%q is not a valid label name for metric %q", label, fqName) |
| 135 | return d |
| 136 | } |
| 137 | labelNames = append(labelNames, "$"+label) |
| 138 | labelNameSet[label] = struct{}{} |
| 139 | } |
| 140 | if len(labelNames) != len(labelNameSet) { |
| 141 | d.err = fmt.Errorf("duplicate label names in constant and variable labels for metric %q", fqName) |
| 142 | return d |
| 143 | } |
| 144 | |
| 145 | xxh := xxhash.New() |
| 146 | for _, val := range labelValues { |
| 147 | xxh.WriteString(val) |
| 148 | xxh.Write(separatorByteSlice) |
| 149 | } |
no test coverage detected