265 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			265 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
| // Copyright 2016 The Prometheus 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 v1
 | |
| 
 | |
| import (
 | |
| 	"unsafe"
 | |
| 
 | |
| 	jsoniter "github.com/json-iterator/go"
 | |
| 
 | |
| 	"github.com/prometheus/prometheus/model/exemplar"
 | |
| 	"github.com/prometheus/prometheus/model/labels"
 | |
| 	"github.com/prometheus/prometheus/promql"
 | |
| 	"github.com/prometheus/prometheus/util/jsonutil"
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	jsoniter.RegisterTypeEncoderFunc("promql.Vector", unsafeMarshalVectorJSON, neverEmpty)
 | |
| 	jsoniter.RegisterTypeEncoderFunc("promql.Matrix", unsafeMarshalMatrixJSON, neverEmpty)
 | |
| 	jsoniter.RegisterTypeEncoderFunc("promql.Series", unsafeMarshalSeriesJSON, neverEmpty)
 | |
| 	jsoniter.RegisterTypeEncoderFunc("promql.Sample", unsafeMarshalSampleJSON, neverEmpty)
 | |
| 	jsoniter.RegisterTypeEncoderFunc("promql.FPoint", unsafeMarshalFPointJSON, neverEmpty)
 | |
| 	jsoniter.RegisterTypeEncoderFunc("promql.HPoint", unsafeMarshalHPointJSON, neverEmpty)
 | |
| 	jsoniter.RegisterTypeEncoderFunc("exemplar.Exemplar", marshalExemplarJSON, neverEmpty)
 | |
| 	jsoniter.RegisterTypeEncoderFunc("labels.Labels", unsafeMarshalLabelsJSON, labelsIsEmpty)
 | |
| }
 | |
| 
 | |
| // JSONCodec is a Codec that encodes API responses as JSON.
 | |
| type JSONCodec struct{}
 | |
| 
 | |
| func (j JSONCodec) ContentType() MIMEType {
 | |
| 	return MIMEType{Type: "application", SubType: "json"}
 | |
| }
 | |
| 
 | |
| func (j JSONCodec) CanEncode(_ *Response) bool {
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| func (j JSONCodec) Encode(resp *Response) ([]byte, error) {
 | |
| 	json := jsoniter.ConfigCompatibleWithStandardLibrary
 | |
| 	return json.Marshal(resp)
 | |
| }
 | |
| 
 | |
| // marshalSeriesJSON writes something like the following:
 | |
| //
 | |
| //	{
 | |
| //	   "metric" : {
 | |
| //	      "__name__" : "up",
 | |
| //	      "job" : "prometheus",
 | |
| //	      "instance" : "localhost:9090"
 | |
| //	   },
 | |
| //	   "values": [
 | |
| //	      [ 1435781451.781, "1" ],
 | |
| //	      < more values>
 | |
| //	   ],
 | |
| //	   "histograms": [
 | |
| //	      [ 1435781451.781, { < histogram, see jsonutil.MarshalHistogram > } ],
 | |
| //	      < more histograms >
 | |
| //	   ],
 | |
| //	},
 | |
| func unsafeMarshalSeriesJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
 | |
| 	s := *((*promql.Series)(ptr))
 | |
| 	marshalSeriesJSON(s, stream)
 | |
| }
 | |
| 
 | |
| func marshalSeriesJSON(s promql.Series, stream *jsoniter.Stream) {
 | |
| 	stream.WriteObjectStart()
 | |
| 	stream.WriteObjectField(`metric`)
 | |
| 	marshalLabelsJSON(s.Metric, stream)
 | |
| 
 | |
| 	for i, p := range s.Floats {
 | |
| 		stream.WriteMore()
 | |
| 		if i == 0 {
 | |
| 			stream.WriteObjectField(`values`)
 | |
| 			stream.WriteArrayStart()
 | |
| 		}
 | |
| 		marshalFPointJSON(p, stream)
 | |
| 	}
 | |
| 	if len(s.Floats) > 0 {
 | |
| 		stream.WriteArrayEnd()
 | |
| 	}
 | |
| 	for i, p := range s.Histograms {
 | |
| 		stream.WriteMore()
 | |
| 		if i == 0 {
 | |
| 			stream.WriteObjectField(`histograms`)
 | |
| 			stream.WriteArrayStart()
 | |
| 		}
 | |
| 		marshalHPointJSON(p, stream)
 | |
| 	}
 | |
| 	if len(s.Histograms) > 0 {
 | |
| 		stream.WriteArrayEnd()
 | |
| 	}
 | |
| 	stream.WriteObjectEnd()
 | |
| }
 | |
