Parse created timestamps from Prometheus Protobuf (#12973)
Signed-off-by: Arthur Silva Sens <arthur.sens@coralogix.com>
This commit is contained in:
parent
4d50e5d122
commit
ef8e6ae780
|
@ -16,6 +16,8 @@ package textparse
|
||||||
import (
|
import (
|
||||||
"mime"
|
"mime"
|
||||||
|
|
||||||
|
"github.com/gogo/protobuf/types"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/model/exemplar"
|
"github.com/prometheus/prometheus/model/exemplar"
|
||||||
"github.com/prometheus/prometheus/model/histogram"
|
"github.com/prometheus/prometheus/model/histogram"
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
|
@ -64,6 +66,11 @@ type Parser interface {
|
||||||
// retrieved (including the case where no exemplars exist at all).
|
// retrieved (including the case where no exemplars exist at all).
|
||||||
Exemplar(l *exemplar.Exemplar) bool
|
Exemplar(l *exemplar.Exemplar) bool
|
||||||
|
|
||||||
|
// CreatedTimestamp writes the created timestamp of the current sample
|
||||||
|
// into the passed timestamp. It returns false if no created timestamp
|
||||||
|
// exists or if the metric type does not support created timestamps.
|
||||||
|
CreatedTimestamp(ct *types.Timestamp) bool
|
||||||
|
|
||||||
// Next advances the parser to the next sample. It returns false if no
|
// Next advances the parser to the next sample. It returns false if no
|
||||||
// more samples were read or an error occurred.
|
// more samples were read or an error occurred.
|
||||||
Next() (Entry, error)
|
Next() (Entry, error)
|
||||||
|
|
|
@ -24,6 +24,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/gogo/protobuf/types"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/model/exemplar"
|
"github.com/prometheus/prometheus/model/exemplar"
|
||||||
"github.com/prometheus/prometheus/model/histogram"
|
"github.com/prometheus/prometheus/model/histogram"
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
|
@ -211,6 +213,11 @@ func (p *OpenMetricsParser) Exemplar(e *exemplar.Exemplar) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreatedTimestamp returns false because OpenMetricsParser does not support created timestamps (yet).
|
||||||
|
func (p *OpenMetricsParser) CreatedTimestamp(_ *types.Timestamp) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// nextToken returns the next token from the openMetricsLexer.
|
// nextToken returns the next token from the openMetricsLexer.
|
||||||
func (p *OpenMetricsParser) nextToken() token {
|
func (p *OpenMetricsParser) nextToken() token {
|
||||||
tok := p.l.Lex()
|
tok := p.l.Lex()
|
||||||
|
|
|
@ -26,6 +26,8 @@ import (
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gogo/protobuf/types"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/model/exemplar"
|
"github.com/prometheus/prometheus/model/exemplar"
|
||||||
"github.com/prometheus/prometheus/model/histogram"
|
"github.com/prometheus/prometheus/model/histogram"
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
|
@ -245,6 +247,11 @@ func (p *PromParser) Exemplar(*exemplar.Exemplar) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreatedTimestamp returns false because PromParser does not support created timestamps.
|
||||||
|
func (p *PromParser) CreatedTimestamp(_ *types.Timestamp) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// nextToken returns the next token from the promlexer. It skips over tabs
|
// nextToken returns the next token from the promlexer. It skips over tabs
|
||||||
// and spaces.
|
// and spaces.
|
||||||
func (p *PromParser) nextToken() token {
|
func (p *PromParser) nextToken() token {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
|
"github.com/gogo/protobuf/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
|
|
||||||
|
@ -347,6 +348,24 @@ func (p *ProtobufParser) Exemplar(ex *exemplar.Exemplar) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ProtobufParser) CreatedTimestamp(ct *types.Timestamp) bool {
|
||||||
|
var foundCT *types.Timestamp
|
||||||
|
switch p.mf.GetType() {
|
||||||
|
case dto.MetricType_COUNTER:
|
||||||
|
foundCT = p.mf.GetMetric()[p.metricPos].GetCounter().GetCreatedTimestamp()
|
||||||
|
case dto.MetricType_SUMMARY:
|
||||||
|
foundCT = p.mf.GetMetric()[p.metricPos].GetSummary().GetCreatedTimestamp()
|
||||||
|
case dto.MetricType_HISTOGRAM, dto.MetricType_GAUGE_HISTOGRAM:
|
||||||
|
foundCT = p.mf.GetMetric()[p.metricPos].GetHistogram().GetCreatedTimestamp()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if foundCT == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*ct = *foundCT
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Next advances the parser to the next "sample" (emulating the behavior of a
|
// Next advances the parser to the next "sample" (emulating the behavior of a
|
||||||
// text format parser). It returns (EntryInvalid, io.EOF) if no samples were
|
// text format parser). It returns (EntryInvalid, io.EOF) if no samples were
|
||||||
// read.
|
// read.
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
|
"github.com/gogo/protobuf/types"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/model/exemplar"
|
"github.com/prometheus/prometheus/model/exemplar"
|
||||||
|
@ -530,6 +531,69 @@ metric: <
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
|
|
||||||
|
`,
|
||||||
|
`name: "test_counter_with_createdtimestamp"
|
||||||
|
help: "A counter with a created timestamp."
|
||||||
|
type: COUNTER
|
||||||
|
metric: <
|
||||||
|
counter: <
|
||||||
|
value: 42
|
||||||
|
created_timestamp: <
|
||||||
|
seconds: 1
|
||||||
|
nanos: 1
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
|
||||||
|
`,
|
||||||
|
`name: "test_summary_with_createdtimestamp"
|
||||||
|
help: "A summary with a created timestamp."
|
||||||
|
type: SUMMARY
|
||||||
|
metric: <
|
||||||
|
summary: <
|
||||||
|
sample_count: 42
|
||||||
|
sample_sum: 1.234
|
||||||
|
created_timestamp: <
|
||||||
|
seconds: 1
|
||||||
|
nanos: 1
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
|
||||||
|
`,
|
||||||
|
`name: "test_histogram_with_createdtimestamp"
|
||||||
|
help: "A histogram with a created timestamp."
|
||||||
|
type: HISTOGRAM
|
||||||
|
metric: <
|
||||||
|
histogram: <
|
||||||
|
created_timestamp: <
|
||||||
|
seconds: 1
|
||||||
|
nanos: 1
|
||||||
|
>
|
||||||
|
positive_span: <
|
||||||
|
offset: 0
|
||||||
|
length: 0
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
|
||||||
|
`,
|
||||||
|
`name: "test_gaugehistogram_with_createdtimestamp"
|
||||||
|
help: "A gauge histogram with a created timestamp."
|
||||||
|
type: GAUGE_HISTOGRAM
|
||||||
|
metric: <
|
||||||
|
histogram: <
|
||||||
|
created_timestamp: <
|
||||||
|
seconds: 1
|
||||||
|
nanos: 1
|
||||||
|
>
|
||||||
|
positive_span: <
|
||||||
|
offset: 0
|
||||||
|
length: 0
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,6 +630,7 @@ func TestProtobufParse(t *testing.T) {
|
||||||
shs *histogram.Histogram
|
shs *histogram.Histogram
|
||||||
fhs *histogram.FloatHistogram
|
fhs *histogram.FloatHistogram
|
||||||
e []exemplar.Exemplar
|
e []exemplar.Exemplar
|
||||||
|
ct *types.Timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
inputBuf := createTestProtoBuf(t)
|
inputBuf := createTestProtoBuf(t)
|
||||||
|
@ -997,6 +1062,86 @@ func TestProtobufParse(t *testing.T) {
|
||||||
"__name__", "empty_histogram",
|
"__name__", "empty_histogram",
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
m: "test_counter_with_createdtimestamp",
|
||||||
|
help: "A counter with a created timestamp.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_counter_with_createdtimestamp",
|
||||||
|
typ: MetricTypeCounter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_counter_with_createdtimestamp",
|
||||||
|
v: 42,
|
||||||
|
ct: &types.Timestamp{Seconds: 1, Nanos: 1},
|
||||||
|
lset: labels.FromStrings(
|
||||||
|
"__name__", "test_counter_with_createdtimestamp",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_summary_with_createdtimestamp",
|
||||||
|
help: "A summary with a created timestamp.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_summary_with_createdtimestamp",
|
||||||
|
typ: MetricTypeSummary,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_summary_with_createdtimestamp_count",
|
||||||
|
v: 42,
|
||||||
|
ct: &types.Timestamp{Seconds: 1, Nanos: 1},
|
||||||
|
lset: labels.FromStrings(
|
||||||
|
"__name__", "test_summary_with_createdtimestamp_count",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_summary_with_createdtimestamp_sum",
|
||||||
|
v: 1.234,
|
||||||
|
ct: &types.Timestamp{Seconds: 1, Nanos: 1},
|
||||||
|
lset: labels.FromStrings(
|
||||||
|
"__name__", "test_summary_with_createdtimestamp_sum",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_histogram_with_createdtimestamp",
|
||||||
|
help: "A histogram with a created timestamp.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_histogram_with_createdtimestamp",
|
||||||
|
typ: MetricTypeHistogram,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_histogram_with_createdtimestamp",
|
||||||
|
ct: &types.Timestamp{Seconds: 1, Nanos: 1},
|
||||||
|
shs: &histogram.Histogram{
|
||||||
|
CounterResetHint: histogram.UnknownCounterReset,
|
||||||
|
PositiveSpans: []histogram.Span{},
|
||||||
|
NegativeSpans: []histogram.Span{},
|
||||||
|
},
|
||||||
|
lset: labels.FromStrings(
|
||||||
|
"__name__", "test_histogram_with_createdtimestamp",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_gaugehistogram_with_createdtimestamp",
|
||||||
|
help: "A gauge histogram with a created timestamp.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_gaugehistogram_with_createdtimestamp",
|
||||||
|
typ: MetricTypeGaugeHistogram,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m: "test_gaugehistogram_with_createdtimestamp",
|
||||||
|
ct: &types.Timestamp{Seconds: 1, Nanos: 1},
|
||||||
|
shs: &histogram.Histogram{
|
||||||
|
CounterResetHint: histogram.GaugeType,
|
||||||
|
PositiveSpans: []histogram.Span{},
|
||||||
|
NegativeSpans: []histogram.Span{},
|
||||||
|
},
|
||||||
|
lset: labels.FromStrings(
|
||||||
|
"__name__", "test_gaugehistogram_with_createdtimestamp",
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1739,6 +1884,86 @@ func TestProtobufParse(t *testing.T) {
|
||||||
"__name__", "empty_histogram",
|
"__name__", "empty_histogram",
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{ // 81
|
||||||
|
m: "test_counter_with_createdtimestamp",
|
||||||
|
help: "A counter with a created timestamp.",
|
||||||
|
},
|
||||||
|
{ // 82
|
||||||
|
m: "test_counter_with_createdtimestamp",
|
||||||
|
typ: MetricTypeCounter,
|
||||||
|
},
|
||||||
|
{ // 83
|
||||||
|
m: "test_counter_with_createdtimestamp",
|
||||||
|
v: 42,
|
||||||
|
ct: &types.Timestamp{Seconds: 1, Nanos: 1},
|
||||||
|
lset: labels.FromStrings(
|
||||||
|
"__name__", "test_counter_with_createdtimestamp",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ // 84
|
||||||
|
m: "test_summary_with_createdtimestamp",
|
||||||
|
help: "A summary with a created timestamp.",
|
||||||
|
},
|
||||||
|
{ // 85
|
||||||
|
m: "test_summary_with_createdtimestamp",
|
||||||
|
typ: MetricTypeSummary,
|
||||||
|
},
|
||||||
|
{ // 86
|
||||||
|
m: "test_summary_with_createdtimestamp_count",
|
||||||
|
v: 42,
|
||||||
|
ct: &types.Timestamp{Seconds: 1, Nanos: 1},
|
||||||
|
lset: labels.FromStrings(
|
||||||
|
"__name__", "test_summary_with_createdtimestamp_count",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ // 87
|
||||||
|
m: "test_summary_with_createdtimestamp_sum",
|
||||||
|
v: 1.234,
|
||||||
|
ct: &types.Timestamp{Seconds: 1, Nanos: 1},
|
||||||
|
lset: labels.FromStrings(
|
||||||
|
"__name__", "test_summary_with_createdtimestamp_sum",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ // 88
|
||||||
|
m: "test_histogram_with_createdtimestamp",
|
||||||
|
help: "A histogram with a created timestamp.",
|
||||||
|
},
|
||||||
|
{ // 89
|
||||||
|
m: "test_histogram_with_createdtimestamp",
|
||||||
|
typ: MetricTypeHistogram,
|
||||||
|
},
|
||||||
|
{ // 90
|
||||||
|
m: "test_histogram_with_createdtimestamp",
|
||||||
|
ct: &types.Timestamp{Seconds: 1, Nanos: 1},
|
||||||
|
shs: &histogram.Histogram{
|
||||||
|
CounterResetHint: histogram.UnknownCounterReset,
|
||||||
|
PositiveSpans: []histogram.Span{},
|
||||||
|
NegativeSpans: []histogram.Span{},
|
||||||
|
},
|
||||||
|
lset: labels.FromStrings(
|
||||||
|
"__name__", "test_histogram_with_createdtimestamp",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ // 91
|
||||||
|
m: "test_gaugehistogram_with_createdtimestamp",
|
||||||
|
help: "A gauge histogram with a created timestamp.",
|
||||||
|
},
|
||||||
|
{ // 92
|
||||||
|
m: "test_gaugehistogram_with_createdtimestamp",
|
||||||
|
typ: MetricTypeGaugeHistogram,
|
||||||
|
},
|
||||||
|
{ // 93
|
||||||
|
m: "test_gaugehistogram_with_createdtimestamp",
|
||||||
|
ct: &types.Timestamp{Seconds: 1, Nanos: 1},
|
||||||
|
shs: &histogram.Histogram{
|
||||||
|
CounterResetHint: histogram.GaugeType,
|
||||||
|
PositiveSpans: []histogram.Span{},
|
||||||
|
NegativeSpans: []histogram.Span{},
|
||||||
|
},
|
||||||
|
lset: labels.FromStrings(
|
||||||
|
"__name__", "test_gaugehistogram_with_createdtimestamp",
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1764,8 +1989,10 @@ func TestProtobufParse(t *testing.T) {
|
||||||
m, ts, v := p.Series()
|
m, ts, v := p.Series()
|
||||||
|
|
||||||
var e exemplar.Exemplar
|
var e exemplar.Exemplar
|
||||||
|
var ct types.Timestamp
|
||||||
p.Metric(&res)
|
p.Metric(&res)
|
||||||
found := p.Exemplar(&e)
|
eFound := p.Exemplar(&e)
|
||||||
|
ctFound := p.CreatedTimestamp(&ct)
|
||||||
require.Equal(t, exp[i].m, string(m), "i: %d", i)
|
require.Equal(t, exp[i].m, string(m), "i: %d", i)
|
||||||
if ts != nil {
|
if ts != nil {
|
||||||
require.Equal(t, exp[i].t, *ts, "i: %d", i)
|
require.Equal(t, exp[i].t, *ts, "i: %d", i)
|
||||||
|
@ -1775,12 +2002,18 @@ func TestProtobufParse(t *testing.T) {
|
||||||
require.Equal(t, exp[i].v, v, "i: %d", i)
|
require.Equal(t, exp[i].v, v, "i: %d", i)
|
||||||
require.Equal(t, exp[i].lset, res, "i: %d", i)
|
require.Equal(t, exp[i].lset, res, "i: %d", i)
|
||||||
if len(exp[i].e) == 0 {
|
if len(exp[i].e) == 0 {
|
||||||
require.Equal(t, false, found, "i: %d", i)
|
require.Equal(t, false, eFound, "i: %d", i)
|
||||||
} else {
|
} else {
|
||||||
require.Equal(t, true, found, "i: %d", i)
|
require.Equal(t, true, eFound, "i: %d", i)
|
||||||
require.Equal(t, exp[i].e[0], e, "i: %d", i)
|
require.Equal(t, exp[i].e[0], e, "i: %d", i)
|
||||||
require.False(t, p.Exemplar(&e), "too many exemplars returned, i: %d", i)
|
require.False(t, p.Exemplar(&e), "too many exemplars returned, i: %d", i)
|
||||||
}
|
}
|
||||||
|
if exp[i].ct != nil {
|
||||||
|
require.Equal(t, true, ctFound, "i: %d", i)
|
||||||
|
require.Equal(t, exp[i].ct.String(), ct.String(), "i: %d", i)
|
||||||
|
} else {
|
||||||
|
require.Equal(t, false, ctFound, "i: %d", i)
|
||||||
|
}
|
||||||
|
|
||||||
case EntryHistogram:
|
case EntryHistogram:
|
||||||
m, ts, shs, fhs := p.Histogram()
|
m, ts, shs, fhs := p.Histogram()
|
||||||
|
|
Loading…
Reference in New Issue