Copyright 2017, OpenCensus Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Package prometheus contains a Prometheus exporter that supports exporting OpenCensus views as Prometheus metrics.
package prometheus // import "contrib.go.opencensus.io/exporter/prometheus"

import (
	
	
	
	

	
	
	
	
	
	
)
Exporter exports stats to Prometheus, users need to register the exporter as an http.Handler to be able to export.
Options contains options for configuring the exporter.
type Options struct {
	Namespace   string
	Registry    *prometheus.Registry
	OnError     func(err error)
	ConstLabels prometheus.Labels // ConstLabels will be set as labels on all views.
}
NewExporter returns an exporter that exports stats to Prometheus.
func ( Options) (*Exporter, error) {
	if .Registry == nil {
		.Registry = prometheus.NewRegistry()
	}
	 := newCollector(, .Registry)
	 := &Exporter{
		opts:    ,
		g:       .Registry,
		c:       ,
		handler: promhttp.HandlerFor(.Registry, promhttp.HandlerOpts{}),
	}
	.ensureRegisteredOnce()

	return , nil
}

var _ http.Handler = (*Exporter)(nil)
ensureRegisteredOnce invokes reg.Register on the collector itself exactly once to ensure that we don't get errors such as cannot register the collector: descriptor Desc{fqName: *} already exists with the same fully-qualified name and const label values which is documented by Prometheus at https://github.com/prometheus/client_golang/blob/fcc130e101e76c5d303513d0e28f4b6d732845c7/prometheus/registry.go#L89-L101
func ( *collector) () {
	.registerOnce.Do(func() {
		if  := .reg.Register();  != nil {
			.opts.onError(fmt.Errorf("cannot register the collector: %v", ))
		}
	})

}

func ( *Options) ( error) {
	if .OnError != nil {
		.OnError()
	} else {
		log.Printf("Failed to export to Prometheus: %v", )
	}
}
ExportView exports to the Prometheus if view data has one or more rows. Each OpenCensus AggregationData will be converted to corresponding Prometheus Metric: SumData will be converted to Untyped Metric, CountData will be a Counter Metric, DistributionData will be a Histogram Metric. Deprecated in lieu of metricexport.Reader interface.
func ( *Exporter) ( *view.Data) {
}
ServeHTTP serves the Prometheus endpoint.
collector implements prometheus.Collector
type collector struct {
	opts Options
	mu   sync.Mutex // mu guards all the fields.

	registerOnce sync.Once
reg helps collector register views dynamically.
reader reads metrics from all registered producers.
	reader *metricexport.Reader
}

func ( *collector) ( chan<- *prometheus.Desc) {
	 := &descExporter{c: , descCh: }
	.reader.ReadAndExport()
}
Collect fetches the statistics from OpenCensus and delivers them as Prometheus Metrics. Collect is invoked every time a prometheus.Gatherer is run for example when the HTTP endpoint is invoked by Prometheus.
ExportMetrics exports to the Prometheus. Each OpenCensus Metric will be converted to corresponding Prometheus Metric: TypeCumulativeInt64 and TypeCumulativeFloat64 will be a Counter Metric, TypeCumulativeDistribution will be a Histogram Metric. TypeGaugeFloat64 and TypeGaugeInt64 will be a Gauge Metric
func ( *metricExporter) ( context.Context,  []*metricdata.Metric) error {
	for ,  := range  {
		 := .c.toDesc()
		for ,  := range .TimeSeries {
			 := toLabelValues(.LabelValues)
			for ,  := range .Points {
				,  := toPromMetric(, , , )
				if  != nil {
					.c.opts.onError()
				} else if  != nil {
					.metricCh <- 
				}
			}
		}
	}
	return nil
}

type descExporter struct {
	c      *collector
	descCh chan<- *prometheus.Desc
}
ExportMetrics exports descriptor to the Prometheus. It is invoked when request to scrape descriptors is received.
func ( *descExporter) ( context.Context,  []*metricdata.Metric) error {
	for ,  := range  {
		 := .c.toDesc()
		.descCh <- 
	}
	return nil
}

func ( []metricdata.LabelKey) ( []string) {
	for ,  := range  {
		 = append(, sanitize(.Key))
	}
	return 
}

func ( string,  *metricdata.Metric) string {
	var  string
	if  != "" {
		 =  + "_"
	}
	return  + sanitize(.Descriptor.Name)
}

func (
	 *prometheus.Desc,
	 *metricdata.Metric,
	 metricdata.Point,
	 []string) (prometheus.Metric, error) {
	switch .Descriptor.Type {
	case metricdata.TypeCumulativeFloat64, metricdata.TypeCumulativeInt64:
		,  := toPromValue()
		if  != nil {
			return nil, 
		}
		return prometheus.NewConstMetric(, prometheus.CounterValue, , ...)

	case metricdata.TypeGaugeFloat64, metricdata.TypeGaugeInt64:
		,  := toPromValue()
		if  != nil {
			return nil, 
		}
		return prometheus.NewConstMetric(, prometheus.GaugeValue, , ...)

	case metricdata.TypeCumulativeDistribution:
		switch v := .Value.(type) {
		case *metricdata.Distribution:
Histograms are cumulative in Prometheus. Get cumulative bucket counts.
			 := uint64(0)
			for ,  := range .BucketOptions.Bounds {
				 += uint64(.Buckets[].Count)
				[] = 
			}
			return prometheus.NewConstHistogram(, uint64(.Count), .Sum, , ...)
		default:
			return nil, typeMismatchError()
		}
TODO: [rghetia] add support for TypeSummary.
		return nil, nil
	default:
		return nil, fmt.Errorf("aggregation %T is not yet supported", .Descriptor.Type)
	}
}

func ( []metricdata.LabelValue) ( []string) {
	for ,  := range  {
		if .Present {
			 = append(, .Value)
		} else {
			 = append(, "")
		}
	}
	return 
}

func ( metricdata.Point) error {
	return fmt.Errorf("point type %T does not match metric type", )

}

func ( metricdata.Point) (float64, error) {
	switch v := .Value.(type) {
	case float64:
		return , nil
	case int64:
		return float64(), nil
	default:
		return 0.0, typeMismatchError()
	}