| 
 | |
| // In the Prometheus API we render an empty object as `[]` or similar.
 | |
| func neverEmpty(unsafe.Pointer) bool {
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // marshalSampleJSON writes something like the following for normal value samples:
 | |
| //
 | |
| //	{
 | |
| //	   "metric" : {
 | |
| //	      "__name__" : "up",
 | |
| //	      "job" : "prometheus",
 | |
| //	      "instance" : "localhost:9090"
 | |
| //	   },
 | |
| //	   "value": [ 1435781451.781, "1.234" ]
 | |
| //	},
 | |
| //
 | |
| // For histogram samples, it writes something like this:
 | |
| //
 | |
| //	{
 | |
| //	   "metric" : {
 | |
| //	      "__name__" : "up",
 | |
| //	      "job" : "prometheus",
 | |
| //	      "instance" : "localhost:9090"
 | |
| //	   },
 | |
| //	   "histogram": [ 1435781451.781, { < histogram, see jsonutil.MarshalHistogram > } ]
 | |
| //	},
 | |
| func unsafeMarshalSampleJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
 | |
| 	s := *((*promql.Sample)(ptr))
 | |
| 	marshalSampleJSON(s, stream)
 | |
| }
 | |
| 
 | |
| func marshalSampleJSON(s promql.Sample, stream *jsoniter.Stream) {
 | |
| 	stream.WriteObjectStart()
 | |
| 	stream.WriteObjectField(`metric`)
 | |
| 	marshalLabelsJSON(s.Metric, stream)
 | |
| 	stream.WriteMore()
 | |
| 	if s.H == nil {
 | |
| 		stream.WriteObjectField(`value`)
 | |
| 	} else {
 | |
| 		stream.WriteObjectField(`histogram`)
 | |
| 	}
 | |
| 	stream.WriteArrayStart()
 | |
| 	jsonutil.MarshalTimestamp(s.T, stream)
 | |
| 	stream.WriteMore()
 | |
| 	if s.H == nil {
 | |
| 		jsonutil.MarshalFloat(s.F, stream)
 | |
| 	} else {
 | |
| 		jsonutil.MarshalHistogram(s.H, stream)
 | |
| 	}
 | |
| 	stream.WriteArrayEnd()
 | |
| 	stream.WriteObjectEnd()
 | |
| }
 | |
| 
 | |
| // marshalFPointJSON writes `[ts, "1.234"]`.
 | |
| func unsafeMarshalFPointJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
 | |
| 	p := *((*promql.FPoint)(ptr))
 | |
| 	marshalFPointJSON(p, stream)
 | |
| }
 | |
| 
 | |
| func marshalFPointJSON(p promql.FPoint, stream *jsoniter.Stream) {
 | |
| 	stream.WriteArrayStart()
 | |
| 	jsonutil.MarshalTimestamp(p.T, stream)
 | |
| 	stream.WriteMore()
 | |
| 	jsonutil.MarshalFloat(p.F, stream)
 | |
| 	stream.WriteArrayEnd()
 | |
| }
 | |
| 
 | |
| // marshalHPointJSON writes `[ts, { < histogram, see jsonutil.MarshalHistogram > } ]`.
 | |
| func unsafeMarshalHPointJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
 | |
| 	p := *((*promql.HPoint)(ptr))
 | |
