full diff: https://github.com/prometheus/common/compare/7600349dcfe1abd18d72d3a1770870d9800a7801...v0.7.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -146,7 +146,7 @@ code.cloudfoundry.org/clock 02e53af36e6c978af692887ed449 |
| 146 | 146 |
github.com/prometheus/client_golang c5b7fccd204277076155f10851dad72b76a49317 # v0.8.0 |
| 147 | 147 |
github.com/beorn7/perks 37c8de3658fcb183f997c4e13e8337516ab753e6 # v1.0.1 |
| 148 | 148 |
github.com/prometheus/client_model d1d2010b5beead3fa1c5f271a5cf626e40b3ad6e # v0.1.0 |
| 149 |
-github.com/prometheus/common 7600349dcfe1abd18d72d3a1770870d9800a7801 |
|
| 149 |
+github.com/prometheus/common 287d3e634a1e550c9e463dd7e5a75a422c614505 # v0.7.0 |
|
| 150 | 150 |
github.com/prometheus/procfs 7d6f385de8bea29190f15ba9931442a0eaef9af7 |
| 151 | 151 |
github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c # v1.0.1 |
| 152 | 152 |
github.com/pkg/errors ba968bfe8b2f7e042a574c888954fccecfa385b4 # v0.8.1 |
| ... | ... |
@@ -6,7 +6,11 @@ components and libraries. |
| 6 | 6 |
|
| 7 | 7 |
* **config**: Common configuration structures |
| 8 | 8 |
* **expfmt**: Decoding and encoding for the exposition format |
| 9 |
-* **log**: A logging wrapper around [logrus](https://github.com/sirupsen/logrus) |
|
| 10 | 9 |
* **model**: Shared data structures |
| 10 |
+* **promlog**: A logging wrapper around [go-kit/log](https://github.com/go-kit/kit/tree/master/log) |
|
| 11 | 11 |
* **route**: A routing wrapper around [httprouter](https://github.com/julienschmidt/httprouter) using `context.Context` |
| 12 |
+* **server**: Common servers |
|
| 12 | 13 |
* **version**: Version information and metrics |
| 14 |
+ |
|
| 15 |
+## Deprecated |
|
| 16 |
+* **log**: A logging wrapper around [logrus](https://github.com/sirupsen/logrus) |
| ... | ... |
@@ -14,13 +14,45 @@ |
| 14 | 14 |
package expfmt |
| 15 | 15 |
|
| 16 | 16 |
import ( |
| 17 |
+ "bufio" |
|
| 17 | 18 |
"fmt" |
| 18 | 19 |
"io" |
| 20 |
+ "io/ioutil" |
|
| 19 | 21 |
"math" |
| 22 |
+ "strconv" |
|
| 20 | 23 |
"strings" |
| 24 |
+ "sync" |
|
| 21 | 25 |
|
| 22 |
- dto "github.com/prometheus/client_model/go" |
|
| 23 | 26 |
"github.com/prometheus/common/model" |
| 27 |
+ |
|
| 28 |
+ dto "github.com/prometheus/client_model/go" |
|
| 29 |
+) |
|
| 30 |
+ |
|
| 31 |
+// enhancedWriter has all the enhanced write functions needed here. bufio.Writer |
|
| 32 |
+// implements it. |
|
| 33 |
+type enhancedWriter interface {
|
|
| 34 |
+ io.Writer |
|
| 35 |
+ WriteRune(r rune) (n int, err error) |
|
| 36 |
+ WriteString(s string) (n int, err error) |
|
| 37 |
+ WriteByte(c byte) error |
|
| 38 |
+} |
|
| 39 |
+ |
|
| 40 |
+const ( |
|
| 41 |
+ initialNumBufSize = 24 |
|
| 42 |
+) |
|
| 43 |
+ |
|
| 44 |
+var ( |
|
| 45 |
+ bufPool = sync.Pool{
|
|
| 46 |
+ New: func() interface{} {
|
|
| 47 |
+ return bufio.NewWriter(ioutil.Discard) |
|
| 48 |
+ }, |
|
| 49 |
+ } |
|
| 50 |
+ numBufPool = sync.Pool{
|
|
| 51 |
+ New: func() interface{} {
|
|
| 52 |
+ b := make([]byte, 0, initialNumBufSize) |
|
| 53 |
+ return &b |
|
| 54 |
+ }, |
|
| 55 |
+ } |
|
| 24 | 56 |
) |
| 25 | 57 |
|
| 26 | 58 |
// MetricFamilyToText converts a MetricFamily proto message into text format and |
| ... | ... |
@@ -32,37 +64,90 @@ import ( |
| 32 | 32 |
// will result in invalid text format output. |
| 33 | 33 |
// |
| 34 | 34 |
// This method fulfills the type 'prometheus.encoder'. |
| 35 |
-func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
|
| 36 |
- var written int |
|
| 37 |
- |
|
| 35 |
+func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err error) {
|
|
| 38 | 36 |
// Fail-fast checks. |
| 39 | 37 |
if len(in.Metric) == 0 {
|
| 40 |
- return written, fmt.Errorf("MetricFamily has no metrics: %s", in)
|
|
| 38 |
+ return 0, fmt.Errorf("MetricFamily has no metrics: %s", in)
|
|
| 41 | 39 |
} |
| 42 | 40 |
name := in.GetName() |
| 43 | 41 |
if name == "" {
|
| 44 |
- return written, fmt.Errorf("MetricFamily has no name: %s", in)
|
|
| 42 |
+ return 0, fmt.Errorf("MetricFamily has no name: %s", in)
|
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 45 |
+ // Try the interface upgrade. If it doesn't work, we'll use a |
|
| 46 |
+ // bufio.Writer from the sync.Pool. |
|
| 47 |
+ w, ok := out.(enhancedWriter) |
|
| 48 |
+ if !ok {
|
|
| 49 |
+ b := bufPool.Get().(*bufio.Writer) |
|
| 50 |
+ b.Reset(out) |
|
| 51 |
+ w = b |
|
| 52 |
+ defer func() {
|
|
| 53 |
+ bErr := b.Flush() |
|
| 54 |
+ if err == nil {
|
|
| 55 |
+ err = bErr |
|
| 56 |
+ } |
|
| 57 |
+ bufPool.Put(b) |
|
| 58 |
+ }() |
|
| 45 | 59 |
} |
| 46 | 60 |
|
| 61 |
+ var n int |
|
| 62 |
+ |
|
| 47 | 63 |
// Comments, first HELP, then TYPE. |
| 48 | 64 |
if in.Help != nil {
|
| 49 |
- n, err := fmt.Fprintf( |
|
| 50 |
- out, "# HELP %s %s\n", |
|
| 51 |
- name, escapeString(*in.Help, false), |
|
| 52 |
- ) |
|
| 65 |
+ n, err = w.WriteString("# HELP ")
|
|
| 53 | 66 |
written += n |
| 54 | 67 |
if err != nil {
|
| 55 |
- return written, err |
|
| 68 |
+ return |
|
| 69 |
+ } |
|
| 70 |
+ n, err = w.WriteString(name) |
|
| 71 |
+ written += n |
|
| 72 |
+ if err != nil {
|
|
| 73 |
+ return |
|
| 74 |
+ } |
|
| 75 |
+ err = w.WriteByte(' ')
|
|
| 76 |
+ written++ |
|
| 77 |
+ if err != nil {
|
|
| 78 |
+ return |
|
| 56 | 79 |
} |
| 80 |
+ n, err = writeEscapedString(w, *in.Help, false) |
|
| 81 |
+ written += n |
|
| 82 |
+ if err != nil {
|
|
| 83 |
+ return |
|
| 84 |
+ } |
|
| 85 |
+ err = w.WriteByte('\n')
|
|
| 86 |
+ written++ |
|
| 87 |
+ if err != nil {
|
|
| 88 |
+ return |
|
| 89 |
+ } |
|
| 90 |
+ } |
|
| 91 |
+ n, err = w.WriteString("# TYPE ")
|
|
| 92 |
+ written += n |
|
| 93 |
+ if err != nil {
|
|
| 94 |
+ return |
|
| 95 |
+ } |
|
| 96 |
+ n, err = w.WriteString(name) |
|
| 97 |
+ written += n |
|
| 98 |
+ if err != nil {
|
|
| 99 |
+ return |
|
| 57 | 100 |
} |
| 58 | 101 |
metricType := in.GetType() |
| 59 |
- n, err := fmt.Fprintf( |
|
| 60 |
- out, "# TYPE %s %s\n", |
|
| 61 |
- name, strings.ToLower(metricType.String()), |
|
| 62 |
- ) |
|
| 102 |
+ switch metricType {
|
|
| 103 |
+ case dto.MetricType_COUNTER: |
|
| 104 |
+ n, err = w.WriteString(" counter\n")
|
|
| 105 |
+ case dto.MetricType_GAUGE: |
|
| 106 |
+ n, err = w.WriteString(" gauge\n")
|
|
| 107 |
+ case dto.MetricType_SUMMARY: |
|
| 108 |
+ n, err = w.WriteString(" summary\n")
|
|
| 109 |
+ case dto.MetricType_UNTYPED: |
|
| 110 |
+ n, err = w.WriteString(" untyped\n")
|
|
| 111 |
+ case dto.MetricType_HISTOGRAM: |
|
| 112 |
+ n, err = w.WriteString(" histogram\n")
|
|
| 113 |
+ default: |
|
| 114 |
+ return written, fmt.Errorf("unknown metric type %s", metricType.String())
|
|
| 115 |
+ } |
|
| 63 | 116 |
written += n |
| 64 | 117 |
if err != nil {
|
| 65 |
- return written, err |
|
| 118 |
+ return |
|
| 66 | 119 |
} |
| 67 | 120 |
|
| 68 | 121 |
// Finally the samples, one line for each. |
| ... | ... |
@@ -75,9 +160,8 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
| 75 | 75 |
) |
| 76 | 76 |
} |
| 77 | 77 |
n, err = writeSample( |
| 78 |
- name, metric, "", "", |
|
| 78 |
+ w, name, "", metric, "", 0, |
|
| 79 | 79 |
metric.Counter.GetValue(), |
| 80 |
- out, |
|
| 81 | 80 |
) |
| 82 | 81 |
case dto.MetricType_GAUGE: |
| 83 | 82 |
if metric.Gauge == nil {
|
| ... | ... |
@@ -86,9 +170,8 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
| 86 | 86 |
) |
| 87 | 87 |
} |
| 88 | 88 |
n, err = writeSample( |
| 89 |
- name, metric, "", "", |
|
| 89 |
+ w, name, "", metric, "", 0, |
|
| 90 | 90 |
metric.Gauge.GetValue(), |
| 91 |
- out, |
|
| 92 | 91 |
) |
| 93 | 92 |
case dto.MetricType_UNTYPED: |
| 94 | 93 |
if metric.Untyped == nil {
|
| ... | ... |
@@ -97,9 +180,8 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
| 97 | 97 |
) |
| 98 | 98 |
} |
| 99 | 99 |
n, err = writeSample( |
| 100 |
- name, metric, "", "", |
|
| 100 |
+ w, name, "", metric, "", 0, |
|
| 101 | 101 |
metric.Untyped.GetValue(), |
| 102 |
- out, |
|
| 103 | 102 |
) |
| 104 | 103 |
case dto.MetricType_SUMMARY: |
| 105 | 104 |
if metric.Summary == nil {
|
| ... | ... |
@@ -109,29 +191,26 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
| 109 | 109 |
} |
| 110 | 110 |
for _, q := range metric.Summary.Quantile {
|
| 111 | 111 |
n, err = writeSample( |
| 112 |
- name, metric, |
|
| 113 |
- model.QuantileLabel, fmt.Sprint(q.GetQuantile()), |
|
| 112 |
+ w, name, "", metric, |
|
| 113 |
+ model.QuantileLabel, q.GetQuantile(), |
|
| 114 | 114 |
q.GetValue(), |
| 115 |
- out, |
|
| 116 | 115 |
) |
| 117 | 116 |
written += n |
| 118 | 117 |
if err != nil {
|
| 119 |
- return written, err |
|
| 118 |
+ return |
|
| 120 | 119 |
} |
| 121 | 120 |
} |
| 122 | 121 |
n, err = writeSample( |
| 123 |
- name+"_sum", metric, "", "", |
|
| 122 |
+ w, name, "_sum", metric, "", 0, |
|
| 124 | 123 |
metric.Summary.GetSampleSum(), |
| 125 |
- out, |
|
| 126 | 124 |
) |
| 125 |
+ written += n |
|
| 127 | 126 |
if err != nil {
|
| 128 |
- return written, err |
|
| 127 |
+ return |
|
| 129 | 128 |
} |
| 130 |
- written += n |
|
| 131 | 129 |
n, err = writeSample( |
| 132 |
- name+"_count", metric, "", "", |
|
| 130 |
+ w, name, "_count", metric, "", 0, |
|
| 133 | 131 |
float64(metric.Summary.GetSampleCount()), |
| 134 |
- out, |
|
| 135 | 132 |
) |
| 136 | 133 |
case dto.MetricType_HISTOGRAM: |
| 137 | 134 |
if metric.Histogram == nil {
|
| ... | ... |
@@ -140,46 +219,42 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
| 140 | 140 |
) |
| 141 | 141 |
} |
| 142 | 142 |
infSeen := false |
| 143 |
- for _, q := range metric.Histogram.Bucket {
|
|
| 143 |
+ for _, b := range metric.Histogram.Bucket {
|
|
| 144 | 144 |
n, err = writeSample( |
| 145 |
- name+"_bucket", metric, |
|
| 146 |
- model.BucketLabel, fmt.Sprint(q.GetUpperBound()), |
|
| 147 |
- float64(q.GetCumulativeCount()), |
|
| 148 |
- out, |
|
| 145 |
+ w, name, "_bucket", metric, |
|
| 146 |
+ model.BucketLabel, b.GetUpperBound(), |
|
| 147 |
+ float64(b.GetCumulativeCount()), |
|
| 149 | 148 |
) |
| 150 | 149 |
written += n |
| 151 | 150 |
if err != nil {
|
| 152 |
- return written, err |
|
| 151 |
+ return |
|
| 153 | 152 |
} |
| 154 |
- if math.IsInf(q.GetUpperBound(), +1) {
|
|
| 153 |
+ if math.IsInf(b.GetUpperBound(), +1) {
|
|
| 155 | 154 |
infSeen = true |
| 156 | 155 |
} |
| 157 | 156 |
} |
| 158 | 157 |
if !infSeen {
|
| 159 | 158 |
n, err = writeSample( |
| 160 |
- name+"_bucket", metric, |
|
| 161 |
- model.BucketLabel, "+Inf", |
|
| 159 |
+ w, name, "_bucket", metric, |
|
| 160 |
+ model.BucketLabel, math.Inf(+1), |
|
| 162 | 161 |
float64(metric.Histogram.GetSampleCount()), |
| 163 |
- out, |
|
| 164 | 162 |
) |
| 163 |
+ written += n |
|
| 165 | 164 |
if err != nil {
|
| 166 |
- return written, err |
|
| 165 |
+ return |
|
| 167 | 166 |
} |
| 168 |
- written += n |
|
| 169 | 167 |
} |
| 170 | 168 |
n, err = writeSample( |
| 171 |
- name+"_sum", metric, "", "", |
|
| 169 |
+ w, name, "_sum", metric, "", 0, |
|
| 172 | 170 |
metric.Histogram.GetSampleSum(), |
| 173 |
- out, |
|
| 174 | 171 |
) |
| 172 |
+ written += n |
|
| 175 | 173 |
if err != nil {
|
| 176 |
- return written, err |
|
| 174 |
+ return |
|
| 177 | 175 |
} |
| 178 |
- written += n |
|
| 179 | 176 |
n, err = writeSample( |
| 180 |
- name+"_count", metric, "", "", |
|
| 177 |
+ w, name, "_count", metric, "", 0, |
|
| 181 | 178 |
float64(metric.Histogram.GetSampleCount()), |
| 182 |
- out, |
|
| 183 | 179 |
) |
| 184 | 180 |
default: |
| 185 | 181 |
return written, fmt.Errorf( |
| ... | ... |
@@ -188,116 +263,204 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
| 188 | 188 |
} |
| 189 | 189 |
written += n |
| 190 | 190 |
if err != nil {
|
| 191 |
- return written, err |
|
| 191 |
+ return |
|
| 192 | 192 |
} |
| 193 | 193 |
} |
| 194 |
- return written, nil |
|
| 194 |
+ return |
|
| 195 | 195 |
} |
| 196 | 196 |
|
| 197 |
-// writeSample writes a single sample in text format to out, given the metric |
|
| 197 |
+// writeSample writes a single sample in text format to w, given the metric |
|
| 198 | 198 |
// name, the metric proto message itself, optionally an additional label name |
| 199 |
-// and value (use empty strings if not required), and the value. The function |
|
| 200 |
-// returns the number of bytes written and any error encountered. |
|
| 199 |
+// with a float64 value (use empty string as label name if not required), and |
|
| 200 |
+// the value. The function returns the number of bytes written and any error |
|
| 201 |
+// encountered. |
|
| 201 | 202 |
func writeSample( |
| 202 |
- name string, |
|
| 203 |
+ w enhancedWriter, |
|
| 204 |
+ name, suffix string, |
|
| 203 | 205 |
metric *dto.Metric, |
| 204 |
- additionalLabelName, additionalLabelValue string, |
|
| 206 |
+ additionalLabelName string, additionalLabelValue float64, |
|
| 205 | 207 |
value float64, |
| 206 |
- out io.Writer, |
|
| 207 | 208 |
) (int, error) {
|
| 208 | 209 |
var written int |
| 209 |
- n, err := fmt.Fprint(out, name) |
|
| 210 |
+ n, err := w.WriteString(name) |
|
| 210 | 211 |
written += n |
| 211 | 212 |
if err != nil {
|
| 212 | 213 |
return written, err |
| 213 | 214 |
} |
| 214 |
- n, err = labelPairsToText( |
|
| 215 |
- metric.Label, |
|
| 216 |
- additionalLabelName, additionalLabelValue, |
|
| 217 |
- out, |
|
| 215 |
+ if suffix != "" {
|
|
| 216 |
+ n, err = w.WriteString(suffix) |
|
| 217 |
+ written += n |
|
| 218 |
+ if err != nil {
|
|
| 219 |
+ return written, err |
|
| 220 |
+ } |
|
| 221 |
+ } |
|
| 222 |
+ n, err = writeLabelPairs( |
|
| 223 |
+ w, metric.Label, additionalLabelName, additionalLabelValue, |
|
| 218 | 224 |
) |
| 219 | 225 |
written += n |
| 220 | 226 |
if err != nil {
|
| 221 | 227 |
return written, err |
| 222 | 228 |
} |
| 223 |
- n, err = fmt.Fprintf(out, " %v", value) |
|
| 229 |
+ err = w.WriteByte(' ')
|
|
| 230 |
+ written++ |
|
| 231 |
+ if err != nil {
|
|
| 232 |
+ return written, err |
|
| 233 |
+ } |
|
| 234 |
+ n, err = writeFloat(w, value) |
|
| 224 | 235 |
written += n |
| 225 | 236 |
if err != nil {
|
| 226 | 237 |
return written, err |
| 227 | 238 |
} |
| 228 | 239 |
if metric.TimestampMs != nil {
|
| 229 |
- n, err = fmt.Fprintf(out, " %v", *metric.TimestampMs) |
|
| 240 |
+ err = w.WriteByte(' ')
|
|
| 241 |
+ written++ |
|
| 242 |
+ if err != nil {
|
|
| 243 |
+ return written, err |
|
| 244 |
+ } |
|
| 245 |
+ n, err = writeInt(w, *metric.TimestampMs) |
|
| 230 | 246 |
written += n |
| 231 | 247 |
if err != nil {
|
| 232 | 248 |
return written, err |
| 233 | 249 |
} |
| 234 | 250 |
} |
| 235 |
- n, err = out.Write([]byte{'\n'})
|
|
| 236 |
- written += n |
|
| 251 |
+ err = w.WriteByte('\n')
|
|
| 252 |
+ written++ |
|
| 237 | 253 |
if err != nil {
|
| 238 | 254 |
return written, err |
| 239 | 255 |
} |
| 240 | 256 |
return written, nil |
| 241 | 257 |
} |
| 242 | 258 |
|
| 243 |
-// labelPairsToText converts a slice of LabelPair proto messages plus the |
|
| 259 |
+// writeLabelPairs converts a slice of LabelPair proto messages plus the |
|
| 244 | 260 |
// explicitly given additional label pair into text formatted as required by the |
| 245 |
-// text format and writes it to 'out'. An empty slice in combination with an |
|
| 246 |
-// empty string 'additionalLabelName' results in nothing being |
|
| 247 |
-// written. Otherwise, the label pairs are written, escaped as required by the |
|
| 248 |
-// text format, and enclosed in '{...}'. The function returns the number of
|
|
| 249 |
-// bytes written and any error encountered. |
|
| 250 |
-func labelPairsToText( |
|
| 261 |
+// text format and writes it to 'w'. An empty slice in combination with an empty |
|
| 262 |
+// string 'additionalLabelName' results in nothing being written. Otherwise, the |
|
| 263 |
+// label pairs are written, escaped as required by the text format, and enclosed |
|
| 264 |
+// in '{...}'. The function returns the number of bytes written and any error
|
|
| 265 |
+// encountered. |
|
| 266 |
+func writeLabelPairs( |
|
| 267 |
+ w enhancedWriter, |
|
| 251 | 268 |
in []*dto.LabelPair, |
| 252 |
- additionalLabelName, additionalLabelValue string, |
|
| 253 |
- out io.Writer, |
|
| 269 |
+ additionalLabelName string, additionalLabelValue float64, |
|
| 254 | 270 |
) (int, error) {
|
| 255 | 271 |
if len(in) == 0 && additionalLabelName == "" {
|
| 256 | 272 |
return 0, nil |
| 257 | 273 |
} |
| 258 |
- var written int |
|
| 259 |
- separator := '{'
|
|
| 274 |
+ var ( |
|
| 275 |
+ written int |
|
| 276 |
+ separator byte = '{'
|
|
| 277 |
+ ) |
|
| 260 | 278 |
for _, lp := range in {
|
| 261 |
- n, err := fmt.Fprintf( |
|
| 262 |
- out, `%c%s="%s"`, |
|
| 263 |
- separator, lp.GetName(), escapeString(lp.GetValue(), true), |
|
| 264 |
- ) |
|
| 279 |
+ err := w.WriteByte(separator) |
|
| 280 |
+ written++ |
|
| 281 |
+ if err != nil {
|
|
| 282 |
+ return written, err |
|
| 283 |
+ } |
|
| 284 |
+ n, err := w.WriteString(lp.GetName()) |
|
| 285 |
+ written += n |
|
| 286 |
+ if err != nil {
|
|
| 287 |
+ return written, err |
|
| 288 |
+ } |
|
| 289 |
+ n, err = w.WriteString(`="`) |
|
| 290 |
+ written += n |
|
| 291 |
+ if err != nil {
|
|
| 292 |
+ return written, err |
|
| 293 |
+ } |
|
| 294 |
+ n, err = writeEscapedString(w, lp.GetValue(), true) |
|
| 265 | 295 |
written += n |
| 266 | 296 |
if err != nil {
|
| 267 | 297 |
return written, err |
| 268 | 298 |
} |
| 299 |
+ err = w.WriteByte('"')
|
|
| 300 |
+ written++ |
|
| 301 |
+ if err != nil {
|
|
| 302 |
+ return written, err |
|
| 303 |
+ } |
|
| 269 | 304 |
separator = ',' |
| 270 | 305 |
} |
| 271 | 306 |
if additionalLabelName != "" {
|
| 272 |
- n, err := fmt.Fprintf( |
|
| 273 |
- out, `%c%s="%s"`, |
|
| 274 |
- separator, additionalLabelName, |
|
| 275 |
- escapeString(additionalLabelValue, true), |
|
| 276 |
- ) |
|
| 307 |
+ err := w.WriteByte(separator) |
|
| 308 |
+ written++ |
|
| 309 |
+ if err != nil {
|
|
| 310 |
+ return written, err |
|
| 311 |
+ } |
|
| 312 |
+ n, err := w.WriteString(additionalLabelName) |
|
| 313 |
+ written += n |
|
| 314 |
+ if err != nil {
|
|
| 315 |
+ return written, err |
|
| 316 |
+ } |
|
| 317 |
+ n, err = w.WriteString(`="`) |
|
| 318 |
+ written += n |
|
| 319 |
+ if err != nil {
|
|
| 320 |
+ return written, err |
|
| 321 |
+ } |
|
| 322 |
+ n, err = writeFloat(w, additionalLabelValue) |
|
| 277 | 323 |
written += n |
| 278 | 324 |
if err != nil {
|
| 279 | 325 |
return written, err |
| 280 | 326 |
} |
| 327 |
+ err = w.WriteByte('"')
|
|
| 328 |
+ written++ |
|
| 329 |
+ if err != nil {
|
|
| 330 |
+ return written, err |
|
| 331 |
+ } |
|
| 281 | 332 |
} |
| 282 |
- n, err := out.Write([]byte{'}'})
|
|
| 283 |
- written += n |
|
| 333 |
+ err := w.WriteByte('}')
|
|
| 334 |
+ written++ |
|
| 284 | 335 |
if err != nil {
|
| 285 | 336 |
return written, err |
| 286 | 337 |
} |
| 287 | 338 |
return written, nil |
| 288 | 339 |
} |
| 289 | 340 |
|
| 341 |
+// writeEscapedString replaces '\' by '\\', new line character by '\n', and - if |
|
| 342 |
+// includeDoubleQuote is true - '"' by '\"'. |
|
| 290 | 343 |
var ( |
| 291 |
- escape = strings.NewReplacer("\\", `\\`, "\n", `\n`)
|
|
| 292 |
- escapeWithDoubleQuote = strings.NewReplacer("\\", `\\`, "\n", `\n`, "\"", `\"`)
|
|
| 344 |
+ escaper = strings.NewReplacer("\\", `\\`, "\n", `\n`)
|
|
| 345 |
+ quotedEscaper = strings.NewReplacer("\\", `\\`, "\n", `\n`, "\"", `\"`)
|
|
| 293 | 346 |
) |
| 294 | 347 |
|
| 295 |
-// escapeString replaces '\' by '\\', new line character by '\n', and - if |
|
| 296 |
-// includeDoubleQuote is true - '"' by '\"'. |
|
| 297 |
-func escapeString(v string, includeDoubleQuote bool) string {
|
|
| 348 |
+func writeEscapedString(w enhancedWriter, v string, includeDoubleQuote bool) (int, error) {
|
|
| 298 | 349 |
if includeDoubleQuote {
|
| 299 |
- return escapeWithDoubleQuote.Replace(v) |
|
| 350 |
+ return quotedEscaper.WriteString(w, v) |
|
| 351 |
+ } else {
|
|
| 352 |
+ return escaper.WriteString(w, v) |
|
| 353 |
+ } |
|
| 354 |
+} |
|
| 355 |
+ |
|
| 356 |
+// writeFloat is equivalent to fmt.Fprint with a float64 argument but hardcodes |
|
| 357 |
+// a few common cases for increased efficiency. For non-hardcoded cases, it uses |
|
| 358 |
+// strconv.AppendFloat to avoid allocations, similar to writeInt. |
|
| 359 |
+func writeFloat(w enhancedWriter, f float64) (int, error) {
|
|
| 360 |
+ switch {
|
|
| 361 |
+ case f == 1: |
|
| 362 |
+ return 1, w.WriteByte('1')
|
|
| 363 |
+ case f == 0: |
|
| 364 |
+ return 1, w.WriteByte('0')
|
|
| 365 |
+ case f == -1: |
|
| 366 |
+ return w.WriteString("-1")
|
|
| 367 |
+ case math.IsNaN(f): |
|
| 368 |
+ return w.WriteString("NaN")
|
|
| 369 |
+ case math.IsInf(f, +1): |
|
| 370 |
+ return w.WriteString("+Inf")
|
|
| 371 |
+ case math.IsInf(f, -1): |
|
| 372 |
+ return w.WriteString("-Inf")
|
|
| 373 |
+ default: |
|
| 374 |
+ bp := numBufPool.Get().(*[]byte) |
|
| 375 |
+ *bp = strconv.AppendFloat((*bp)[:0], f, 'g', -1, 64) |
|
| 376 |
+ written, err := w.Write(*bp) |
|
| 377 |
+ numBufPool.Put(bp) |
|
| 378 |
+ return written, err |
|
| 300 | 379 |
} |
| 380 |
+} |
|
| 301 | 381 |
|
| 302 |
- return escape.Replace(v) |
|
| 382 |
+// writeInt is equivalent to fmt.Fprint with an int64 argument but uses |
|
| 383 |
+// strconv.AppendInt with a byte slice taken from a sync.Pool to avoid |
|
| 384 |
+// allocations. |
|
| 385 |
+func writeInt(w enhancedWriter, i int64) (int, error) {
|
|
| 386 |
+ bp := numBufPool.Get().(*[]byte) |
|
| 387 |
+ *bp = strconv.AppendInt((*bp)[:0], i, 10) |
|
| 388 |
+ written, err := w.Write(*bp) |
|
| 389 |
+ numBufPool.Put(bp) |
|
| 390 |
+ return written, err |
|
| 303 | 391 |
} |
| ... | ... |
@@ -325,7 +325,7 @@ func (p *TextParser) startLabelValue() stateFn {
|
| 325 | 325 |
// - Other labels have to be added to currentLabels for signature calculation. |
| 326 | 326 |
if p.currentMF.GetType() == dto.MetricType_SUMMARY {
|
| 327 | 327 |
if p.currentLabelPair.GetName() == model.QuantileLabel {
|
| 328 |
- if p.currentQuantile, p.err = strconv.ParseFloat(p.currentLabelPair.GetValue(), 64); p.err != nil {
|
|
| 328 |
+ if p.currentQuantile, p.err = parseFloat(p.currentLabelPair.GetValue()); p.err != nil {
|
|
| 329 | 329 |
// Create a more helpful error message. |
| 330 | 330 |
p.parseError(fmt.Sprintf("expected float as value for 'quantile' label, got %q", p.currentLabelPair.GetValue()))
|
| 331 | 331 |
return nil |
| ... | ... |
@@ -337,7 +337,7 @@ func (p *TextParser) startLabelValue() stateFn {
|
| 337 | 337 |
// Similar special treatment of histograms. |
| 338 | 338 |
if p.currentMF.GetType() == dto.MetricType_HISTOGRAM {
|
| 339 | 339 |
if p.currentLabelPair.GetName() == model.BucketLabel {
|
| 340 |
- if p.currentBucket, p.err = strconv.ParseFloat(p.currentLabelPair.GetValue(), 64); p.err != nil {
|
|
| 340 |
+ if p.currentBucket, p.err = parseFloat(p.currentLabelPair.GetValue()); p.err != nil {
|
|
| 341 | 341 |
// Create a more helpful error message. |
| 342 | 342 |
p.parseError(fmt.Sprintf("expected float as value for 'le' label, got %q", p.currentLabelPair.GetValue()))
|
| 343 | 343 |
return nil |
| ... | ... |
@@ -359,7 +359,7 @@ func (p *TextParser) startLabelValue() stateFn {
|
| 359 | 359 |
} |
| 360 | 360 |
return p.readingValue |
| 361 | 361 |
default: |
| 362 |
- p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.Value))
|
|
| 362 |
+ p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.GetValue()))
|
|
| 363 | 363 |
return nil |
| 364 | 364 |
} |
| 365 | 365 |
} |
| ... | ... |
@@ -392,7 +392,7 @@ func (p *TextParser) readingValue() stateFn {
|
| 392 | 392 |
if p.readTokenUntilWhitespace(); p.err != nil {
|
| 393 | 393 |
return nil // Unexpected end of input. |
| 394 | 394 |
} |
| 395 |
- value, err := strconv.ParseFloat(p.currentToken.String(), 64) |
|
| 395 |
+ value, err := parseFloat(p.currentToken.String()) |
|
| 396 | 396 |
if err != nil {
|
| 397 | 397 |
// Create a more helpful error message. |
| 398 | 398 |
p.parseError(fmt.Sprintf("expected float as value, got %q", p.currentToken.String()))
|
| ... | ... |
@@ -755,3 +755,10 @@ func histogramMetricName(name string) string {
|
| 755 | 755 |
return name |
| 756 | 756 |
} |
| 757 | 757 |
} |
| 758 |
+ |
|
| 759 |
+func parseFloat(s string) (float64, error) {
|
|
| 760 |
+ if strings.ContainsAny(s, "pP_") {
|
|
| 761 |
+ return 0, fmt.Errorf("unsupported character in float")
|
|
| 762 |
+ } |
|
| 763 |
+ return strconv.ParseFloat(s, 64) |
|
| 764 |
+} |
| 758 | 765 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,22 @@ |
| 0 |
+module github.com/prometheus/common |
|
| 1 |
+ |
|
| 2 |
+require ( |
|
| 3 |
+ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect |
|
| 4 |
+ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 // indirect |
|
| 5 |
+ github.com/go-kit/kit v0.9.0 |
|
| 6 |
+ github.com/go-logfmt/logfmt v0.4.0 // indirect |
|
| 7 |
+ github.com/golang/protobuf v1.3.2 |
|
| 8 |
+ github.com/julienschmidt/httprouter v1.2.0 |
|
| 9 |
+ github.com/matttproud/golang_protobuf_extensions v1.0.1 |
|
| 10 |
+ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 |
|
| 11 |
+ github.com/pkg/errors v0.8.1 |
|
| 12 |
+ github.com/prometheus/client_golang v1.0.0 |
|
| 13 |
+ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 |
|
| 14 |
+ github.com/sirupsen/logrus v1.4.2 |
|
| 15 |
+ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 // indirect |
|
| 16 |
+ golang.org/x/sys v0.0.0-20190422165155-953cdadca894 |
|
| 17 |
+ gopkg.in/alecthomas/kingpin.v2 v2.2.6 |
|
| 18 |
+ gopkg.in/yaml.v2 v2.2.2 |
|
| 19 |
+) |
|
| 20 |
+ |
|
| 21 |
+go 1.11 |
| ... | ... |
@@ -1,12 +1,12 @@ |
| 1 | 1 |
/* |
| 2 |
+Copyright (c) 2011, Open Knowledge Foundation Ltd. |
|
| 3 |
+All rights reserved. |
|
| 4 |
+ |
|
| 2 | 5 |
HTTP Content-Type Autonegotiation. |
| 3 | 6 |
|
| 4 | 7 |
The functions in this package implement the behaviour specified in |
| 5 | 8 |
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html |
| 6 | 9 |
|
| 7 |
-Copyright (c) 2011, Open Knowledge Foundation Ltd. |
|
| 8 |
-All rights reserved. |
|
| 9 |
- |
|
| 10 | 10 |
Redistribution and use in source and binary forms, with or without |
| 11 | 11 |
modification, are permitted provided that the following conditions are |
| 12 | 12 |
met: |
| ... | ... |
@@ -43,7 +43,7 @@ const ( |
| 43 | 43 |
// (1970-01-01 00:00 UTC) excluding leap seconds. |
| 44 | 44 |
type Time int64 |
| 45 | 45 |
|
| 46 |
-// Interval describes and interval between two timestamps. |
|
| 46 |
+// Interval describes an interval between two timestamps. |
|
| 47 | 47 |
type Interval struct {
|
| 48 | 48 |
Start, End Time |
| 49 | 49 |
} |
| ... | ... |
@@ -150,7 +150,13 @@ func (t *Time) UnmarshalJSON(b []byte) error {
|
| 150 | 150 |
return err |
| 151 | 151 |
} |
| 152 | 152 |
|
| 153 |
- *t = Time(v + va) |
|
| 153 |
+ // If the value was something like -0.1 the negative is lost in the |
|
| 154 |
+ // parsing because of the leading zero, this ensures that we capture it. |
|
| 155 |
+ if len(p[0]) > 0 && p[0][0] == '-' && v+va > 0 {
|
|
| 156 |
+ *t = Time(v+va) * -1 |
|
| 157 |
+ } else {
|
|
| 158 |
+ *t = Time(v + va) |
|
| 159 |
+ } |
|
| 154 | 160 |
|
| 155 | 161 |
default: |
| 156 | 162 |
return fmt.Errorf("invalid time %q", string(b))
|