mirror of https://github.com/prometheus/prometheus
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
264 lines
7.1 KiB
264 lines
7.1 KiB
// 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() |
|
}
|
|
|