| 	marshalHPointJSON(p, stream)
 | |
| }
 | |
| 
 | |
| func marshalHPointJSON(p promql.HPoint, stream *jsoniter.Stream) {
 | |
| 	stream.WriteArrayStart()
 | |
| 	jsonutil.MarshalTimestamp(p.T, stream)
 | |
| 	stream.WriteMore()
 | |
| 	jsonutil.MarshalHistogram(p.H, stream)
 | |
| 	stream.WriteArrayEnd()
 | |
| }
 | |
| 
 | |
| // marshalExemplarJSON writes.
 | |
| //
 | |
| //	{
 | |
| //	   labels: <labels>,
 | |
| //	   value: "<string>",
 | |
| //	   timestamp: <float>
 | |
| //	}
 | |
| func marshalExemplarJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
 | |
| 	p := *((*exemplar.Exemplar)(ptr))
 | |
| 	stream.WriteObjectStart()
 | |
| 
 | |
| 	// "labels" key.
 | |
| 	stream.WriteObjectField(`labels`)
 | |
| 	marshalLabelsJSON(p.Labels, stream)
 | |
| 
 | |
| 	// "value" key.
 | |
| 	stream.WriteMore()
 | |
| 	stream.WriteObjectField(`value`)
 | |
| 	jsonutil.MarshalFloat(p.Value, stream)
 | |
| 
 | |
| 	// "timestamp" key.
 | |
| 	stream.WriteMore()
 | |
| 	stream.WriteObjectField(`timestamp`)
 | |
| 	jsonutil.MarshalTimestamp(p.Ts, stream)
 | |
| 
 | |
| 	stream.WriteObjectEnd()
 | |
| }
 | |
| 
 | |
| func unsafeMarshalLabelsJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
 | |
| 	labelsPtr := (*labels.Labels)(ptr)
 | |
| 	marshalLabelsJSON(*labelsPtr, stream)
 | |
| }
 | |
| 
 | |
| func marshalLabelsJSON(lbls labels.Labels, stream *jsoniter.Stream) {
 | |
| 	stream.WriteObjectStart()
 | |
| 	i := 0
 | |
| 	lbls.Range(func(v labels.Label) {
 | |
| 		if i != 0 {
 | |
| 			stream.WriteMore()
 | |
| 		}
 | |
| 		i++
 | |
| 		stream.WriteString(v.Name)
 | |
| 		stream.WriteRaw(`:`)
 | |
| 		stream.WriteString(v.Value)
 | |
| 	})
 | |
| 	stream.WriteObjectEnd()
 | |
| }
 | |
| 
 | |
| func labelsIsEmpty(ptr unsafe.Pointer) bool {
 | |
| 	labelsPtr := (*labels.Labels)(ptr)
 | |
| 	return labelsPtr.IsEmpty()
 | |
| }
 | |
| 
 | |
| // Marshal a Vector as `[sample,sample,...]` - empty Vector is `[]`.
 | |
| func unsafeMarshalVectorJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
 | |
| 	v := *((*promql.Vector)(ptr))
 | |
| 	stream.WriteArrayStart()
 | |
| 	for i, s := range v {
 | |
| 		marshalSampleJSON(s, stream)
 | |
| 		if i != len(v)-1 {
 | |
| 			stream.WriteMore()
 | |
| 		}
 | |
| 	}
 | |
| 	stream.WriteArrayEnd()
 | |
| }
 | |
| 
 | |
| // Marshal a Matrix as `[series,series,...]` - empty Matrix is `[]`.
 | |
| func unsafeMarshalMatrixJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
 | |
| 	m := *((*promql.Matrix)(ptr))
 | |
| 	stream.WriteArrayStart()
 | |
| 	for i, s := range m {
 | |
| 		marshalSeriesJSON(s, stream)
 | |
| 		if i != len(m)-1 {
 | |
| 			stream.WriteMore()
 | |
| 		}
 | |
| 	}
 | |
| 	stream.WriteArrayEnd()
 | |
| }
 |