func extractMetricFamily(out Ingester, o *ProcessOptions, family *dto.MetricFamily) error { switch family.GetType() { case dto.MetricType_COUNTER: if err := extractCounter(out, o, family); err != nil { return err } case dto.MetricType_GAUGE: if err := extractGauge(out, o, family); err != nil { return err } case dto.MetricType_SUMMARY: if err := extractSummary(out, o, family); err != nil { return err } case dto.MetricType_UNTYPED: if err := extractUntyped(out, o, family); err != nil { return err } case dto.MetricType_HISTOGRAM: if err := extractHistogram(out, o, family); err != nil { return err } } return nil }
func extractSamples(f *dto.MetricFamily, o *DecodeOptions) model.Vector { switch f.GetType() { case dto.MetricType_COUNTER: return extractCounter(o, f) case dto.MetricType_GAUGE: return extractGauge(o, f) case dto.MetricType_SUMMARY: return extractSummary(o, f) case dto.MetricType_UNTYPED: return extractUntyped(o, f) case dto.MetricType_HISTOGRAM: return extractHistogram(o, f) } panic("expfmt.extractSamples: unknown metric family type") }
func (collector *PrometheusCollector) GetSpec() []v1.MetricSpec { response, err := collector.httpClient.Get(collector.configFile.Endpoint.URL) if err != nil { return nil } defer response.Body.Close() if response.StatusCode != http.StatusOK { return nil } dec := expfmt.NewDecoder(response.Body, expfmt.ResponseFormat(response.Header)) var specs []v1.MetricSpec for { d := rawmodel.MetricFamily{} if err = dec.Decode(&d); err != nil { break } name := d.GetName() if len(name) == 0 { continue } // If metrics to collect is specified, skip any metrics not in the list to collect. if _, ok := collector.metricsSet[name]; collector.metricsSet != nil && !ok { continue } spec := v1.MetricSpec{ Name: name, Type: metricType(d.GetType()), Format: v1.FloatType, } specs = append(specs, spec) } if err != nil && err != io.EOF { return nil } return specs }
// checkMetricConsistency checks if the provided Metric is consistent with the // provided MetricFamily. It also hashed the Metric labels and the MetricFamily // name. If the resulting hash is alread in the provided metricHashes, an error // is returned. If not, it is added to metricHashes. The provided dimHashes maps // MetricFamily names to their dimHash (hashed sorted label names). If dimHashes // doesn't yet contain a hash for the provided MetricFamily, it is // added. Otherwise, an error is returned if the existing dimHashes in not equal // the calculated dimHash. func checkMetricConsistency( metricFamily *dto.MetricFamily, dtoMetric *dto.Metric, metricHashes map[uint64]struct{}, dimHashes map[string]uint64, ) error { // Type consistency with metric family. if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil || metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil || metricFamily.GetType() == dto.MetricType_SUMMARY && dtoMetric.Summary == nil || metricFamily.GetType() == dto.MetricType_HISTOGRAM && dtoMetric.Histogram == nil || metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil { return fmt.Errorf( "collected metric %s %s is not a %s", metricFamily.GetName(), dtoMetric, metricFamily.GetType(), ) } // Is the metric unique (i.e. no other metric with the same name and the same label values)? h := hashNew() h = hashAdd(h, metricFamily.GetName()) h = hashAddByte(h, separatorByte) dh := hashNew() // Make sure label pairs are sorted. We depend on it for the consistency // check. sort.Sort(LabelPairSorter(dtoMetric.Label)) for _, lp := range dtoMetric.Label { h = hashAdd(h, lp.GetValue()) h = hashAddByte(h, separatorByte) dh = hashAdd(dh, lp.GetName()) dh = hashAddByte(dh, separatorByte) } if _, exists := metricHashes[h]; exists { return fmt.Errorf( "collected metric %s %s was collected before with the same name and label values", metricFamily.GetName(), dtoMetric, ) } if dimHash, ok := dimHashes[metricFamily.GetName()]; ok { if dimHash != dh { return fmt.Errorf( "collected metric %s %s has label dimensions inconsistent with previously collected metrics in the same metric family", metricFamily.GetName(), dtoMetric, ) } } else { dimHashes[metricFamily.GetName()] = dh } metricHashes[h] = struct{}{} return nil }
func newMetricFamily(dtoMF *dto.MetricFamily) *metricFamily { mf := &metricFamily{ Name: dtoMF.GetName(), Help: dtoMF.GetHelp(), Type: dtoMF.GetType().String(), Metrics: make([]interface{}, len(dtoMF.Metric)), } for i, m := range dtoMF.Metric { if dtoMF.GetType() == dto.MetricType_SUMMARY { mf.Metrics[i] = summary{ Labels: makeLabels(m), Quantiles: makeQuantiles(m), Count: fmt.Sprint(m.GetSummary().GetSampleCount()), Sum: fmt.Sprint(m.GetSummary().GetSampleSum()), } } else if dtoMF.GetType() == dto.MetricType_HISTOGRAM { mf.Metrics[i] = histogram{ Labels: makeLabels(m), Buckets: makeBuckets(m), Count: fmt.Sprint(m.GetHistogram().GetSampleCount()), Sum: fmt.Sprint(m.GetSummary().GetSampleSum()), } } else { mf.Metrics[i] = metric{ Labels: makeLabels(m), Value: fmt.Sprint(getValue(m)), } } } return mf }
func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *dto.Metric, desc *Desc, metricHashes map[uint64]struct{}) error { // Type consistency with metric family. if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil || metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil || metricFamily.GetType() == dto.MetricType_SUMMARY && dtoMetric.Summary == nil || metricFamily.GetType() == dto.MetricType_HISTOGRAM && dtoMetric.Histogram == nil || metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil { return fmt.Errorf( "collected metric %s %s is not a %s", metricFamily.GetName(), dtoMetric, metricFamily.GetType(), ) } // Is the metric unique (i.e. no other metric with the same name and the same label values)? h := fnv.New64a() var buf bytes.Buffer buf.WriteString(metricFamily.GetName()) buf.WriteByte(separatorByte) h.Write(buf.Bytes()) // Make sure label pairs are sorted. We depend on it for the consistency // check. Label pairs must be sorted by contract. But the point of this // method is to check for contract violations. So we better do the sort // now. sort.Sort(LabelPairSorter(dtoMetric.Label)) for _, lp := range dtoMetric.Label { buf.Reset() buf.WriteString(lp.GetValue()) buf.WriteByte(separatorByte) h.Write(buf.Bytes()) } metricHash := h.Sum64() if _, exists := metricHashes[metricHash]; exists { return fmt.Errorf( "collected metric %s %s was collected before with the same name and label values", metricFamily.GetName(), dtoMetric, ) } metricHashes[metricHash] = struct{}{} if desc == nil { return nil // Nothing left to check if we have no desc. } // Desc consistency with metric family. if metricFamily.GetName() != desc.fqName { return fmt.Errorf( "collected metric %s %s has name %q but should have %q", metricFamily.GetName(), dtoMetric, metricFamily.GetName(), desc.fqName, ) } if metricFamily.GetHelp() != desc.help { return fmt.Errorf( "collected metric %s %s has help %q but should have %q", metricFamily.GetName(), dtoMetric, metricFamily.GetHelp(), desc.help, ) } // Is the desc consistent with the content of the metric? lpsFromDesc := make([]*dto.LabelPair, 0, len(dtoMetric.Label)) lpsFromDesc = append(lpsFromDesc, desc.constLabelPairs...) for _, l := range desc.variableLabels { lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{ Name: proto.String(l), }) } if len(lpsFromDesc) != len(dtoMetric.Label) { return fmt.Errorf( "labels in collected metric %s %s are inconsistent with descriptor %s", metricFamily.GetName(), dtoMetric, desc, ) } sort.Sort(LabelPairSorter(lpsFromDesc)) for i, lpFromDesc := range lpsFromDesc { lpFromMetric := dtoMetric.Label[i] if lpFromDesc.GetName() != lpFromMetric.GetName() || lpFromDesc.Value != nil && lpFromDesc.GetValue() != lpFromMetric.GetValue() { return fmt.Errorf( "labels in collected metric %s %s are inconsistent with descriptor %s", metricFamily.GetName(), dtoMetric, desc, ) } } r.mtx.RLock() // Remaining checks need the read lock. defer r.mtx.RUnlock() // Is the desc registered? if _, exist := r.descIDs[desc.id]; !exist { return fmt.Errorf( "collected metric %s %s with unregistered descriptor %s", metricFamily.GetName(), dtoMetric, desc, ) } return nil }
// MetricFamilyToText converts a MetricFamily proto message into text format and // writes the resulting lines to 'out'. It returns the number of bytes written // and any error encountered. This function does not perform checks on the // content of the metric and label names, i.e. invalid metric or label names // will result in invalid text format output. // This method fulfills the type 'prometheus.encoder'. func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) { var written int // Fail-fast checks. if len(in.Metric) == 0 { return written, fmt.Errorf("MetricFamily has no metrics: %s", in) } name := in.GetName() if name == "" { return written, fmt.Errorf("MetricFamily has no name: %s", in) } // Comments, first HELP, then TYPE. if in.Help != nil { n, err := fmt.Fprintf( out, "# HELP %s %s\n", name, escapeString(*in.Help, false), ) written += n if err != nil { return written, err } } metricType := in.GetType() n, err := fmt.Fprintf( out, "# TYPE %s %s\n", name, strings.ToLower(metricType.String()), ) written += n if err != nil { return written, err } // Finally the samples, one line for each. for _, metric := range in.Metric { switch metricType { case dto.MetricType_COUNTER: if metric.Counter == nil { return written, fmt.Errorf( "expected counter in metric %s %s", name, metric, ) } n, err = writeSample( name, metric, "", "", metric.Counter.GetValue(), out, ) case dto.MetricType_GAUGE: if metric.Gauge == nil { return written, fmt.Errorf( "expected gauge in metric %s %s", name, metric, ) } n, err = writeSample( name, metric, "", "", metric.Gauge.GetValue(), out, ) case dto.MetricType_UNTYPED: if metric.Untyped == nil { return written, fmt.Errorf( "expected untyped in metric %s %s", name, metric, ) } n, err = writeSample( name, metric, "", "", metric.Untyped.GetValue(), out, ) case dto.MetricType_SUMMARY: if metric.Summary == nil { return written, fmt.Errorf( "expected summary in metric %s %s", name, metric, ) } for _, q := range metric.Summary.Quantile { n, err = writeSample( name, metric, model.QuantileLabel, fmt.Sprint(q.GetQuantile()), q.GetValue(), out, ) written += n if err != nil { return written, err } } n, err = writeSample( name+"_sum", metric, "", "", metric.Summary.GetSampleSum(), out, ) if err != nil { return written, err } written += n n, err = writeSample( name+"_count", metric, "", "", float64(metric.Summary.GetSampleCount()), out, ) case dto.MetricType_HISTOGRAM: if metric.Histogram == nil { return written, fmt.Errorf( "expected histogram in metric %s %s", name, metric, ) } infSeen := false for _, q := range metric.Histogram.Bucket { n, err = writeSample( name+"_bucket", metric, model.BucketLabel, fmt.Sprint(q.GetUpperBound()), float64(q.GetCumulativeCount()), out, ) written += n if err != nil { return written, err } if math.IsInf(q.GetUpperBound(), +1) { infSeen = true } } if !infSeen { n, err = writeSample( name+"_bucket", metric, model.BucketLabel, "+Inf", float64(metric.Histogram.GetSampleCount()), out, ) if err != nil { return written, err } written += n } n, err = writeSample( name+"_sum", metric, "", "", metric.Histogram.GetSampleSum(), out, ) if err != nil { return written, err } written += n n, err = writeSample( name+"_count", metric, "", "", float64(metric.Histogram.GetSampleCount()), out, ) default: return written, fmt.Errorf( "unexpected type in metric %s %s", name, metric, ) } written += n if err != nil { return written, err } } return written, nil }
func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *dto.Metric, desc *Desc, metricHashes map[uint64]struct{}) error { // Type consistency with metric family. if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil || metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil || metricFamily.GetType() == dto.MetricType_SUMMARY && dtoMetric.Summary == nil || metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil { return fmt.Errorf( "collected metric %q is not a %s", dtoMetric, metricFamily.Type, ) } // Desc consistency with metric family. if metricFamily.GetHelp() != desc.help { return fmt.Errorf( "collected metric %q has help %q but should have %q", dtoMetric, desc.help, metricFamily.GetHelp(), ) } // Is the desc consistent with the content of the metric? lpsFromDesc := make([]*dto.LabelPair, 0, len(dtoMetric.Label)) lpsFromDesc = append(lpsFromDesc, desc.constLabelPairs...) for _, l := range desc.variableLabels { lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{ Name: proto.String(l), }) } if len(lpsFromDesc) != len(dtoMetric.Label) { return fmt.Errorf( "labels in collected metric %q are inconsistent with descriptor %s", dtoMetric, desc, ) } sort.Sort(LabelPairSorter(lpsFromDesc)) for i, lpFromDesc := range lpsFromDesc { lpFromMetric := dtoMetric.Label[i] if lpFromDesc.GetName() != lpFromMetric.GetName() || lpFromDesc.Value != nil && lpFromDesc.GetValue() != lpFromMetric.GetValue() { return fmt.Errorf( "labels in collected metric %q are inconsistent with descriptor %s", dtoMetric, desc, ) } } // Is the metric unique (i.e. no other metric with the same name and the same label values)? h := fnv.New64a() var buf bytes.Buffer buf.WriteString(desc.fqName) buf.WriteByte(model.SeparatorByte) h.Write(buf.Bytes()) for _, lp := range dtoMetric.Label { buf.Reset() buf.WriteString(lp.GetValue()) buf.WriteByte(model.SeparatorByte) h.Write(buf.Bytes()) } metricHash := h.Sum64() if _, exists := metricHashes[metricHash]; exists { return fmt.Errorf( "collected metric %q was collected before with the same name and label values", dtoMetric, ) } metricHashes[metricHash] = struct{}{} r.mtx.RLock() // Remaining checks need the read lock. defer r.mtx.RUnlock() // Is the desc registered? if _, exist := r.descIDs[desc.id]; !exist { return fmt.Errorf("collected metric %q with unregistered descriptor %s", dtoMetric, desc) } return nil }