prw2.0: Added support for "custom" layouts for native histogram proto (#13558)

* prw2.0: Added support for "custom" layouts for native histogram.

Result of the discussions:
* https://github.com/prometheus/prometheus/issues/13475#issuecomment-1931496924
* https://cloud-native.slack.com/archives/C02KR205UMU/p1707301006347199

Signed-off-by: bwplotka <bwplotka@gmail.com>

* prw2.0: Added support for "custom" layouts for native histogram.

Result of the discussions:
* https://github.com/prometheus/prometheus/issues/13475#issuecomment-1931496924
* https://cloud-native.slack.com/archives/C02KR205UMU/p1707301006347199

Signed-off-by: bwplotka <bwplotka@gmail.com>

# Conflicts:
#	prompb/write/v2/types.pb.go

* Update prompb/write/v2/types.proto

Co-authored-by: George Krajcsovits <krajorama@users.noreply.github.com>
Signed-off-by: Bartlomiej Plotka <bwplotka@gmail.com>

* Addressed comments, fixed test.

Signed-off-by: bwplotka <bwplotka@gmail.com>

---------

Signed-off-by: bwplotka <bwplotka@gmail.com>
Signed-off-by: Bartlomiej Plotka <bwplotka@gmail.com>
Co-authored-by: George Krajcsovits <krajorama@users.noreply.github.com>
This commit is contained in:
Bartlomiej Plotka 2024-03-14 14:47:25 +01:00 committed by GitHub
parent ae414a3e6b
commit 0eae349b78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 264 additions and 110 deletions

View file

@ -113,7 +113,7 @@ func (m *TimeSeries) OptimizedMarshalToSizedBuffer(dAtA []byte) (int, error) {
i = encodeVarintTypes(dAtA, i, uint64(size)) i = encodeVarintTypes(dAtA, i, uint64(size))
} }
i-- i--
dAtA[i] = 0x22 dAtA[i] = 0x1a
} }
} }
if len(m.Exemplars) > 0 { if len(m.Exemplars) > 0 {
@ -127,7 +127,7 @@ func (m *TimeSeries) OptimizedMarshalToSizedBuffer(dAtA []byte) (int, error) {
i = encodeVarintTypes(dAtA, i, uint64(size)) i = encodeVarintTypes(dAtA, i, uint64(size))
} }
i-- i--
dAtA[i] = 0x1a dAtA[i] = 0x22
} }
} }
if len(m.Samples) > 0 { if len(m.Samples) > 0 {

View file

@ -174,7 +174,7 @@ type TimeSeries struct {
// WriteRequests with the same labels e.g. for different exemplars, metadata // WriteRequests with the same labels e.g. for different exemplars, metadata
// or created timestamp. // or created timestamp.
LabelsRefs []uint32 `protobuf:"varint,1,rep,packed,name=labels_refs,json=labelsRefs,proto3" json:"labels_refs,omitempty"` LabelsRefs []uint32 `protobuf:"varint,1,rep,packed,name=labels_refs,json=labelsRefs,proto3" json:"labels_refs,omitempty"`
// samples contain zero or more samples for a given timeseries. For a typical // samples contain zero or more samples for a given timeseries. For typical
// clients, in healthy cases, there will be only one sample, for ~real // clients, in healthy cases, there will be only one sample, for ~real
// time metric streaming. Samples can, in theory, co-exist with histogram samples // time metric streaming. Samples can, in theory, co-exist with histogram samples
// (histograms field), although it should be extremely rare in practice (e.g. // (histograms field), although it should be extremely rare in practice (e.g.
@ -184,7 +184,7 @@ type TimeSeries struct {
// Samples are sorted by timestamp (older first). // Samples are sorted by timestamp (older first).
Samples []Sample `protobuf:"bytes,2,rep,name=samples,proto3" json:"samples"` Samples []Sample `protobuf:"bytes,2,rep,name=samples,proto3" json:"samples"`
// histograms contain zero or more histogram samples for a given timeseries. // histograms contain zero or more histogram samples for a given timeseries.
// For a typical clients, in healthy cases, there will be only one sample, for ~real // For typical clients, in healthy cases, there will be only one sample, for ~real
// time metric streaming. histograms can co-exist with samples (see samples // time metric streaming. histograms can co-exist with samples (see samples
// for details). // for details).
// //
@ -508,12 +508,16 @@ type Histogram struct {
Count isHistogram_Count `protobuf_oneof:"count"` Count isHistogram_Count `protobuf_oneof:"count"`
Sum float64 `protobuf:"fixed64,3,opt,name=sum,proto3" json:"sum,omitempty"` Sum float64 `protobuf:"fixed64,3,opt,name=sum,proto3" json:"sum,omitempty"`
// The schema defines the bucket schema. Currently, valid numbers // The schema defines the bucket schema. Currently, valid numbers
// are -4 <= n <= 8. They are all for base-2 bucket schemas, where 1 // are -53 and numbers in range of -4 <= n <= 8. More valid numbers might be
// added in future for new bucketing layouts.
//
// The schema equal to -53 means custom buckets. See
// custom_values field description for more details.
//
// Values between -4 and 8 represent base-2 bucket schema, where 1
// is a bucket boundary in each case, and then each power of two is // is a bucket boundary in each case, and then each power of two is
// divided into 2^n logarithmic buckets. Or in other words, each // divided into 2^n (n is schema value) logarithmic buckets. Or in other words,
// bucket boundary is the previous boundary times 2^(2^-n). In the // each bucket boundary is the previous boundary times 2^(2^-n).
// future, more bucket schemas may be added using numbers < -4 or >
// 8.
Schema int32 `protobuf:"zigzag32,4,opt,name=schema,proto3" json:"schema,omitempty"` Schema int32 `protobuf:"zigzag32,4,opt,name=schema,proto3" json:"schema,omitempty"`
ZeroThreshold float64 `protobuf:"fixed64,5,opt,name=zero_threshold,json=zeroThreshold,proto3" json:"zero_threshold,omitempty"` ZeroThreshold float64 `protobuf:"fixed64,5,opt,name=zero_threshold,json=zeroThreshold,proto3" json:"zero_threshold,omitempty"`
// Types that are valid to be assigned to ZeroCount: // Types that are valid to be assigned to ZeroCount:
@ -524,25 +528,58 @@ type Histogram struct {
// Negative Buckets. // Negative Buckets.
NegativeSpans []BucketSpan `protobuf:"bytes,8,rep,name=negative_spans,json=negativeSpans,proto3" json:"negative_spans"` NegativeSpans []BucketSpan `protobuf:"bytes,8,rep,name=negative_spans,json=negativeSpans,proto3" json:"negative_spans"`
// Use either "negative_deltas" or "negative_counts", the former for // Use either "negative_deltas" or "negative_counts", the former for
// regular histograms with integer counts, the latter for float // regular histograms with integer counts, the latter for
// histograms. // float histograms.
NegativeDeltas []int64 `protobuf:"zigzag64,9,rep,packed,name=negative_deltas,json=negativeDeltas,proto3" json:"negative_deltas,omitempty"` NegativeDeltas []int64 `protobuf:"zigzag64,9,rep,packed,name=negative_deltas,json=negativeDeltas,proto3" json:"negative_deltas,omitempty"`
NegativeCounts []float64 `protobuf:"fixed64,10,rep,packed,name=negative_counts,json=negativeCounts,proto3" json:"negative_counts,omitempty"` NegativeCounts []float64 `protobuf:"fixed64,10,rep,packed,name=negative_counts,json=negativeCounts,proto3" json:"negative_counts,omitempty"`
// Positive Buckets. // Positive Buckets.
//
// In case of custom buckets (-53 schema value) the positive buckets are interpreted as follows:
// * The span offset+length points to an the index of the custom_values array
// or +Inf if pointing to the len of the array.
// * The counts and deltas have the same meaning as for exponential histograms.
PositiveSpans []BucketSpan `protobuf:"bytes,11,rep,name=positive_spans,json=positiveSpans,proto3" json:"positive_spans"` PositiveSpans []BucketSpan `protobuf:"bytes,11,rep,name=positive_spans,json=positiveSpans,proto3" json:"positive_spans"`
// Use either "positive_deltas" or "positive_counts", the former for // Use either "positive_deltas" or "positive_counts", the former for
// regular histograms with integer counts, the latter for float // regular histograms with integer counts, the latter for
// histograms. // float histograms.
PositiveDeltas []int64 `protobuf:"zigzag64,12,rep,packed,name=positive_deltas,json=positiveDeltas,proto3" json:"positive_deltas,omitempty"` PositiveDeltas []int64 `protobuf:"zigzag64,12,rep,packed,name=positive_deltas,json=positiveDeltas,proto3" json:"positive_deltas,omitempty"`
PositiveCounts []float64 `protobuf:"fixed64,13,rep,packed,name=positive_counts,json=positiveCounts,proto3" json:"positive_counts,omitempty"` PositiveCounts []float64 `protobuf:"fixed64,13,rep,packed,name=positive_counts,json=positiveCounts,proto3" json:"positive_counts,omitempty"`
ResetHint Histogram_ResetHint `protobuf:"varint,14,opt,name=reset_hint,json=resetHint,proto3,enum=write.v2.Histogram_ResetHint" json:"reset_hint,omitempty"` ResetHint Histogram_ResetHint `protobuf:"varint,14,opt,name=reset_hint,json=resetHint,proto3,enum=write.v2.Histogram_ResetHint" json:"reset_hint,omitempty"`
// timestamp represents timestamp of the sample in ms. // timestamp represents timestamp of the sample in ms.
// For Go, see github.com/prometheus/prometheus/model/timestamp/timestamp.go // For Go, see github.com/prometheus/prometheus/model/timestamp/timestamp.go
// for conversion from/to time.Time to Prometheus timestamp. // for conversion from/to time.Time to Prometheus timestamp.
Timestamp int64 `protobuf:"varint,15,opt,name=timestamp,proto3" json:"timestamp,omitempty"` Timestamp int64 `protobuf:"varint,15,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` // custom_values is an additional field used by non-exponential bucketing layouts.
XXX_unrecognized []byte `json:"-"` //
XXX_sizecache int32 `json:"-"` // For custom buckets (-53 schema value) custom_values specify monotonically
// increasing upper inclusive boundaries for the bucket counts with arbitrary
// widths for this histogram. In other words, custom_values represents custom,
// explicit bucketing that could have been converted from the classic histograms.
//
// Those bounds are then referenced by spans in positive_spans with corresponding positive
// counts of deltas (refer to positive_spans for more details). This way we can
// have encode sparse histograms with custom bucketing (many buckets are often
// not used).
//
// Note that for custom bounds, even negative observations are placed in the positive
// counts to simplify the implementation and avoid ambiguity of where to place
// an underflow bucket, e.g. (-2, 1]. Therefore negative buckets and
// the zero bucket are unused, if the schema indicates custom bucketing.
//
// For each upper boundary the previous boundary represent the lower exclusive
// boundary for that bucket. The first element is the upper inclusive boundary
// for the first bucket, which implicitly has a lower inclusive bound of -Inf.
// This is similar to "le" label semantics on classic histograms. You may add a
// bucket with an upper bound of 0 to make sure that you really have no negative
// observations, but in practice, native histogram rendering will show both with
// or without first upper boundary 0 and no negative counts as the same case.
//
// The last element is not only the upper inclusive bound of the last regular
// bucket, but implicitly the lower exclusive bound of the +Inf bucket.
CustomValues []float64 `protobuf:"fixed64,16,rep,packed,name=custom_values,json=customValues,proto3" json:"custom_values,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *Histogram) Reset() { *m = Histogram{} } func (m *Histogram) Reset() { *m = Histogram{} }
@ -725,6 +762,13 @@ func (m *Histogram) GetTimestamp() int64 {
return 0 return 0
} }
func (m *Histogram) GetCustomValues() []float64 {
if m != nil {
return m.CustomValues
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package. // XXX_OneofWrappers is for the internal use of the proto package.
func (*Histogram) XXX_OneofWrappers() []interface{} { func (*Histogram) XXX_OneofWrappers() []interface{} {
return []interface{}{ return []interface{}{
@ -810,62 +854,64 @@ func init() {
func init() { proto.RegisterFile("write/v2/types.proto", fileDescriptor_4919b8b88a093366) } func init() { proto.RegisterFile("write/v2/types.proto", fileDescriptor_4919b8b88a093366) }
var fileDescriptor_4919b8b88a093366 = []byte{ var fileDescriptor_4919b8b88a093366 = []byte{
// 875 bytes of a gzipped FileDescriptorProto // 897 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0x5b, 0x6f, 0x1b, 0x45, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0xdd, 0x6e, 0x1b, 0x45,
0x14, 0xce, 0x78, 0x7d, 0x3d, 0x89, 0xdd, 0xf5, 0xd4, 0x69, 0xb7, 0x81, 0xa6, 0xc6, 0x12, 0x60, 0x14, 0xce, 0x78, 0x1d, 0xff, 0x9c, 0xd8, 0xee, 0x7a, 0xea, 0xb4, 0xdb, 0x40, 0x53, 0x63, 0x04,
0x81, 0xe4, 0x80, 0x41, 0x48, 0xa0, 0xbc, 0xd8, 0xe9, 0x26, 0xf6, 0x83, 0x9d, 0x6a, 0x76, 0x23, 0x58, 0x20, 0x39, 0x60, 0x10, 0x12, 0x28, 0x37, 0x76, 0xba, 0x89, 0x7d, 0x61, 0xa7, 0x1a, 0x6f,
0x14, 0x5e, 0x56, 0x1b, 0x7b, 0x6c, 0xaf, 0xd8, 0x1b, 0x3b, 0x63, 0x43, 0xf8, 0x5f, 0xfc, 0x87, 0x40, 0xe1, 0x66, 0xb5, 0xb1, 0xc7, 0xf6, 0x8a, 0xfd, 0x63, 0x67, 0x6c, 0x08, 0x8f, 0xc2, 0x7b,
0x3e, 0x22, 0xf1, 0x0c, 0x42, 0xf9, 0x0f, 0xbc, 0xa3, 0x99, 0xbd, 0xc6, 0x55, 0xd5, 0xb7, 0x39, 0xf0, 0x0e, 0xbd, 0x44, 0xe2, 0x1a, 0x84, 0xf2, 0x24, 0x68, 0x66, 0x7f, 0xed, 0xaa, 0xca, 0xdd,
0xdf, 0x65, 0xce, 0xb7, 0x27, 0x67, 0x62, 0xe8, 0xfc, 0x1a, 0x39, 0x9c, 0x9e, 0xed, 0x86, 0x67, 0xcc, 0xf7, 0x33, 0xe7, 0xdb, 0x93, 0x73, 0x62, 0x68, 0xfd, 0x1a, 0xda, 0x9c, 0x9e, 0x6d, 0xfb,
0xfc, 0x3e, 0xa4, 0x6c, 0x10, 0x46, 0x01, 0x0f, 0x70, 0x5d, 0xa2, 0x83, 0xdd, 0xf0, 0xa4, 0xb3, 0x67, 0xfc, 0x3e, 0xa0, 0xac, 0x17, 0x84, 0x3e, 0xf7, 0x71, 0x45, 0xa2, 0xbd, 0x6d, 0xff, 0xa4,
0x0e, 0xd6, 0x81, 0x04, 0xcf, 0xc4, 0x29, 0xe6, 0x7b, 0x4b, 0x38, 0xfa, 0x51, 0x28, 0x08, 0xfd, 0xb5, 0xf2, 0x57, 0xbe, 0x04, 0xcf, 0xc4, 0x29, 0xe2, 0x3b, 0x0b, 0xa8, 0xfd, 0x28, 0x14, 0x84,
0x65, 0x4b, 0x19, 0xc7, 0x1a, 0xd4, 0xd8, 0xbd, 0x77, 0x17, 0xb8, 0x4c, 0x43, 0x5d, 0xa5, 0xdf, 0xfe, 0xb2, 0xa1, 0x8c, 0x63, 0x0d, 0xca, 0xec, 0xde, 0xbd, 0xf3, 0x1d, 0xa6, 0xa1, 0xb6, 0xd2,
0x20, 0x69, 0x89, 0x7f, 0x00, 0xe0, 0x8e, 0x47, 0x19, 0x8d, 0x1c, 0xca, 0xb4, 0x52, 0x57, 0xe9, 0xad, 0x92, 0xe4, 0x8a, 0xbf, 0x07, 0xe0, 0xb6, 0x4b, 0x19, 0x0d, 0x6d, 0xca, 0xb4, 0x42, 0x5b,
0x1f, 0x0e, 0x3b, 0x83, 0xf4, 0xfa, 0x81, 0xe9, 0x78, 0xd4, 0x90, 0xdc, 0xb8, 0xfc, 0xf6, 0x9f, 0xe9, 0x1e, 0xf5, 0x5b, 0xbd, 0xe4, 0xf9, 0x9e, 0x61, 0xbb, 0x74, 0x26, 0xb9, 0x61, 0xf1, 0xed,
0x57, 0x07, 0xa4, 0xa0, 0xee, 0xfd, 0x51, 0x02, 0xc8, 0x05, 0xf8, 0x15, 0x1c, 0xba, 0xf6, 0x1d, 0xbf, 0xaf, 0x0e, 0x48, 0x4e, 0xdd, 0xf9, 0xb3, 0x00, 0x90, 0x09, 0xf0, 0x2b, 0x38, 0x72, 0xac,
0x75, 0x99, 0x15, 0xd1, 0x55, 0xdc, 0xa8, 0x49, 0x20, 0x86, 0x08, 0x5d, 0x31, 0xfc, 0x15, 0xd4, 0x3b, 0xea, 0x30, 0x33, 0xa4, 0xcb, 0xa8, 0x50, 0x9d, 0x40, 0x04, 0x11, 0xba, 0x64, 0xf8, 0x4b,
0x98, 0xed, 0x85, 0x6e, 0xd6, 0x48, 0xcd, 0x1b, 0x19, 0x92, 0x48, 0x9a, 0xa4, 0x32, 0xfc, 0x3d, 0x28, 0x33, 0xcb, 0x0d, 0x9c, 0xb4, 0x90, 0x9a, 0x15, 0x9a, 0x49, 0x22, 0x2e, 0x92, 0xc8, 0xf0,
0xc0, 0xc6, 0x61, 0x3c, 0x58, 0x47, 0xb6, 0xc7, 0x34, 0x45, 0x9a, 0x9e, 0xe6, 0xa6, 0x49, 0xca, 0x77, 0x00, 0x6b, 0x9b, 0x71, 0x7f, 0x15, 0x5a, 0x2e, 0xd3, 0x14, 0x69, 0x7a, 0x9a, 0x99, 0x46,
0xa5, 0xe1, 0x72, 0x31, 0xfe, 0x0e, 0x1a, 0xf4, 0x37, 0xea, 0x85, 0xae, 0x1d, 0x31, 0xad, 0x2c, 0x09, 0x97, 0x84, 0xcb, 0xc4, 0xf8, 0x5b, 0xa8, 0xd2, 0xdf, 0xa8, 0x1b, 0x38, 0x56, 0xc8, 0xb4,
0x9d, 0x38, 0x77, 0xea, 0x09, 0x95, 0x18, 0x73, 0x29, 0xfe, 0x16, 0xea, 0x1e, 0xe5, 0xf6, 0xd2, 0xa2, 0x74, 0xe2, 0xcc, 0xa9, 0xc7, 0x54, 0x6c, 0xcc, 0xa4, 0xf8, 0x1b, 0xa8, 0xb8, 0x94, 0x5b,
0xe6, 0xb6, 0x56, 0xe9, 0xa2, 0xc7, 0xb6, 0x59, 0xc2, 0x24, 0xb6, 0x4c, 0x89, 0xbf, 0x84, 0xf6, 0x0b, 0x8b, 0x5b, 0xda, 0x61, 0x1b, 0xed, 0xda, 0x26, 0x31, 0x13, 0xdb, 0x52, 0x25, 0xfe, 0x02,
0x22, 0xa2, 0x36, 0xa7, 0x4b, 0x4b, 0x0e, 0x88, 0xdb, 0x5e, 0xa8, 0x55, 0xbb, 0xa8, 0xaf, 0x10, 0x9a, 0xf3, 0x90, 0x5a, 0x9c, 0x2e, 0x4c, 0xd9, 0x20, 0x6e, 0xb9, 0x81, 0x56, 0x6a, 0xa3, 0xae,
0x35, 0x21, 0xcc, 0x14, 0xef, 0x59, 0x50, 0x4f, 0xfb, 0x7f, 0x78, 0x68, 0x1d, 0xa8, 0xec, 0x6c, 0x42, 0xd4, 0x98, 0x30, 0x12, 0xbc, 0x63, 0x42, 0x25, 0xa9, 0xff, 0x78, 0xd3, 0x5a, 0x70, 0xb8,
0x77, 0x4b, 0xb5, 0x52, 0x17, 0xf5, 0x11, 0x89, 0x0b, 0xfc, 0x31, 0x34, 0xf2, 0x3e, 0x8a, 0xec, 0xb5, 0x9c, 0x0d, 0xd5, 0x0a, 0x6d, 0xd4, 0x45, 0x24, 0xba, 0xe0, 0x0f, 0xa1, 0x9a, 0xd5, 0x51,
0x93, 0x03, 0xbd, 0x73, 0xa8, 0xc6, 0xf3, 0xcc, 0xdd, 0xe8, 0xbd, 0xee, 0xd2, 0xbe, 0xfb, 0xaf, 0x64, 0x9d, 0x0c, 0xe8, 0x9c, 0x43, 0x29, 0xea, 0x67, 0xe6, 0x46, 0xef, 0x75, 0x17, 0xf6, 0xdd,
0x12, 0xd4, 0xd3, 0x0f, 0xc5, 0x5f, 0x43, 0x59, 0x2c, 0x9e, 0xf4, 0xb7, 0x86, 0x2f, 0xdf, 0x1d, 0x7f, 0x17, 0xa0, 0x92, 0x7c, 0x28, 0xfe, 0x0a, 0x8a, 0x62, 0xf0, 0xa4, 0xbf, 0xd1, 0x7f, 0xf9,
0x85, 0x38, 0x44, 0xce, 0xc2, 0xbc, 0x0f, 0x29, 0x91, 0x52, 0xfc, 0x02, 0xea, 0x1b, 0xea, 0x86, 0x6e, 0x2b, 0xc4, 0x21, 0xb4, 0xe7, 0xc6, 0x7d, 0x40, 0x89, 0x94, 0xe2, 0x17, 0x50, 0x59, 0x53,
0xe2, 0x83, 0x64, 0xb4, 0x26, 0xa9, 0x89, 0x9a, 0xd0, 0x95, 0xa0, 0xb6, 0xbe, 0xc3, 0x25, 0x55, 0x27, 0x10, 0x1f, 0x24, 0xa3, 0xd5, 0x49, 0x59, 0xdc, 0x09, 0x5d, 0x0a, 0x6a, 0xe3, 0xd9, 0x5c,
0x8e, 0x29, 0x51, 0x13, 0xba, 0xea, 0xfd, 0x8d, 0x00, 0xf2, 0xab, 0xf0, 0x47, 0xf0, 0x7c, 0xa6, 0x52, 0xc5, 0x88, 0x12, 0x77, 0x42, 0x97, 0x9d, 0x7f, 0x10, 0x40, 0xf6, 0x14, 0xfe, 0x00, 0x9e,
0x9b, 0x64, 0x7a, 0x61, 0x99, 0xb7, 0x6f, 0x74, 0xeb, 0x66, 0x6e, 0xbc, 0xd1, 0x2f, 0xa6, 0x97, 0x4f, 0x74, 0x83, 0x8c, 0x2f, 0x4c, 0xe3, 0xf6, 0x8d, 0x6e, 0xde, 0x4c, 0x67, 0x6f, 0xf4, 0x8b,
0x53, 0xfd, 0xb5, 0x7a, 0x80, 0x9f, 0xc3, 0xd3, 0x22, 0x79, 0x71, 0x7d, 0x33, 0x37, 0x75, 0xa2, 0xf1, 0xe5, 0x58, 0x7f, 0xad, 0x1e, 0xe0, 0xe7, 0xf0, 0x34, 0x4f, 0x5e, 0x5c, 0xdf, 0x4c, 0x0d,
0x22, 0x7c, 0x0c, 0xed, 0x22, 0x71, 0x35, 0xba, 0xb9, 0xd2, 0xd5, 0x12, 0x7e, 0x01, 0xc7, 0x45, 0x9d, 0xa8, 0x08, 0x1f, 0x43, 0x33, 0x4f, 0x5c, 0x0d, 0x6e, 0xae, 0x74, 0xb5, 0x80, 0x5f, 0xc0,
0x78, 0x32, 0x35, 0xcc, 0xeb, 0x2b, 0x32, 0x9a, 0xa9, 0x0a, 0x3e, 0x85, 0x93, 0x77, 0x1c, 0x39, 0x71, 0x1e, 0x1e, 0x8d, 0x67, 0xc6, 0xf5, 0x15, 0x19, 0x4c, 0x54, 0x05, 0x9f, 0xc2, 0xc9, 0x3b,
0x5f, 0xde, 0x6f, 0x65, 0xdc, 0xcc, 0x66, 0x23, 0x72, 0xab, 0x56, 0x70, 0x07, 0xd4, 0x22, 0x31, 0x8e, 0x8c, 0x2f, 0xee, 0x97, 0x9a, 0xdd, 0x4c, 0x26, 0x03, 0x72, 0xab, 0x1e, 0xe2, 0x16, 0xa8,
0x9d, 0x5f, 0x5e, 0xab, 0x55, 0xac, 0x41, 0xe7, 0x91, 0xdc, 0x1c, 0x99, 0xba, 0xa1, 0x9b, 0x6a, 0x79, 0x62, 0x3c, 0xbd, 0xbc, 0x56, 0x4b, 0x58, 0x83, 0xd6, 0x8e, 0xdc, 0x18, 0x18, 0xfa, 0x4c,
0xad, 0xf7, 0x5f, 0x05, 0x1a, 0xd9, 0xbe, 0xe2, 0x97, 0xd0, 0x58, 0x04, 0x5b, 0x9f, 0x5b, 0x8e, 0x37, 0xd4, 0x72, 0xe7, 0x8f, 0x12, 0x54, 0xd3, 0x79, 0xc5, 0x2f, 0xa1, 0x3a, 0xf7, 0x37, 0x1e,
0xcf, 0xe5, 0x6c, 0xcb, 0x93, 0x03, 0x52, 0x97, 0xd0, 0xd4, 0xe7, 0xf8, 0x13, 0x38, 0x8c, 0xe9, 0x37, 0x6d, 0x8f, 0xcb, 0xde, 0x16, 0x47, 0x07, 0xa4, 0x22, 0xa1, 0xb1, 0xc7, 0xf1, 0x47, 0x70,
0x95, 0x1b, 0xd8, 0x3c, 0xfe, 0xd3, 0x4f, 0x0e, 0x08, 0x48, 0xf0, 0x52, 0x60, 0x58, 0x05, 0x85, 0x14, 0xd1, 0x4b, 0xc7, 0xb7, 0x78, 0xf4, 0xa7, 0x1f, 0x1d, 0x10, 0x90, 0xe0, 0xa5, 0xc0, 0xb0,
0x6d, 0x3d, 0x39, 0x60, 0x44, 0xc4, 0x11, 0x3f, 0x83, 0x2a, 0x5b, 0x6c, 0xa8, 0x67, 0xcb, 0xd1, 0x0a, 0x0a, 0xdb, 0xb8, 0xb2, 0xc1, 0x88, 0x88, 0x23, 0x7e, 0x06, 0x25, 0x36, 0x5f, 0x53, 0xd7,
0xb6, 0x49, 0x52, 0xe1, 0x4f, 0xa1, 0xf5, 0x3b, 0x8d, 0x02, 0x8b, 0x6f, 0x22, 0xca, 0x36, 0x81, 0x92, 0xad, 0x6d, 0x92, 0xf8, 0x86, 0x3f, 0x81, 0xc6, 0xef, 0x34, 0xf4, 0x4d, 0xbe, 0x0e, 0x29,
0xbb, 0x94, 0x7b, 0x8d, 0x48, 0x53, 0xa0, 0x66, 0x0a, 0xe2, 0xcf, 0x12, 0x59, 0x9e, 0xab, 0x2a, 0x5b, 0xfb, 0xce, 0x42, 0xce, 0x35, 0x22, 0x75, 0x81, 0x1a, 0x09, 0x88, 0x3f, 0x8d, 0x65, 0x59,
0x73, 0x21, 0x72, 0x24, 0xf0, 0x8b, 0x34, 0xdb, 0x17, 0xa0, 0x16, 0x74, 0x71, 0xc0, 0x9a, 0x0c, 0xae, 0x92, 0xcc, 0x85, 0x48, 0x4d, 0xe0, 0x17, 0x49, 0xb6, 0xcf, 0x41, 0xcd, 0xe9, 0xa2, 0x80,
0x88, 0x48, 0x2b, 0x53, 0xc6, 0x21, 0x47, 0xd0, 0xf2, 0xe9, 0xda, 0xe6, 0xce, 0x8e, 0x5a, 0x2c, 0x65, 0x19, 0x10, 0x91, 0x46, 0xaa, 0x8c, 0x42, 0x0e, 0xa0, 0xe1, 0xd1, 0x95, 0xc5, 0xed, 0x2d,
0xb4, 0x7d, 0xa6, 0xd5, 0xf7, 0xff, 0xc3, 0x8c, 0xb7, 0x8b, 0x9f, 0x29, 0x37, 0x42, 0xdb, 0x4f, 0x35, 0x59, 0x60, 0x79, 0x4c, 0xab, 0xec, 0xff, 0x87, 0x19, 0x6e, 0xe6, 0x3f, 0x53, 0x3e, 0x0b,
0x1e, 0x55, 0x33, 0x75, 0x08, 0x8c, 0xe1, 0xcf, 0xe1, 0x49, 0x76, 0xc5, 0x92, 0xba, 0xdc, 0x66, 0x2c, 0x2f, 0x5e, 0xaa, 0x7a, 0xe2, 0x10, 0x18, 0xc3, 0x9f, 0xc1, 0x93, 0xf4, 0x89, 0x05, 0x75,
0x5a, 0xa3, 0xab, 0xf4, 0x31, 0xc9, 0x6e, 0x7e, 0x2d, 0xd1, 0x47, 0x42, 0x99, 0x8d, 0x69, 0xd0, 0xb8, 0xc5, 0xb4, 0x6a, 0x5b, 0xe9, 0x62, 0x92, 0xbe, 0xfc, 0x5a, 0xa2, 0x3b, 0x42, 0x99, 0x8d,
0x55, 0xfa, 0x28, 0x17, 0xca, 0x60, 0x4c, 0x84, 0x0a, 0x03, 0xe6, 0x14, 0x42, 0x1d, 0x7e, 0x38, 0x69, 0xd0, 0x56, 0xba, 0x28, 0x13, 0xca, 0x60, 0x4c, 0x84, 0x0a, 0x7c, 0x66, 0xe7, 0x42, 0x1d,
0x54, 0xea, 0xc8, 0x42, 0x65, 0x57, 0x24, 0xa1, 0x8e, 0xe2, 0x50, 0x29, 0x9c, 0x87, 0xca, 0x84, 0x3d, 0x1e, 0x2a, 0x71, 0xa4, 0xa1, 0xd2, 0x27, 0xe2, 0x50, 0xb5, 0x28, 0x54, 0x02, 0x67, 0xa1,
0x49, 0xa8, 0x66, 0x1c, 0x2a, 0x85, 0x93, 0x50, 0xe7, 0x00, 0x11, 0x65, 0x94, 0x5b, 0x1b, 0x31, 0x52, 0x61, 0x1c, 0xaa, 0x1e, 0x85, 0x4a, 0xe0, 0x38, 0xd4, 0x39, 0x40, 0x48, 0x19, 0xe5, 0xe6,
0xf9, 0xd6, 0xfe, 0x6b, 0xcb, 0x36, 0x67, 0x40, 0x84, 0x6a, 0xe2, 0xf8, 0x9c, 0x34, 0xa2, 0xf4, 0x5a, 0x74, 0xbe, 0xb1, 0xbf, 0x6d, 0xe9, 0xe4, 0xf4, 0x88, 0x50, 0x8d, 0x6c, 0x8f, 0x93, 0x6a,
0xf8, 0xf8, 0x41, 0x3f, 0xd9, 0x7f, 0xd0, 0x4b, 0x68, 0x64, 0x2e, 0x7c, 0x02, 0xcf, 0x88, 0x58, 0x98, 0x1c, 0x77, 0x17, 0xfa, 0xc9, 0xde, 0x42, 0xe3, 0x8f, 0xa1, 0x3e, 0xdf, 0x30, 0xee, 0xbb,
0x49, 0x6b, 0x32, 0x9d, 0x9b, 0x7b, 0xef, 0x0a, 0x43, 0xab, 0xc0, 0xdd, 0xea, 0x86, 0x8a, 0x70, 0xa6, 0x5c, 0x7f, 0xa6, 0xa9, 0x32, 0x42, 0x2d, 0x02, 0x7f, 0x90, 0x58, 0x67, 0x01, 0xd5, 0xf4,
0x1b, 0x9a, 0x05, 0x6c, 0x7e, 0xad, 0x96, 0xc4, 0xea, 0x17, 0xa0, 0xf8, 0x91, 0x29, 0xe3, 0x1a, 0x69, 0x7c, 0x02, 0xcf, 0x88, 0x98, 0x5b, 0x73, 0x34, 0x9e, 0x1a, 0x7b, 0xcb, 0x87, 0xa1, 0x91,
0x54, 0xe4, 0x17, 0x8e, 0x8f, 0x00, 0xf2, 0x05, 0xe9, 0x9d, 0x03, 0xe4, 0xd3, 0x14, 0x3b, 0x1a, 0xe3, 0x6e, 0xf5, 0x99, 0x8a, 0x70, 0x13, 0xea, 0x39, 0x6c, 0x7a, 0xad, 0x16, 0xc4, 0x7e, 0xe4,
0xac, 0x56, 0x8c, 0xc6, 0x4b, 0xdf, 0x26, 0x49, 0x25, 0x70, 0x97, 0xfa, 0x6b, 0xbe, 0x91, 0xbb, 0xa0, 0x68, 0x13, 0x95, 0x61, 0x19, 0x0e, 0x65, 0x1b, 0x86, 0x35, 0x80, 0x6c, 0x8a, 0x3a, 0xe7,
0xde, 0x24, 0x49, 0x35, 0x3e, 0x7e, 0xfb, 0x70, 0x8a, 0xfe, 0x7c, 0x38, 0x45, 0xff, 0x3e, 0x9c, 0x00, 0x59, 0xcb, 0xc5, 0x20, 0xfb, 0xcb, 0x25, 0xa3, 0xd1, 0x66, 0x34, 0x49, 0x7c, 0x13, 0xb8,
0xa2, 0x9f, 0x6a, 0x72, 0x1e, 0xbb, 0xe1, 0x5d, 0x55, 0xfe, 0xcc, 0x7d, 0xf3, 0x7f, 0x00, 0x00, 0x43, 0xbd, 0x15, 0x5f, 0xcb, 0x85, 0xa8, 0x93, 0xf8, 0x36, 0x3c, 0x7e, 0xfb, 0x70, 0x8a, 0xfe,
0x00, 0xff, 0xff, 0x50, 0xe1, 0xdd, 0xa2, 0x1e, 0x07, 0x00, 0x00, 0x7a, 0x38, 0x45, 0xff, 0x3d, 0x9c, 0xa2, 0x9f, 0xca, 0xb2, 0x69, 0xdb, 0xfe, 0x5d, 0x49, 0xfe,
0x16, 0x7e, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x86, 0xd6, 0x1e, 0x43, 0x07, 0x00,
0x00,
} }
func (m *WriteRequest) Marshal() (dAtA []byte, err error) { func (m *WriteRequest) Marshal() (dAtA []byte, err error) {
@ -1180,6 +1226,18 @@ func (m *Histogram) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i -= len(m.XXX_unrecognized) i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized)
} }
if len(m.CustomValues) > 0 {
for iNdEx := len(m.CustomValues) - 1; iNdEx >= 0; iNdEx-- {
f6 := math.Float64bits(float64(m.CustomValues[iNdEx]))
i -= 8
encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(f6))
}
i = encodeVarintTypes(dAtA, i, uint64(len(m.CustomValues)*8))
i--
dAtA[i] = 0x1
i--
dAtA[i] = 0x82
}
if m.Timestamp != 0 { if m.Timestamp != 0 {
i = encodeVarintTypes(dAtA, i, uint64(m.Timestamp)) i = encodeVarintTypes(dAtA, i, uint64(m.Timestamp))
i-- i--
@ -1192,30 +1250,30 @@ func (m *Histogram) MarshalToSizedBuffer(dAtA []byte) (int, error) {
} }
if len(m.PositiveCounts) > 0 { if len(m.PositiveCounts) > 0 {
for iNdEx := len(m.PositiveCounts) - 1; iNdEx >= 0; iNdEx-- { for iNdEx := len(m.PositiveCounts) - 1; iNdEx >= 0; iNdEx-- {
f6 := math.Float64bits(float64(m.PositiveCounts[iNdEx])) f7 := math.Float64bits(float64(m.PositiveCounts[iNdEx]))
i -= 8 i -= 8
encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(f6)) encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(f7))
} }
i = encodeVarintTypes(dAtA, i, uint64(len(m.PositiveCounts)*8)) i = encodeVarintTypes(dAtA, i, uint64(len(m.PositiveCounts)*8))
i-- i--
dAtA[i] = 0x6a dAtA[i] = 0x6a
} }
if len(m.PositiveDeltas) > 0 { if len(m.PositiveDeltas) > 0 {
var j7 int var j8 int
dAtA9 := make([]byte, len(m.PositiveDeltas)*10) dAtA10 := make([]byte, len(m.PositiveDeltas)*10)
for _, num := range m.PositiveDeltas { for _, num := range m.PositiveDeltas {
x8 := (uint64(num) << 1) ^ uint64((num >> 63)) x9 := (uint64(num) << 1) ^ uint64((num >> 63))
for x8 >= 1<<7 { for x9 >= 1<<7 {
dAtA9[j7] = uint8(uint64(x8)&0x7f | 0x80) dAtA10[j8] = uint8(uint64(x9)&0x7f | 0x80)
j7++ j8++
x8 >>= 7 x9 >>= 7
} }
dAtA9[j7] = uint8(x8) dAtA10[j8] = uint8(x9)
j7++ j8++
} }
i -= j7 i -= j8
copy(dAtA[i:], dAtA9[:j7]) copy(dAtA[i:], dAtA10[:j8])
i = encodeVarintTypes(dAtA, i, uint64(j7)) i = encodeVarintTypes(dAtA, i, uint64(j8))
i-- i--
dAtA[i] = 0x62 dAtA[i] = 0x62
} }
@ -1235,30 +1293,30 @@ func (m *Histogram) MarshalToSizedBuffer(dAtA []byte) (int, error) {
} }
if len(m.NegativeCounts) > 0 { if len(m.NegativeCounts) > 0 {
for iNdEx := len(m.NegativeCounts) - 1; iNdEx >= 0; iNdEx-- { for iNdEx := len(m.NegativeCounts) - 1; iNdEx >= 0; iNdEx-- {
f10 := math.Float64bits(float64(m.NegativeCounts[iNdEx])) f11 := math.Float64bits(float64(m.NegativeCounts[iNdEx]))
i -= 8 i -= 8
encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(f10)) encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(f11))
} }
i = encodeVarintTypes(dAtA, i, uint64(len(m.NegativeCounts)*8)) i = encodeVarintTypes(dAtA, i, uint64(len(m.NegativeCounts)*8))
i-- i--
dAtA[i] = 0x52 dAtA[i] = 0x52
} }
if len(m.NegativeDeltas) > 0 { if len(m.NegativeDeltas) > 0 {
var j11 int var j12 int
dAtA13 := make([]byte, len(m.NegativeDeltas)*10) dAtA14 := make([]byte, len(m.NegativeDeltas)*10)
for _, num := range m.NegativeDeltas { for _, num := range m.NegativeDeltas {
x12 := (uint64(num) << 1) ^ uint64((num >> 63)) x13 := (uint64(num) << 1) ^ uint64((num >> 63))
for x12 >= 1<<7 { for x13 >= 1<<7 {
dAtA13[j11] = uint8(uint64(x12)&0x7f | 0x80) dAtA14[j12] = uint8(uint64(x13)&0x7f | 0x80)
j11++ j12++
x12 >>= 7 x13 >>= 7
} }
dAtA13[j11] = uint8(x12) dAtA14[j12] = uint8(x13)
j11++ j12++
} }
i -= j11 i -= j12
copy(dAtA[i:], dAtA13[:j11]) copy(dAtA[i:], dAtA14[:j12])
i = encodeVarintTypes(dAtA, i, uint64(j11)) i = encodeVarintTypes(dAtA, i, uint64(j12))
i-- i--
dAtA[i] = 0x4a dAtA[i] = 0x4a
} }
@ -1601,6 +1659,9 @@ func (m *Histogram) Size() (n int) {
if m.Timestamp != 0 { if m.Timestamp != 0 {
n += 1 + sovTypes(uint64(m.Timestamp)) n += 1 + sovTypes(uint64(m.Timestamp))
} }
if len(m.CustomValues) > 0 {
n += 2 + sovTypes(uint64(len(m.CustomValues)*8)) + len(m.CustomValues)*8
}
if m.XXX_unrecognized != nil { if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized) n += len(m.XXX_unrecognized)
} }
@ -2915,6 +2976,60 @@ func (m *Histogram) Unmarshal(dAtA []byte) error {
break break
} }
} }
case 16:
if wireType == 1 {
var v uint64
if (iNdEx + 8) > l {
return io.ErrUnexpectedEOF
}
v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:]))
iNdEx += 8
v2 := float64(math.Float64frombits(v))
m.CustomValues = append(m.CustomValues, v2)
} else if wireType == 2 {
var packedLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
packedLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if packedLen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + packedLen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
var elementCount int
elementCount = packedLen / 8
if elementCount != 0 && len(m.CustomValues) == 0 {
m.CustomValues = make([]float64, 0, elementCount)
}
for iNdEx < postIndex {
var v uint64
if (iNdEx + 8) > l {
return io.ErrUnexpectedEOF
}
v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:]))
iNdEx += 8
v2 := float64(math.Float64frombits(v))
m.CustomValues = append(m.CustomValues, v2)
}
} else {
return fmt.Errorf("proto: wrong wireType = %d for field CustomValues", wireType)
}
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:]) skippy, err := skipTypes(dAtA[iNdEx:])

View file

@ -155,13 +155,18 @@ message Histogram {
double count_float = 2; double count_float = 2;
} }
double sum = 3; // Sum of observations in the histogram. double sum = 3; // Sum of observations in the histogram.
// The schema defines the bucket schema. Currently, valid numbers // The schema defines the bucket schema. Currently, valid numbers
// are -4 <= n <= 8. They are all for base-2 bucket schemas, where 1 // are -53 and numbers in range of -4 <= n <= 8. More valid numbers might be
// added in future for new bucketing layouts.
//
// The schema equal to -53 means custom buckets. See
// custom_values field description for more details.
//
// Values between -4 and 8 represent base-2 bucket schema, where 1
// is a bucket boundary in each case, and then each power of two is // is a bucket boundary in each case, and then each power of two is
// divided into 2^n logarithmic buckets. Or in other words, each // divided into 2^n (n is schema value) logarithmic buckets. Or in other words,
// bucket boundary is the previous boundary times 2^(2^-n). In the // each bucket boundary is the previous boundary times 2^(2^-n).
// future, more bucket schemas may be added using numbers < -4 or >
// 8.
sint32 schema = 4; sint32 schema = 4;
double zero_threshold = 5; // Breadth of the zero bucket. double zero_threshold = 5; // Breadth of the zero bucket.
oneof zero_count { // Count in zero bucket. oneof zero_count { // Count in zero bucket.
@ -172,16 +177,21 @@ message Histogram {
// Negative Buckets. // Negative Buckets.
repeated BucketSpan negative_spans = 8 [(gogoproto.nullable) = false]; repeated BucketSpan negative_spans = 8 [(gogoproto.nullable) = false];
// Use either "negative_deltas" or "negative_counts", the former for // Use either "negative_deltas" or "negative_counts", the former for
// regular histograms with integer counts, the latter for float // regular histograms with integer counts, the latter for
// histograms. // float histograms.
repeated sint64 negative_deltas = 9; // Count delta of each bucket compared to previous one (or to zero for 1st bucket). repeated sint64 negative_deltas = 9; // Count delta of each bucket compared to previous one (or to zero for 1st bucket).
repeated double negative_counts = 10; // Absolute count of each bucket. repeated double negative_counts = 10; // Absolute count of each bucket.
// Positive Buckets. // Positive Buckets.
//
// In case of custom buckets (-53 schema value) the positive buckets are interpreted as follows:
// * The span offset+length points to an the index of the custom_values array
// or +Inf if pointing to the len of the array.
// * The counts and deltas have the same meaning as for exponential histograms.
repeated BucketSpan positive_spans = 11 [(gogoproto.nullable) = false]; repeated BucketSpan positive_spans = 11 [(gogoproto.nullable) = false];
// Use either "positive_deltas" or "positive_counts", the former for // Use either "positive_deltas" or "positive_counts", the former for
// regular histograms with integer counts, the latter for float // regular histograms with integer counts, the latter for
// histograms. // float histograms.
repeated sint64 positive_deltas = 12; // Count delta of each bucket compared to previous one (or to zero for 1st bucket). repeated sint64 positive_deltas = 12; // Count delta of each bucket compared to previous one (or to zero for 1st bucket).
repeated double positive_counts = 13; // Absolute count of each bucket. repeated double positive_counts = 13; // Absolute count of each bucket.
@ -190,6 +200,35 @@ message Histogram {
// For Go, see github.com/prometheus/prometheus/model/timestamp/timestamp.go // For Go, see github.com/prometheus/prometheus/model/timestamp/timestamp.go
// for conversion from/to time.Time to Prometheus timestamp. // for conversion from/to time.Time to Prometheus timestamp.
int64 timestamp = 15; int64 timestamp = 15;
// custom_values is an additional field used by non-exponential bucketing layouts.
//
// For custom buckets (-53 schema value) custom_values specify monotonically
// increasing upper inclusive boundaries for the bucket counts with arbitrary
// widths for this histogram. In other words, custom_values represents custom,
// explicit bucketing that could have been converted from the classic histograms.
//
// Those bounds are then referenced by spans in positive_spans with corresponding positive
// counts of deltas (refer to positive_spans for more details). This way we can
// have encode sparse histograms with custom bucketing (many buckets are often
// not used).
//
// Note that for custom bounds, even negative observations are placed in the positive
// counts to simplify the implementation and avoid ambiguity of where to place
// an underflow bucket, e.g. (-2, 1]. Therefore negative buckets and
// the zero bucket are unused, if the schema indicates custom bucketing.
//
// For each upper boundary the previous boundary represent the lower exclusive
// boundary for that bucket. The first element is the upper inclusive boundary
// for the first bucket, which implicitly has a lower inclusive bound of -Inf.
// This is similar to "le" label semantics on classic histograms. You may add a
// bucket with an upper bound of 0 to make sure that you really have no negative
// observations, but in practice, native histogram rendering will show both with
// or without first upper boundary 0 and no negative counts as the same case.
//
// The last element is not only the upper inclusive bound of the last regular
// bucket, but implicitly the lower exclusive bound of the +Inf bucket.
repeated double custom_values = 16;
} }
// A BucketSpan defines a number of consecutive buckets with their // A BucketSpan defines a number of consecutive buckets with their