diff --git a/CHANGELOG.md b/CHANGELOG.md index 37eece98b3..b2ebd73845 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## master / unreleased * [CHANGE] Alertmanager: Validating new fields on the PagerDuty AM config. #5290 +* [CHANGE] Ingester: Creating label `native-histogram-sample` on the `cortex_discarded_samples_total` to keep track of discarded native histogram samples. #5289 * [BUGFIX] Ruler: Validate if rule group can be safely converted back to rule group yaml from protobuf message #5265 * [BUGFIX] Querier: Convert gRPC `ResourceExhausted` status code from store gateway to 422 limit error. #5286 diff --git a/pkg/cortexpb/compat.go b/pkg/cortexpb/compat.go index d6114eb3fd..79e446face 100644 --- a/pkg/cortexpb/compat.go +++ b/pkg/cortexpb/compat.go @@ -21,7 +21,7 @@ import ( // ToWriteRequest converts matched slices of Labels, Samples and Metadata into a WriteRequest proto. // It gets timeseries from the pool, so ReuseSlice() should be called when done. -func ToWriteRequest(lbls []labels.Labels, samples []Sample, metadata []*MetricMetadata, source WriteRequest_SourceEnum) *WriteRequest { +func ToWriteRequest(lbls []labels.Labels, samples []Sample, metadata []*MetricMetadata, histograms []Histogram, source WriteRequest_SourceEnum) *WriteRequest { req := &WriteRequest{ Timeseries: PreallocTimeseriesSliceFromPool(), Metadata: metadata, @@ -32,6 +32,9 @@ func ToWriteRequest(lbls []labels.Labels, samples []Sample, metadata []*MetricMe ts := TimeseriesFromPool() ts.Labels = append(ts.Labels, FromLabelsToLabelAdapters(lbls[i])...) ts.Samples = append(ts.Samples, s) + if i < len(histograms) { + ts.Histograms = append(ts.Histograms, histograms[i]) + } req.Timeseries = append(req.Timeseries, PreallocTimeseries{TimeSeries: ts}) } diff --git a/pkg/cortexpb/cortex.pb.go b/pkg/cortexpb/cortex.pb.go index 311430e194..3b63e15904 100644 --- a/pkg/cortexpb/cortex.pb.go +++ b/pkg/cortexpb/cortex.pb.go @@ -88,6 +88,33 @@ func (MetricMetadata_MetricType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_893a47d0a749d749, []int{5, 0} } +type Histogram_ResetHint int32 + +const ( + Histogram_UNKNOWN Histogram_ResetHint = 0 + Histogram_YES Histogram_ResetHint = 1 + Histogram_NO Histogram_ResetHint = 2 + Histogram_GAUGE Histogram_ResetHint = 3 +) + +var Histogram_ResetHint_name = map[int32]string{ + 0: "UNKNOWN", + 1: "YES", + 2: "NO", + 3: "GAUGE", +} + +var Histogram_ResetHint_value = map[string]int32{ + "UNKNOWN": 0, + "YES": 1, + "NO": 2, + "GAUGE": 3, +} + +func (Histogram_ResetHint) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_893a47d0a749d749, []int{8, 0} +} + type WriteRequest struct { Timeseries []PreallocTimeseries `protobuf:"bytes,1,rep,name=timeseries,proto3,customtype=PreallocTimeseries" json:"timeseries"` Source WriteRequest_SourceEnum `protobuf:"varint,2,opt,name=Source,proto3,enum=cortexpb.WriteRequest_SourceEnum" json:"Source,omitempty"` @@ -186,8 +213,9 @@ var xxx_messageInfo_WriteResponse proto.InternalMessageInfo type TimeSeries struct { Labels []LabelAdapter `protobuf:"bytes,1,rep,name=labels,proto3,customtype=LabelAdapter" json:"labels"` // Sorted by time, oldest sample first. - Samples []Sample `protobuf:"bytes,2,rep,name=samples,proto3" json:"samples"` - Exemplars []Exemplar `protobuf:"bytes,3,rep,name=exemplars,proto3" json:"exemplars"` + Samples []Sample `protobuf:"bytes,2,rep,name=samples,proto3" json:"samples"` + Exemplars []Exemplar `protobuf:"bytes,3,rep,name=exemplars,proto3" json:"exemplars"` + Histograms []Histogram `protobuf:"bytes,4,rep,name=histograms,proto3" json:"histograms"` } func (m *TimeSeries) Reset() { *m = TimeSeries{} } @@ -236,6 +264,13 @@ func (m *TimeSeries) GetExemplars() []Exemplar { return nil } +func (m *TimeSeries) GetHistograms() []Histogram { + if m != nil { + return m.Histograms + } + return nil +} + type LabelPair struct { Name []byte `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` @@ -494,9 +529,304 @@ func (m *Exemplar) GetTimestampMs() int64 { return 0 } +// A native histogram, also known as a sparse histogram. +// Original design doc: +// https://docs.google.com/document/d/1cLNv3aufPZb3fNfaJgdaRBZsInZKKIHo9E6HinJVbpM/edit +// The appendix of this design doc also explains the concept of float +// histograms. This Histogram message can represent both, the usual +// integer histogram as well as a float histogram. +type Histogram struct { + // Types that are valid to be assigned to Count: + // + // *Histogram_CountInt + // *Histogram_CountFloat + Count isHistogram_Count `protobuf_oneof:"count"` + Sum float64 `protobuf:"fixed64,3,opt,name=sum,proto3" json:"sum,omitempty"` + // The schema defines the bucket schema. Currently, valid numbers + // are -4 <= n <= 8. They are all for base-2 bucket schemas, where 1 + // 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 + // bucket boundary is the previous boundary times 2^(2^-n). In the + // future, more bucket schemas may be added using numbers < -4 or > + // 8. + 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"` + // Types that are valid to be assigned to ZeroCount: + // + // *Histogram_ZeroCountInt + // *Histogram_ZeroCountFloat + ZeroCount isHistogram_ZeroCount `protobuf_oneof:"zero_count"` + // Negative Buckets. + 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 + // regular histograms with integer counts, the latter for float + // histograms. + 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"` + // Positive Buckets. + 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 + // regular histograms with integer counts, the latter for float + // histograms. + 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"` + ResetHint Histogram_ResetHint `protobuf:"varint,14,opt,name=reset_hint,json=resetHint,proto3,enum=cortexpb.Histogram_ResetHint" json:"reset_hint,omitempty"` + // timestamp is in ms format, see model/timestamp/timestamp.go for + // conversion from time.Time to Prometheus timestamp. + TimestampMs int64 `protobuf:"varint,15,opt,name=timestamp_ms,json=timestampMs,proto3" json:"timestamp_ms,omitempty"` +} + +func (m *Histogram) Reset() { *m = Histogram{} } +func (*Histogram) ProtoMessage() {} +func (*Histogram) Descriptor() ([]byte, []int) { + return fileDescriptor_893a47d0a749d749, []int{8} +} +func (m *Histogram) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Histogram) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Histogram.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Histogram) XXX_Merge(src proto.Message) { + xxx_messageInfo_Histogram.Merge(m, src) +} +func (m *Histogram) XXX_Size() int { + return m.Size() +} +func (m *Histogram) XXX_DiscardUnknown() { + xxx_messageInfo_Histogram.DiscardUnknown(m) +} + +var xxx_messageInfo_Histogram proto.InternalMessageInfo + +type isHistogram_Count interface { + isHistogram_Count() + Equal(interface{}) bool + MarshalTo([]byte) (int, error) + Size() int +} +type isHistogram_ZeroCount interface { + isHistogram_ZeroCount() + Equal(interface{}) bool + MarshalTo([]byte) (int, error) + Size() int +} + +type Histogram_CountInt struct { + CountInt uint64 `protobuf:"varint,1,opt,name=count_int,json=countInt,proto3,oneof"` +} +type Histogram_CountFloat struct { + CountFloat float64 `protobuf:"fixed64,2,opt,name=count_float,json=countFloat,proto3,oneof"` +} +type Histogram_ZeroCountInt struct { + ZeroCountInt uint64 `protobuf:"varint,6,opt,name=zero_count_int,json=zeroCountInt,proto3,oneof"` +} +type Histogram_ZeroCountFloat struct { + ZeroCountFloat float64 `protobuf:"fixed64,7,opt,name=zero_count_float,json=zeroCountFloat,proto3,oneof"` +} + +func (*Histogram_CountInt) isHistogram_Count() {} +func (*Histogram_CountFloat) isHistogram_Count() {} +func (*Histogram_ZeroCountInt) isHistogram_ZeroCount() {} +func (*Histogram_ZeroCountFloat) isHistogram_ZeroCount() {} + +func (m *Histogram) GetCount() isHistogram_Count { + if m != nil { + return m.Count + } + return nil +} +func (m *Histogram) GetZeroCount() isHistogram_ZeroCount { + if m != nil { + return m.ZeroCount + } + return nil +} + +func (m *Histogram) GetCountInt() uint64 { + if x, ok := m.GetCount().(*Histogram_CountInt); ok { + return x.CountInt + } + return 0 +} + +func (m *Histogram) GetCountFloat() float64 { + if x, ok := m.GetCount().(*Histogram_CountFloat); ok { + return x.CountFloat + } + return 0 +} + +func (m *Histogram) GetSum() float64 { + if m != nil { + return m.Sum + } + return 0 +} + +func (m *Histogram) GetSchema() int32 { + if m != nil { + return m.Schema + } + return 0 +} + +func (m *Histogram) GetZeroThreshold() float64 { + if m != nil { + return m.ZeroThreshold + } + return 0 +} + +func (m *Histogram) GetZeroCountInt() uint64 { + if x, ok := m.GetZeroCount().(*Histogram_ZeroCountInt); ok { + return x.ZeroCountInt + } + return 0 +} + +func (m *Histogram) GetZeroCountFloat() float64 { + if x, ok := m.GetZeroCount().(*Histogram_ZeroCountFloat); ok { + return x.ZeroCountFloat + } + return 0 +} + +func (m *Histogram) GetNegativeSpans() []BucketSpan { + if m != nil { + return m.NegativeSpans + } + return nil +} + +func (m *Histogram) GetNegativeDeltas() []int64 { + if m != nil { + return m.NegativeDeltas + } + return nil +} + +func (m *Histogram) GetNegativeCounts() []float64 { + if m != nil { + return m.NegativeCounts + } + return nil +} + +func (m *Histogram) GetPositiveSpans() []BucketSpan { + if m != nil { + return m.PositiveSpans + } + return nil +} + +func (m *Histogram) GetPositiveDeltas() []int64 { + if m != nil { + return m.PositiveDeltas + } + return nil +} + +func (m *Histogram) GetPositiveCounts() []float64 { + if m != nil { + return m.PositiveCounts + } + return nil +} + +func (m *Histogram) GetResetHint() Histogram_ResetHint { + if m != nil { + return m.ResetHint + } + return Histogram_UNKNOWN +} + +func (m *Histogram) GetTimestampMs() int64 { + if m != nil { + return m.TimestampMs + } + return 0 +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*Histogram) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*Histogram_CountInt)(nil), + (*Histogram_CountFloat)(nil), + (*Histogram_ZeroCountInt)(nil), + (*Histogram_ZeroCountFloat)(nil), + } +} + +// A BucketSpan defines a number of consecutive buckets with their +// offset. Logically, it would be more straightforward to include the +// bucket counts in the Span. However, the protobuf representation is +// more compact in the way the data is structured here (with all the +// buckets in a single array separate from the Spans). +type BucketSpan struct { + Offset int32 `protobuf:"zigzag32,1,opt,name=offset,proto3" json:"offset,omitempty"` + Length uint32 `protobuf:"varint,2,opt,name=length,proto3" json:"length,omitempty"` +} + +func (m *BucketSpan) Reset() { *m = BucketSpan{} } +func (*BucketSpan) ProtoMessage() {} +func (*BucketSpan) Descriptor() ([]byte, []int) { + return fileDescriptor_893a47d0a749d749, []int{9} +} +func (m *BucketSpan) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BucketSpan) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BucketSpan.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BucketSpan) XXX_Merge(src proto.Message) { + xxx_messageInfo_BucketSpan.Merge(m, src) +} +func (m *BucketSpan) XXX_Size() int { + return m.Size() +} +func (m *BucketSpan) XXX_DiscardUnknown() { + xxx_messageInfo_BucketSpan.DiscardUnknown(m) +} + +var xxx_messageInfo_BucketSpan proto.InternalMessageInfo + +func (m *BucketSpan) GetOffset() int32 { + if m != nil { + return m.Offset + } + return 0 +} + +func (m *BucketSpan) GetLength() uint32 { + if m != nil { + return m.Length + } + return 0 +} + func init() { proto.RegisterEnum("cortexpb.WriteRequest_SourceEnum", WriteRequest_SourceEnum_name, WriteRequest_SourceEnum_value) proto.RegisterEnum("cortexpb.MetricMetadata_MetricType", MetricMetadata_MetricType_name, MetricMetadata_MetricType_value) + proto.RegisterEnum("cortexpb.Histogram_ResetHint", Histogram_ResetHint_name, Histogram_ResetHint_value) proto.RegisterType((*WriteRequest)(nil), "cortexpb.WriteRequest") proto.RegisterType((*WriteResponse)(nil), "cortexpb.WriteResponse") proto.RegisterType((*TimeSeries)(nil), "cortexpb.TimeSeries") @@ -505,55 +835,79 @@ func init() { proto.RegisterType((*MetricMetadata)(nil), "cortexpb.MetricMetadata") proto.RegisterType((*Metric)(nil), "cortexpb.Metric") proto.RegisterType((*Exemplar)(nil), "cortexpb.Exemplar") + proto.RegisterType((*Histogram)(nil), "cortexpb.Histogram") + proto.RegisterType((*BucketSpan)(nil), "cortexpb.BucketSpan") } func init() { proto.RegisterFile("cortex.proto", fileDescriptor_893a47d0a749d749) } var fileDescriptor_893a47d0a749d749 = []byte{ - // 680 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcf, 0x6e, 0xd3, 0x4e, - 0x10, 0xf6, 0xe6, 0x7f, 0xa6, 0x6e, 0x7e, 0xd6, 0xfe, 0x22, 0x61, 0xf5, 0xe0, 0xa4, 0xe6, 0x92, - 0x03, 0x0a, 0xa8, 0x08, 0x10, 0x08, 0x21, 0x39, 0xc8, 0x2d, 0x55, 0x9b, 0x3f, 0x5a, 0x3b, 0x54, - 0x70, 0x89, 0xb6, 0xe9, 0x52, 0x2c, 0xec, 0xd8, 0xd8, 0x4e, 0xd5, 0xdc, 0x38, 0x71, 0xe6, 0xcc, - 0x13, 0xf0, 0x04, 0x48, 0xbc, 0x41, 0x8f, 0x3d, 0x56, 0x1c, 0x2a, 0xea, 0x5c, 0x7a, 0xec, 0x23, - 0x20, 0xaf, 0x9d, 0xb8, 0x15, 0xea, 0xad, 0xb7, 0x99, 0xf9, 0xe6, 0x9b, 0x99, 0x9d, 0x6f, 0xb4, - 0x20, 0x8e, 0x5d, 0x3f, 0x64, 0xc7, 0x6d, 0xcf, 0x77, 0x43, 0x17, 0x57, 0x12, 0xcf, 0xdb, 0x5f, - 0xab, 0x1f, 0xba, 0x87, 0x2e, 0x0f, 0x3e, 0x8c, 0xad, 0x04, 0x57, 0x7f, 0xe6, 0x40, 0xdc, 0xf3, - 0xad, 0x90, 0x11, 0xf6, 0x79, 0xca, 0x82, 0x10, 0x0f, 0x00, 0x42, 0xcb, 0x61, 0x01, 0xf3, 0x2d, - 0x16, 0xc8, 0xa8, 0x99, 0x6f, 0xad, 0x6c, 0xd4, 0xdb, 0x8b, 0x2a, 0x6d, 0xd3, 0x72, 0x98, 0xc1, - 0xb1, 0xce, 0xda, 0xc9, 0x79, 0x43, 0xf8, 0x7d, 0xde, 0xc0, 0x03, 0x9f, 0x51, 0xdb, 0x76, 0xc7, - 0xe6, 0x92, 0x47, 0xae, 0xd5, 0xc0, 0xcf, 0xa1, 0x64, 0xb8, 0x53, 0x7f, 0xcc, 0xe4, 0x5c, 0x13, - 0xb5, 0x6a, 0x1b, 0xeb, 0x59, 0xb5, 0xeb, 0x9d, 0xdb, 0x49, 0x92, 0x3e, 0x99, 0x3a, 0x24, 0x25, - 0xe0, 0x17, 0x50, 0x71, 0x58, 0x48, 0x0f, 0x68, 0x48, 0xe5, 0x3c, 0x1f, 0x45, 0xce, 0xc8, 0x5d, - 0x16, 0xfa, 0xd6, 0xb8, 0x9b, 0xe2, 0x9d, 0xc2, 0xc9, 0x79, 0x03, 0x91, 0x65, 0x3e, 0x7e, 0x09, - 0x6b, 0xc1, 0x27, 0xcb, 0x1b, 0xd9, 0x74, 0x9f, 0xd9, 0xa3, 0x09, 0x75, 0xd8, 0xe8, 0x88, 0xda, - 0xd6, 0x01, 0x0d, 0x2d, 0x77, 0x22, 0x5f, 0x96, 0x9b, 0xa8, 0x55, 0x21, 0xf7, 0xe2, 0x94, 0xdd, - 0x38, 0xa3, 0x47, 0x1d, 0xf6, 0x76, 0x89, 0xab, 0x0d, 0x80, 0x6c, 0x1e, 0x5c, 0x86, 0xbc, 0x36, - 0xd8, 0x96, 0x04, 0x5c, 0x81, 0x02, 0x19, 0xee, 0xea, 0x12, 0x52, 0xff, 0x83, 0xd5, 0x74, 0xfa, - 0xc0, 0x73, 0x27, 0x01, 0x53, 0x7f, 0x21, 0x80, 0x6c, 0x3b, 0x58, 0x83, 0x12, 0xef, 0xbc, 0xd8, - 0xe1, 0xff, 0xd9, 0xe0, 0xbc, 0xdf, 0x80, 0x5a, 0x7e, 0xa7, 0x9e, 0xae, 0x50, 0xe4, 0x21, 0xed, - 0x80, 0x7a, 0x21, 0xf3, 0x49, 0x4a, 0xc4, 0x8f, 0xa0, 0x1c, 0x50, 0xc7, 0xb3, 0x59, 0x20, 0xe7, - 0x78, 0x0d, 0x29, 0xab, 0x61, 0x70, 0x80, 0x3f, 0x5a, 0x20, 0x8b, 0x34, 0xfc, 0x14, 0xaa, 0xec, - 0x98, 0x39, 0x9e, 0x4d, 0xfd, 0x20, 0x5d, 0x18, 0xce, 0x38, 0x7a, 0x0a, 0xa5, 0xac, 0x2c, 0x55, - 0x7d, 0x02, 0xd5, 0xe5, 0x50, 0x18, 0x43, 0x21, 0xde, 0x96, 0x8c, 0x9a, 0xa8, 0x25, 0x12, 0x6e, - 0xe3, 0x3a, 0x14, 0x8f, 0xa8, 0x3d, 0x4d, 0x24, 0x14, 0x49, 0xe2, 0xa8, 0x1a, 0x94, 0x92, 0x39, - 0x32, 0x3c, 0x26, 0xa1, 0x14, 0xc7, 0xeb, 0x20, 0xf2, 0x3b, 0x08, 0xa9, 0xe3, 0x8d, 0x9c, 0x80, - 0x93, 0xf3, 0x64, 0x65, 0x19, 0xeb, 0x06, 0xea, 0xf7, 0x1c, 0xd4, 0x6e, 0x0a, 0x89, 0x9f, 0x41, - 0x21, 0x9c, 0x79, 0x49, 0xa9, 0xda, 0xc6, 0xfd, 0xdb, 0x04, 0x4f, 0x5d, 0x73, 0xe6, 0x31, 0xc2, - 0x09, 0xf8, 0x01, 0x60, 0x87, 0xc7, 0x46, 0x1f, 0xa8, 0x63, 0xd9, 0x33, 0x2e, 0x3a, 0x6f, 0x5a, - 0x25, 0x52, 0x82, 0x6c, 0x72, 0x20, 0xd6, 0x3a, 0x7e, 0xe6, 0x47, 0x66, 0x7b, 0x72, 0x81, 0xe3, - 0xdc, 0x8e, 0x63, 0xd3, 0x89, 0x15, 0xca, 0xc5, 0x24, 0x16, 0xdb, 0xea, 0x0c, 0x20, 0xeb, 0x84, - 0x57, 0xa0, 0x3c, 0xec, 0xed, 0xf4, 0xfa, 0x7b, 0x3d, 0x49, 0x88, 0x9d, 0xd7, 0xfd, 0x61, 0xcf, - 0xd4, 0x89, 0x84, 0x70, 0x15, 0x8a, 0x5b, 0xda, 0x70, 0x4b, 0x97, 0x72, 0x78, 0x15, 0xaa, 0x6f, - 0xb6, 0x0d, 0xb3, 0xbf, 0x45, 0xb4, 0xae, 0x94, 0xc7, 0x18, 0x6a, 0x1c, 0xc9, 0x62, 0x85, 0x98, - 0x6a, 0x0c, 0xbb, 0x5d, 0x8d, 0xbc, 0x93, 0x8a, 0xf1, 0x55, 0x6d, 0xf7, 0x36, 0xfb, 0x52, 0x09, - 0x8b, 0x50, 0x31, 0x4c, 0xcd, 0xd4, 0x0d, 0xdd, 0x94, 0xca, 0xea, 0x0e, 0x94, 0x92, 0xd6, 0x77, - 0x70, 0x4d, 0xea, 0x57, 0x04, 0x95, 0xc5, 0x05, 0xdc, 0xc5, 0x75, 0xde, 0x38, 0x89, 0x5b, 0x25, - 0xcf, 0xff, 0x23, 0x79, 0xe7, 0xd5, 0xe9, 0x85, 0x22, 0x9c, 0x5d, 0x28, 0xc2, 0xd5, 0x85, 0x82, - 0xbe, 0x44, 0x0a, 0xfa, 0x11, 0x29, 0xe8, 0x24, 0x52, 0xd0, 0x69, 0xa4, 0xa0, 0x3f, 0x91, 0x82, - 0x2e, 0x23, 0x45, 0xb8, 0x8a, 0x14, 0xf4, 0x6d, 0xae, 0x08, 0xa7, 0x73, 0x45, 0x38, 0x9b, 0x2b, - 0xc2, 0xfb, 0xe5, 0x47, 0xb6, 0x5f, 0xe2, 0x3f, 0xd7, 0xe3, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, - 0x5e, 0x23, 0x91, 0x5d, 0xe9, 0x04, 0x00, 0x00, + // 1031 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4b, 0x6f, 0x23, 0x45, + 0x17, 0xed, 0x72, 0xfb, 0x79, 0x63, 0x3b, 0x3d, 0xf5, 0x45, 0x1f, 0xad, 0x48, 0xd3, 0x71, 0x1a, + 0x01, 0x16, 0x42, 0x01, 0x05, 0x01, 0x9a, 0x51, 0x84, 0x64, 0x0f, 0xce, 0x43, 0x33, 0x76, 0xa2, + 0xb2, 0xc3, 0x68, 0xd8, 0x58, 0x15, 0xa7, 0x12, 0xb7, 0xa6, 0x5f, 0x74, 0x95, 0xa3, 0x09, 0x2b, + 0x56, 0x88, 0x25, 0x6b, 0xb6, 0x6c, 0xf8, 0x05, 0xfc, 0x86, 0x2c, 0xb3, 0x1c, 0xb1, 0x88, 0x88, + 0xb3, 0x99, 0xe5, 0x2c, 0xf8, 0x01, 0xa8, 0xaa, 0x5f, 0xce, 0x84, 0x11, 0x9b, 0xd9, 0x55, 0x9d, + 0x7b, 0xcf, 0xbd, 0xa7, 0xea, 0x9e, 0x2e, 0x35, 0xd4, 0x27, 0x41, 0x24, 0xd8, 0x8b, 0x8d, 0x30, + 0x0a, 0x44, 0x80, 0xab, 0xf1, 0x2e, 0x3c, 0x5a, 0x5d, 0x39, 0x0d, 0x4e, 0x03, 0x05, 0x7e, 0x2a, + 0x57, 0x71, 0xdc, 0xfe, 0xa3, 0x00, 0xf5, 0xa7, 0x91, 0x23, 0x18, 0x61, 0xdf, 0xcf, 0x18, 0x17, + 0xf8, 0x00, 0x40, 0x38, 0x1e, 0xe3, 0x2c, 0x72, 0x18, 0x37, 0x51, 0x4b, 0x6f, 0x2f, 0x6d, 0xae, + 0x6c, 0xa4, 0x55, 0x36, 0x46, 0x8e, 0xc7, 0x86, 0x2a, 0xd6, 0x5d, 0xbd, 0xb8, 0x5a, 0xd3, 0xfe, + 0xbc, 0x5a, 0xc3, 0x07, 0x11, 0xa3, 0xae, 0x1b, 0x4c, 0x46, 0x19, 0x8f, 0x2c, 0xd4, 0xc0, 0x0f, + 0xa0, 0x3c, 0x0c, 0x66, 0xd1, 0x84, 0x99, 0x85, 0x16, 0x6a, 0x37, 0x37, 0xd7, 0xf3, 0x6a, 0x8b, + 0x9d, 0x37, 0xe2, 0xa4, 0x9e, 0x3f, 0xf3, 0x48, 0x42, 0xc0, 0x0f, 0xa1, 0xea, 0x31, 0x41, 0x8f, + 0xa9, 0xa0, 0xa6, 0xae, 0xa4, 0x98, 0x39, 0xb9, 0xcf, 0x44, 0xe4, 0x4c, 0xfa, 0x49, 0xbc, 0x5b, + 0xbc, 0xb8, 0x5a, 0x43, 0x24, 0xcb, 0xc7, 0x5b, 0xb0, 0xca, 0x9f, 0x3b, 0xe1, 0xd8, 0xa5, 0x47, + 0xcc, 0x1d, 0xfb, 0xd4, 0x63, 0xe3, 0x33, 0xea, 0x3a, 0xc7, 0x54, 0x38, 0x81, 0x6f, 0xbe, 0xaa, + 0xb4, 0x50, 0xbb, 0x4a, 0xde, 0x93, 0x29, 0x4f, 0x64, 0xc6, 0x80, 0x7a, 0xec, 0xdb, 0x2c, 0x6e, + 0xaf, 0x01, 0xe4, 0x7a, 0x70, 0x05, 0xf4, 0xce, 0xc1, 0x9e, 0xa1, 0xe1, 0x2a, 0x14, 0xc9, 0xe1, + 0x93, 0x9e, 0x81, 0xec, 0x65, 0x68, 0x24, 0xea, 0x79, 0x18, 0xf8, 0x9c, 0xd9, 0x7f, 0x23, 0x80, + 0xfc, 0x76, 0x70, 0x07, 0xca, 0xaa, 0x73, 0x7a, 0x87, 0xff, 0xcb, 0x85, 0xab, 0x7e, 0x07, 0xd4, + 0x89, 0xba, 0x2b, 0xc9, 0x15, 0xd6, 0x15, 0xd4, 0x39, 0xa6, 0xa1, 0x60, 0x11, 0x49, 0x88, 0xf8, + 0x33, 0xa8, 0x70, 0xea, 0x85, 0x2e, 0xe3, 0x66, 0x41, 0xd5, 0x30, 0xf2, 0x1a, 0x43, 0x15, 0x50, + 0x87, 0xd6, 0x48, 0x9a, 0x86, 0xbf, 0x84, 0x1a, 0x7b, 0xc1, 0xbc, 0xd0, 0xa5, 0x11, 0x4f, 0x2e, + 0x0c, 0xe7, 0x9c, 0x5e, 0x12, 0x4a, 0x58, 0x79, 0x2a, 0x7e, 0x00, 0x30, 0x75, 0xb8, 0x08, 0x4e, + 0x23, 0xea, 0x71, 0xb3, 0xf8, 0xa6, 0xe0, 0xdd, 0x34, 0x96, 0x30, 0x17, 0x92, 0xed, 0x2f, 0xa0, + 0x96, 0x9d, 0x07, 0x63, 0x28, 0xca, 0x8b, 0x36, 0x51, 0x0b, 0xb5, 0xeb, 0x44, 0xad, 0xf1, 0x0a, + 0x94, 0xce, 0xa8, 0x3b, 0x8b, 0xa7, 0x5f, 0x27, 0xf1, 0xc6, 0xee, 0x40, 0x39, 0x3e, 0x42, 0x1e, + 0x97, 0x24, 0x94, 0xc4, 0xf1, 0x3a, 0xd4, 0x95, 0x85, 0x04, 0xf5, 0xc2, 0xb1, 0xc7, 0x15, 0x59, + 0x27, 0x4b, 0x19, 0xd6, 0xe7, 0xf6, 0xaf, 0x05, 0x68, 0xde, 0xf6, 0x00, 0xfe, 0x0a, 0x8a, 0xe2, + 0x3c, 0x8c, 0x4b, 0x35, 0x37, 0xdf, 0x7f, 0x9b, 0x57, 0x92, 0xed, 0xe8, 0x3c, 0x64, 0x44, 0x11, + 0xf0, 0x27, 0x80, 0x3d, 0x85, 0x8d, 0x4f, 0xa8, 0xe7, 0xb8, 0xe7, 0xca, 0x2f, 0xaa, 0x69, 0x8d, + 0x18, 0x71, 0x64, 0x5b, 0x05, 0xa4, 0x4d, 0xe4, 0x31, 0xa7, 0xcc, 0x0d, 0xcd, 0xa2, 0x8a, 0xab, + 0xb5, 0xc4, 0x66, 0xbe, 0x23, 0xcc, 0x52, 0x8c, 0xc9, 0xb5, 0x7d, 0x0e, 0x90, 0x77, 0xc2, 0x4b, + 0x50, 0x39, 0x1c, 0x3c, 0x1e, 0xec, 0x3f, 0x1d, 0x18, 0x9a, 0xdc, 0x3c, 0xda, 0x3f, 0x1c, 0x8c, + 0x7a, 0xc4, 0x40, 0xb8, 0x06, 0xa5, 0x9d, 0xce, 0xe1, 0x4e, 0xcf, 0x28, 0xe0, 0x06, 0xd4, 0x76, + 0xf7, 0x86, 0xa3, 0xfd, 0x1d, 0xd2, 0xe9, 0x1b, 0x3a, 0xc6, 0xd0, 0x54, 0x91, 0x1c, 0x2b, 0x4a, + 0xea, 0xf0, 0xb0, 0xdf, 0xef, 0x90, 0x67, 0x46, 0x49, 0x1a, 0x72, 0x6f, 0xb0, 0xbd, 0x6f, 0x94, + 0x71, 0x1d, 0xaa, 0xc3, 0x51, 0x67, 0xd4, 0x1b, 0xf6, 0x46, 0x46, 0xc5, 0x7e, 0x0c, 0xe5, 0xb8, + 0xf5, 0x3b, 0x30, 0xa2, 0xfd, 0x13, 0x82, 0x6a, 0x6a, 0x9e, 0x77, 0x61, 0xec, 0x5b, 0x96, 0x78, + 0xeb, 0xc8, 0xf5, 0xbb, 0x23, 0xbf, 0x2c, 0x41, 0x2d, 0x33, 0x23, 0xbe, 0x0f, 0xb5, 0x49, 0x30, + 0xf3, 0xc5, 0xd8, 0xf1, 0x85, 0x1a, 0x79, 0x71, 0x57, 0x23, 0x55, 0x05, 0xed, 0xf9, 0x02, 0xaf, + 0xc3, 0x52, 0x1c, 0x3e, 0x71, 0x03, 0x2a, 0xe2, 0x5e, 0xbb, 0x1a, 0x01, 0x05, 0x6e, 0x4b, 0x0c, + 0x1b, 0xa0, 0xf3, 0x99, 0xa7, 0x3a, 0x21, 0x22, 0x97, 0xf8, 0xff, 0x50, 0xe6, 0x93, 0x29, 0xf3, + 0xa8, 0x1a, 0xee, 0x3d, 0x92, 0xec, 0xf0, 0x07, 0xd0, 0xfc, 0x81, 0x45, 0xc1, 0x58, 0x4c, 0x23, + 0xc6, 0xa7, 0x81, 0x7b, 0xac, 0x06, 0x8d, 0x48, 0x43, 0xa2, 0xa3, 0x14, 0xc4, 0x1f, 0x26, 0x69, + 0xb9, 0xae, 0xb2, 0xd2, 0x85, 0x48, 0x5d, 0xe2, 0x8f, 0x52, 0x6d, 0x1f, 0x83, 0xb1, 0x90, 0x17, + 0x0b, 0xac, 0x28, 0x81, 0x88, 0x34, 0xb3, 0xcc, 0x58, 0x64, 0x07, 0x9a, 0x3e, 0x3b, 0xa5, 0xc2, + 0x39, 0x63, 0x63, 0x1e, 0x52, 0x9f, 0x9b, 0xd5, 0x37, 0x5f, 0xe5, 0xee, 0x6c, 0xf2, 0x9c, 0x89, + 0x61, 0x48, 0xfd, 0xe4, 0x0b, 0x6d, 0xa4, 0x0c, 0x89, 0x71, 0xfc, 0x11, 0x2c, 0x67, 0x25, 0x8e, + 0x99, 0x2b, 0x28, 0x37, 0x6b, 0x2d, 0xbd, 0x8d, 0x49, 0x56, 0xf9, 0x1b, 0x85, 0xde, 0x4a, 0x54, + 0xda, 0xb8, 0x09, 0x2d, 0xbd, 0x8d, 0xf2, 0x44, 0x25, 0x4c, 0x3e, 0x6f, 0xcd, 0x30, 0xe0, 0xce, + 0x82, 0xa8, 0xa5, 0xff, 0x16, 0x95, 0x32, 0x32, 0x51, 0x59, 0x89, 0x44, 0x54, 0x3d, 0x16, 0x95, + 0xc2, 0xb9, 0xa8, 0x2c, 0x31, 0x11, 0xd5, 0x88, 0x45, 0xa5, 0x70, 0x22, 0x6a, 0x0b, 0x20, 0x62, + 0x9c, 0x89, 0xf1, 0x54, 0xde, 0x7c, 0x53, 0x3d, 0x02, 0xf7, 0xff, 0xe5, 0x19, 0xdb, 0x20, 0x32, + 0x6b, 0xd7, 0xf1, 0x05, 0xa9, 0x45, 0xe9, 0xf2, 0x8e, 0xff, 0x96, 0xef, 0xfa, 0xef, 0x21, 0xd4, + 0x32, 0xea, 0xed, 0xef, 0xb9, 0x02, 0xfa, 0xb3, 0xde, 0xd0, 0x40, 0xb8, 0x0c, 0x85, 0xc1, 0xbe, + 0x51, 0xc8, 0xbf, 0x69, 0x7d, 0xb5, 0xf8, 0xf3, 0x6f, 0x16, 0xea, 0x56, 0xa0, 0xa4, 0xc4, 0x77, + 0xeb, 0x00, 0xf9, 0xec, 0xed, 0x2d, 0x80, 0xfc, 0xa2, 0xa4, 0xfd, 0x82, 0x93, 0x13, 0xce, 0x62, + 0x3f, 0xdf, 0x23, 0xc9, 0x4e, 0xe2, 0x2e, 0xf3, 0x4f, 0xc5, 0x54, 0xd9, 0xb8, 0x41, 0x92, 0x5d, + 0xf7, 0xeb, 0xcb, 0x6b, 0x4b, 0x7b, 0x79, 0x6d, 0x69, 0xaf, 0xaf, 0x2d, 0xf4, 0xe3, 0xdc, 0x42, + 0xbf, 0xcf, 0x2d, 0x74, 0x31, 0xb7, 0xd0, 0xe5, 0xdc, 0x42, 0x7f, 0xcd, 0x2d, 0xf4, 0x6a, 0x6e, + 0x69, 0xaf, 0xe7, 0x16, 0xfa, 0xe5, 0xc6, 0xd2, 0x2e, 0x6f, 0x2c, 0xed, 0xe5, 0x8d, 0xa5, 0x7d, + 0x97, 0xfd, 0x14, 0x1c, 0x95, 0xd5, 0x5f, 0xc0, 0xe7, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x4b, + 0xb6, 0xdb, 0xd4, 0x35, 0x08, 0x00, 0x00, } func (x WriteRequest_SourceEnum) String() string { @@ -570,6 +924,13 @@ func (x MetricMetadata_MetricType) String() string { } return strconv.Itoa(int(x)) } +func (x Histogram_ResetHint) String() string { + s, ok := Histogram_ResetHint_name[int32(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} func (this *WriteRequest) Equal(that interface{}) bool { if that == nil { return this == nil @@ -677,6 +1038,14 @@ func (this *TimeSeries) Equal(that interface{}) bool { return false } } + if len(this.Histograms) != len(that1.Histograms) { + return false + } + for i := range this.Histograms { + if !this.Histograms[i].Equal(&that1.Histograms[i]) { + return false + } + } return true } func (this *LabelPair) Equal(that interface{}) bool { @@ -830,71 +1199,303 @@ func (this *Exemplar) Equal(that interface{}) bool { } return true } -func (this *WriteRequest) GoString() string { - if this == nil { - return "nil" +func (this *Histogram) Equal(that interface{}) bool { + if that == nil { + return this == nil } - s := make([]string, 0, 8) - s = append(s, "&cortexpb.WriteRequest{") - s = append(s, "Timeseries: "+fmt.Sprintf("%#v", this.Timeseries)+",\n") - s = append(s, "Source: "+fmt.Sprintf("%#v", this.Source)+",\n") - if this.Metadata != nil { - s = append(s, "Metadata: "+fmt.Sprintf("%#v", this.Metadata)+",\n") + + that1, ok := that.(*Histogram) + if !ok { + that2, ok := that.(Histogram) + if ok { + that1 = &that2 + } else { + return false + } } - s = append(s, "SkipLabelNameValidation: "+fmt.Sprintf("%#v", this.SkipLabelNameValidation)+",\n") - s = append(s, "}") - return strings.Join(s, "") -} -func (this *WriteResponse) GoString() string { - if this == nil { - return "nil" + if that1 == nil { + return this == nil + } else if this == nil { + return false } - s := make([]string, 0, 4) - s = append(s, "&cortexpb.WriteResponse{") - s = append(s, "}") - return strings.Join(s, "") -} -func (this *TimeSeries) GoString() string { - if this == nil { - return "nil" + if that1.Count == nil { + if this.Count != nil { + return false + } + } else if this.Count == nil { + return false + } else if !this.Count.Equal(that1.Count) { + return false } - s := make([]string, 0, 7) - s = append(s, "&cortexpb.TimeSeries{") - s = append(s, "Labels: "+fmt.Sprintf("%#v", this.Labels)+",\n") - if this.Samples != nil { - vs := make([]*Sample, len(this.Samples)) - for i := range vs { - vs[i] = &this.Samples[i] + if this.Sum != that1.Sum { + return false + } + if this.Schema != that1.Schema { + return false + } + if this.ZeroThreshold != that1.ZeroThreshold { + return false + } + if that1.ZeroCount == nil { + if this.ZeroCount != nil { + return false } - s = append(s, "Samples: "+fmt.Sprintf("%#v", vs)+",\n") + } else if this.ZeroCount == nil { + return false + } else if !this.ZeroCount.Equal(that1.ZeroCount) { + return false } - if this.Exemplars != nil { - vs := make([]*Exemplar, len(this.Exemplars)) - for i := range vs { - vs[i] = &this.Exemplars[i] + if len(this.NegativeSpans) != len(that1.NegativeSpans) { + return false + } + for i := range this.NegativeSpans { + if !this.NegativeSpans[i].Equal(&that1.NegativeSpans[i]) { + return false } - s = append(s, "Exemplars: "+fmt.Sprintf("%#v", vs)+",\n") } - s = append(s, "}") - return strings.Join(s, "") -} -func (this *LabelPair) GoString() string { - if this == nil { - return "nil" + if len(this.NegativeDeltas) != len(that1.NegativeDeltas) { + return false } - s := make([]string, 0, 6) - s = append(s, "&cortexpb.LabelPair{") - s = append(s, "Name: "+fmt.Sprintf("%#v", this.Name)+",\n") - s = append(s, "Value: "+fmt.Sprintf("%#v", this.Value)+",\n") - s = append(s, "}") - return strings.Join(s, "") -} -func (this *Sample) GoString() string { - if this == nil { - return "nil" + for i := range this.NegativeDeltas { + if this.NegativeDeltas[i] != that1.NegativeDeltas[i] { + return false + } } - s := make([]string, 0, 6) - s = append(s, "&cortexpb.Sample{") + if len(this.NegativeCounts) != len(that1.NegativeCounts) { + return false + } + for i := range this.NegativeCounts { + if this.NegativeCounts[i] != that1.NegativeCounts[i] { + return false + } + } + if len(this.PositiveSpans) != len(that1.PositiveSpans) { + return false + } + for i := range this.PositiveSpans { + if !this.PositiveSpans[i].Equal(&that1.PositiveSpans[i]) { + return false + } + } + if len(this.PositiveDeltas) != len(that1.PositiveDeltas) { + return false + } + for i := range this.PositiveDeltas { + if this.PositiveDeltas[i] != that1.PositiveDeltas[i] { + return false + } + } + if len(this.PositiveCounts) != len(that1.PositiveCounts) { + return false + } + for i := range this.PositiveCounts { + if this.PositiveCounts[i] != that1.PositiveCounts[i] { + return false + } + } + if this.ResetHint != that1.ResetHint { + return false + } + if this.TimestampMs != that1.TimestampMs { + return false + } + return true +} +func (this *Histogram_CountInt) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Histogram_CountInt) + if !ok { + that2, ok := that.(Histogram_CountInt) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.CountInt != that1.CountInt { + return false + } + return true +} +func (this *Histogram_CountFloat) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Histogram_CountFloat) + if !ok { + that2, ok := that.(Histogram_CountFloat) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.CountFloat != that1.CountFloat { + return false + } + return true +} +func (this *Histogram_ZeroCountInt) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Histogram_ZeroCountInt) + if !ok { + that2, ok := that.(Histogram_ZeroCountInt) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.ZeroCountInt != that1.ZeroCountInt { + return false + } + return true +} +func (this *Histogram_ZeroCountFloat) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Histogram_ZeroCountFloat) + if !ok { + that2, ok := that.(Histogram_ZeroCountFloat) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.ZeroCountFloat != that1.ZeroCountFloat { + return false + } + return true +} +func (this *BucketSpan) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*BucketSpan) + if !ok { + that2, ok := that.(BucketSpan) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Offset != that1.Offset { + return false + } + if this.Length != that1.Length { + return false + } + return true +} +func (this *WriteRequest) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 8) + s = append(s, "&cortexpb.WriteRequest{") + s = append(s, "Timeseries: "+fmt.Sprintf("%#v", this.Timeseries)+",\n") + s = append(s, "Source: "+fmt.Sprintf("%#v", this.Source)+",\n") + if this.Metadata != nil { + s = append(s, "Metadata: "+fmt.Sprintf("%#v", this.Metadata)+",\n") + } + s = append(s, "SkipLabelNameValidation: "+fmt.Sprintf("%#v", this.SkipLabelNameValidation)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} +func (this *WriteResponse) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 4) + s = append(s, "&cortexpb.WriteResponse{") + s = append(s, "}") + return strings.Join(s, "") +} +func (this *TimeSeries) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 8) + s = append(s, "&cortexpb.TimeSeries{") + s = append(s, "Labels: "+fmt.Sprintf("%#v", this.Labels)+",\n") + if this.Samples != nil { + vs := make([]*Sample, len(this.Samples)) + for i := range vs { + vs[i] = &this.Samples[i] + } + s = append(s, "Samples: "+fmt.Sprintf("%#v", vs)+",\n") + } + if this.Exemplars != nil { + vs := make([]*Exemplar, len(this.Exemplars)) + for i := range vs { + vs[i] = &this.Exemplars[i] + } + s = append(s, "Exemplars: "+fmt.Sprintf("%#v", vs)+",\n") + } + if this.Histograms != nil { + vs := make([]*Histogram, len(this.Histograms)) + for i := range vs { + vs[i] = &this.Histograms[i] + } + s = append(s, "Histograms: "+fmt.Sprintf("%#v", vs)+",\n") + } + s = append(s, "}") + return strings.Join(s, "") +} +func (this *LabelPair) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 6) + s = append(s, "&cortexpb.LabelPair{") + s = append(s, "Name: "+fmt.Sprintf("%#v", this.Name)+",\n") + s = append(s, "Value: "+fmt.Sprintf("%#v", this.Value)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} +func (this *Sample) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 6) + s = append(s, "&cortexpb.Sample{") s = append(s, "Value: "+fmt.Sprintf("%#v", this.Value)+",\n") s = append(s, "TimestampMs: "+fmt.Sprintf("%#v", this.TimestampMs)+",\n") s = append(s, "}") @@ -935,6 +1536,87 @@ func (this *Exemplar) GoString() string { s = append(s, "}") return strings.Join(s, "") } +func (this *Histogram) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 19) + s = append(s, "&cortexpb.Histogram{") + if this.Count != nil { + s = append(s, "Count: "+fmt.Sprintf("%#v", this.Count)+",\n") + } + s = append(s, "Sum: "+fmt.Sprintf("%#v", this.Sum)+",\n") + s = append(s, "Schema: "+fmt.Sprintf("%#v", this.Schema)+",\n") + s = append(s, "ZeroThreshold: "+fmt.Sprintf("%#v", this.ZeroThreshold)+",\n") + if this.ZeroCount != nil { + s = append(s, "ZeroCount: "+fmt.Sprintf("%#v", this.ZeroCount)+",\n") + } + if this.NegativeSpans != nil { + vs := make([]*BucketSpan, len(this.NegativeSpans)) + for i := range vs { + vs[i] = &this.NegativeSpans[i] + } + s = append(s, "NegativeSpans: "+fmt.Sprintf("%#v", vs)+",\n") + } + s = append(s, "NegativeDeltas: "+fmt.Sprintf("%#v", this.NegativeDeltas)+",\n") + s = append(s, "NegativeCounts: "+fmt.Sprintf("%#v", this.NegativeCounts)+",\n") + if this.PositiveSpans != nil { + vs := make([]*BucketSpan, len(this.PositiveSpans)) + for i := range vs { + vs[i] = &this.PositiveSpans[i] + } + s = append(s, "PositiveSpans: "+fmt.Sprintf("%#v", vs)+",\n") + } + s = append(s, "PositiveDeltas: "+fmt.Sprintf("%#v", this.PositiveDeltas)+",\n") + s = append(s, "PositiveCounts: "+fmt.Sprintf("%#v", this.PositiveCounts)+",\n") + s = append(s, "ResetHint: "+fmt.Sprintf("%#v", this.ResetHint)+",\n") + s = append(s, "TimestampMs: "+fmt.Sprintf("%#v", this.TimestampMs)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} +func (this *Histogram_CountInt) GoString() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&cortexpb.Histogram_CountInt{` + + `CountInt:` + fmt.Sprintf("%#v", this.CountInt) + `}`}, ", ") + return s +} +func (this *Histogram_CountFloat) GoString() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&cortexpb.Histogram_CountFloat{` + + `CountFloat:` + fmt.Sprintf("%#v", this.CountFloat) + `}`}, ", ") + return s +} +func (this *Histogram_ZeroCountInt) GoString() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&cortexpb.Histogram_ZeroCountInt{` + + `ZeroCountInt:` + fmt.Sprintf("%#v", this.ZeroCountInt) + `}`}, ", ") + return s +} +func (this *Histogram_ZeroCountFloat) GoString() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&cortexpb.Histogram_ZeroCountFloat{` + + `ZeroCountFloat:` + fmt.Sprintf("%#v", this.ZeroCountFloat) + `}`}, ", ") + return s +} +func (this *BucketSpan) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 6) + s = append(s, "&cortexpb.BucketSpan{") + s = append(s, "Offset: "+fmt.Sprintf("%#v", this.Offset)+",\n") + s = append(s, "Length: "+fmt.Sprintf("%#v", this.Length)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} func valueToGoStringCortex(v interface{}, typ string) string { rv := reflect.ValueOf(v) if rv.IsNil() { @@ -1054,6 +1736,20 @@ func (m *TimeSeries) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Histograms) > 0 { + for iNdEx := len(m.Histograms) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Histograms[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCortex(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } if len(m.Exemplars) > 0 { for iNdEx := len(m.Exemplars) - 1; iNdEx >= 0; iNdEx-- { { @@ -1304,13 +2000,246 @@ func (m *Exemplar) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func encodeVarintCortex(dAtA []byte, offset int, v uint64) int { - offset -= sovCortex(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *Histogram) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Histogram) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Histogram) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TimestampMs != 0 { + i = encodeVarintCortex(dAtA, i, uint64(m.TimestampMs)) + i-- + dAtA[i] = 0x78 + } + if m.ResetHint != 0 { + i = encodeVarintCortex(dAtA, i, uint64(m.ResetHint)) + i-- + dAtA[i] = 0x70 + } + if len(m.PositiveCounts) > 0 { + for iNdEx := len(m.PositiveCounts) - 1; iNdEx >= 0; iNdEx-- { + f1 := math.Float64bits(float64(m.PositiveCounts[iNdEx])) + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(f1)) + } + i = encodeVarintCortex(dAtA, i, uint64(len(m.PositiveCounts)*8)) + i-- + dAtA[i] = 0x6a + } + if len(m.PositiveDeltas) > 0 { + var j2 int + dAtA4 := make([]byte, len(m.PositiveDeltas)*10) + for _, num := range m.PositiveDeltas { + x3 := (uint64(num) << 1) ^ uint64((num >> 63)) + for x3 >= 1<<7 { + dAtA4[j2] = uint8(uint64(x3)&0x7f | 0x80) + j2++ + x3 >>= 7 + } + dAtA4[j2] = uint8(x3) + j2++ + } + i -= j2 + copy(dAtA[i:], dAtA4[:j2]) + i = encodeVarintCortex(dAtA, i, uint64(j2)) + i-- + dAtA[i] = 0x62 + } + if len(m.PositiveSpans) > 0 { + for iNdEx := len(m.PositiveSpans) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PositiveSpans[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCortex(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + } + } + if len(m.NegativeCounts) > 0 { + for iNdEx := len(m.NegativeCounts) - 1; iNdEx >= 0; iNdEx-- { + f5 := math.Float64bits(float64(m.NegativeCounts[iNdEx])) + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(f5)) + } + i = encodeVarintCortex(dAtA, i, uint64(len(m.NegativeCounts)*8)) + i-- + dAtA[i] = 0x52 + } + if len(m.NegativeDeltas) > 0 { + var j6 int + dAtA8 := make([]byte, len(m.NegativeDeltas)*10) + for _, num := range m.NegativeDeltas { + x7 := (uint64(num) << 1) ^ uint64((num >> 63)) + for x7 >= 1<<7 { + dAtA8[j6] = uint8(uint64(x7)&0x7f | 0x80) + j6++ + x7 >>= 7 + } + dAtA8[j6] = uint8(x7) + j6++ + } + i -= j6 + copy(dAtA[i:], dAtA8[:j6]) + i = encodeVarintCortex(dAtA, i, uint64(j6)) + i-- + dAtA[i] = 0x4a + } + if len(m.NegativeSpans) > 0 { + for iNdEx := len(m.NegativeSpans) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.NegativeSpans[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCortex(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } + if m.ZeroCount != nil { + { + size := m.ZeroCount.Size() + i -= size + if _, err := m.ZeroCount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + if m.ZeroThreshold != 0 { + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.ZeroThreshold)))) + i-- + dAtA[i] = 0x29 + } + if m.Schema != 0 { + i = encodeVarintCortex(dAtA, i, uint64((uint32(m.Schema)<<1)^uint32((m.Schema>>31)))) + i-- + dAtA[i] = 0x20 + } + if m.Sum != 0 { + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Sum)))) + i-- + dAtA[i] = 0x19 + } + if m.Count != nil { + { + size := m.Count.Size() + i -= size + if _, err := m.Count.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *Histogram_CountInt) MarshalTo(dAtA []byte) (int, error) { + return m.MarshalToSizedBuffer(dAtA[:m.Size()]) +} + +func (m *Histogram_CountInt) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + i = encodeVarintCortex(dAtA, i, uint64(m.CountInt)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} +func (m *Histogram_CountFloat) MarshalTo(dAtA []byte) (int, error) { + return m.MarshalToSizedBuffer(dAtA[:m.Size()]) +} + +func (m *Histogram_CountFloat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.CountFloat)))) + i-- + dAtA[i] = 0x11 + return len(dAtA) - i, nil +} +func (m *Histogram_ZeroCountInt) MarshalTo(dAtA []byte) (int, error) { + return m.MarshalToSizedBuffer(dAtA[:m.Size()]) +} + +func (m *Histogram_ZeroCountInt) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + i = encodeVarintCortex(dAtA, i, uint64(m.ZeroCountInt)) + i-- + dAtA[i] = 0x30 + return len(dAtA) - i, nil +} +func (m *Histogram_ZeroCountFloat) MarshalTo(dAtA []byte) (int, error) { + return m.MarshalToSizedBuffer(dAtA[:m.Size()]) +} + +func (m *Histogram_ZeroCountFloat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.ZeroCountFloat)))) + i-- + dAtA[i] = 0x39 + return len(dAtA) - i, nil +} +func (m *BucketSpan) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BucketSpan) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BucketSpan) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Length != 0 { + i = encodeVarintCortex(dAtA, i, uint64(m.Length)) + i-- + dAtA[i] = 0x10 + } + if m.Offset != 0 { + i = encodeVarintCortex(dAtA, i, uint64((uint32(m.Offset)<<1)^uint32((m.Offset>>31)))) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintCortex(dAtA []byte, offset int, v uint64) int { + offset -= sovCortex(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ } dAtA[offset] = uint8(v) return base @@ -1375,6 +2304,12 @@ func (m *TimeSeries) Size() (n int) { n += 1 + l + sovCortex(uint64(l)) } } + if len(m.Histograms) > 0 { + for _, e := range m.Histograms { + l = e.Size() + n += 1 + l + sovCortex(uint64(l)) + } + } return n } @@ -1470,6 +2405,119 @@ func (m *Exemplar) Size() (n int) { return n } +func (m *Histogram) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Count != nil { + n += m.Count.Size() + } + if m.Sum != 0 { + n += 9 + } + if m.Schema != 0 { + n += 1 + sozCortex(uint64(m.Schema)) + } + if m.ZeroThreshold != 0 { + n += 9 + } + if m.ZeroCount != nil { + n += m.ZeroCount.Size() + } + if len(m.NegativeSpans) > 0 { + for _, e := range m.NegativeSpans { + l = e.Size() + n += 1 + l + sovCortex(uint64(l)) + } + } + if len(m.NegativeDeltas) > 0 { + l = 0 + for _, e := range m.NegativeDeltas { + l += sozCortex(uint64(e)) + } + n += 1 + sovCortex(uint64(l)) + l + } + if len(m.NegativeCounts) > 0 { + n += 1 + sovCortex(uint64(len(m.NegativeCounts)*8)) + len(m.NegativeCounts)*8 + } + if len(m.PositiveSpans) > 0 { + for _, e := range m.PositiveSpans { + l = e.Size() + n += 1 + l + sovCortex(uint64(l)) + } + } + if len(m.PositiveDeltas) > 0 { + l = 0 + for _, e := range m.PositiveDeltas { + l += sozCortex(uint64(e)) + } + n += 1 + sovCortex(uint64(l)) + l + } + if len(m.PositiveCounts) > 0 { + n += 1 + sovCortex(uint64(len(m.PositiveCounts)*8)) + len(m.PositiveCounts)*8 + } + if m.ResetHint != 0 { + n += 1 + sovCortex(uint64(m.ResetHint)) + } + if m.TimestampMs != 0 { + n += 1 + sovCortex(uint64(m.TimestampMs)) + } + return n +} + +func (m *Histogram_CountInt) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovCortex(uint64(m.CountInt)) + return n +} +func (m *Histogram_CountFloat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 9 + return n +} +func (m *Histogram_ZeroCountInt) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovCortex(uint64(m.ZeroCountInt)) + return n +} +func (m *Histogram_ZeroCountFloat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 9 + return n +} +func (m *BucketSpan) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Offset != 0 { + n += 1 + sozCortex(uint64(m.Offset)) + } + if m.Length != 0 { + n += 1 + sovCortex(uint64(m.Length)) + } + return n +} + func sovCortex(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1517,10 +2565,16 @@ func (this *TimeSeries) String() string { repeatedStringForExemplars += strings.Replace(strings.Replace(f.String(), "Exemplar", "Exemplar", 1), `&`, ``, 1) + "," } repeatedStringForExemplars += "}" + repeatedStringForHistograms := "[]Histogram{" + for _, f := range this.Histograms { + repeatedStringForHistograms += strings.Replace(strings.Replace(f.String(), "Histogram", "Histogram", 1), `&`, ``, 1) + "," + } + repeatedStringForHistograms += "}" s := strings.Join([]string{`&TimeSeries{`, `Labels:` + fmt.Sprintf("%v", this.Labels) + `,`, `Samples:` + repeatedStringForSamples + `,`, `Exemplars:` + repeatedStringForExemplars + `,`, + `Histograms:` + repeatedStringForHistograms + `,`, `}`, }, "") return s @@ -1582,6 +2636,89 @@ func (this *Exemplar) String() string { }, "") return s } +func (this *Histogram) String() string { + if this == nil { + return "nil" + } + repeatedStringForNegativeSpans := "[]BucketSpan{" + for _, f := range this.NegativeSpans { + repeatedStringForNegativeSpans += strings.Replace(strings.Replace(f.String(), "BucketSpan", "BucketSpan", 1), `&`, ``, 1) + "," + } + repeatedStringForNegativeSpans += "}" + repeatedStringForPositiveSpans := "[]BucketSpan{" + for _, f := range this.PositiveSpans { + repeatedStringForPositiveSpans += strings.Replace(strings.Replace(f.String(), "BucketSpan", "BucketSpan", 1), `&`, ``, 1) + "," + } + repeatedStringForPositiveSpans += "}" + s := strings.Join([]string{`&Histogram{`, + `Count:` + fmt.Sprintf("%v", this.Count) + `,`, + `Sum:` + fmt.Sprintf("%v", this.Sum) + `,`, + `Schema:` + fmt.Sprintf("%v", this.Schema) + `,`, + `ZeroThreshold:` + fmt.Sprintf("%v", this.ZeroThreshold) + `,`, + `ZeroCount:` + fmt.Sprintf("%v", this.ZeroCount) + `,`, + `NegativeSpans:` + repeatedStringForNegativeSpans + `,`, + `NegativeDeltas:` + fmt.Sprintf("%v", this.NegativeDeltas) + `,`, + `NegativeCounts:` + fmt.Sprintf("%v", this.NegativeCounts) + `,`, + `PositiveSpans:` + repeatedStringForPositiveSpans + `,`, + `PositiveDeltas:` + fmt.Sprintf("%v", this.PositiveDeltas) + `,`, + `PositiveCounts:` + fmt.Sprintf("%v", this.PositiveCounts) + `,`, + `ResetHint:` + fmt.Sprintf("%v", this.ResetHint) + `,`, + `TimestampMs:` + fmt.Sprintf("%v", this.TimestampMs) + `,`, + `}`, + }, "") + return s +} +func (this *Histogram_CountInt) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Histogram_CountInt{`, + `CountInt:` + fmt.Sprintf("%v", this.CountInt) + `,`, + `}`, + }, "") + return s +} +func (this *Histogram_CountFloat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Histogram_CountFloat{`, + `CountFloat:` + fmt.Sprintf("%v", this.CountFloat) + `,`, + `}`, + }, "") + return s +} +func (this *Histogram_ZeroCountInt) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Histogram_ZeroCountInt{`, + `ZeroCountInt:` + fmt.Sprintf("%v", this.ZeroCountInt) + `,`, + `}`, + }, "") + return s +} +func (this *Histogram_ZeroCountFloat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Histogram_ZeroCountFloat{`, + `ZeroCountFloat:` + fmt.Sprintf("%v", this.ZeroCountFloat) + `,`, + `}`, + }, "") + return s +} +func (this *BucketSpan) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&BucketSpan{`, + `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`, + `Length:` + fmt.Sprintf("%v", this.Length) + `,`, + `}`, + }, "") + return s +} func valueToStringCortex(v interface{}) string { rv := reflect.ValueOf(v) if rv.IsNil() { @@ -1934,19 +3071,53 @@ func (m *TimeSeries) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCortex(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthCortex - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthCortex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Histograms", wireType) } - if (iNdEx + skippy) > l { + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCortex + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCortex + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Histograms = append(m.Histograms, Histogram{}) + if err := m.Histograms[len(m.Histograms)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCortex(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCortex + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCortex + } + if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } iNdEx += skippy @@ -2534,6 +3705,627 @@ func (m *Exemplar) Unmarshal(dAtA []byte) error { } return nil } +func (m *Histogram) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Histogram: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Histogram: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CountInt", wireType) + } + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Count = &Histogram_CountInt{v} + case 2: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field CountFloat", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.Count = &Histogram_CountFloat{float64(math.Float64frombits(v))} + case 3: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field Sum", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.Sum = float64(math.Float64frombits(v)) + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Schema", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + v = int32((uint32(v) >> 1) ^ uint32(((v&1)<<31)>>31)) + m.Schema = v + case 5: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field ZeroThreshold", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.ZeroThreshold = float64(math.Float64frombits(v)) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ZeroCountInt", wireType) + } + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ZeroCount = &Histogram_ZeroCountInt{v} + case 7: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field ZeroCountFloat", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.ZeroCount = &Histogram_ZeroCountFloat{float64(math.Float64frombits(v))} + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NegativeSpans", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCortex + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCortex + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NegativeSpans = append(m.NegativeSpans, BucketSpan{}) + if err := m.NegativeSpans[len(m.NegativeSpans)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + v = (v >> 1) ^ uint64((int64(v&1)<<63)>>63) + m.NegativeDeltas = append(m.NegativeDeltas, int64(v)) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthCortex + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthCortex + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.NegativeDeltas) == 0 { + m.NegativeDeltas = make([]int64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + v = (v >> 1) ^ uint64((int64(v&1)<<63)>>63) + m.NegativeDeltas = append(m.NegativeDeltas, int64(v)) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field NegativeDeltas", wireType) + } + case 10: + 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.NegativeCounts = append(m.NegativeCounts, v2) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthCortex + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthCortex + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + elementCount = packedLen / 8 + if elementCount != 0 && len(m.NegativeCounts) == 0 { + m.NegativeCounts = 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.NegativeCounts = append(m.NegativeCounts, v2) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field NegativeCounts", wireType) + } + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PositiveSpans", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCortex + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCortex + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PositiveSpans = append(m.PositiveSpans, BucketSpan{}) + if err := m.PositiveSpans[len(m.PositiveSpans)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 12: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + v = (v >> 1) ^ uint64((int64(v&1)<<63)>>63) + m.PositiveDeltas = append(m.PositiveDeltas, int64(v)) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthCortex + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthCortex + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.PositiveDeltas) == 0 { + m.PositiveDeltas = make([]int64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + v = (v >> 1) ^ uint64((int64(v&1)<<63)>>63) + m.PositiveDeltas = append(m.PositiveDeltas, int64(v)) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field PositiveDeltas", wireType) + } + case 13: + 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.PositiveCounts = append(m.PositiveCounts, v2) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthCortex + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthCortex + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + elementCount = packedLen / 8 + if elementCount != 0 && len(m.PositiveCounts) == 0 { + m.PositiveCounts = 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.PositiveCounts = append(m.PositiveCounts, v2) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field PositiveCounts", wireType) + } + case 14: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ResetHint", wireType) + } + m.ResetHint = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ResetHint |= Histogram_ResetHint(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 15: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TimestampMs", wireType) + } + m.TimestampMs = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TimestampMs |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipCortex(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCortex + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCortex + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BucketSpan) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BucketSpan: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BucketSpan: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + v = int32((uint32(v) >> 1) ^ uint32(((v&1)<<31)>>31)) + m.Offset = v + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Length", wireType) + } + m.Length = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCortex + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Length |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipCortex(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCortex + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCortex + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipCortex(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/pkg/cortexpb/cortex.proto b/pkg/cortexpb/cortex.proto index 4d683fbcc0..cedb173183 100644 --- a/pkg/cortexpb/cortex.proto +++ b/pkg/cortexpb/cortex.proto @@ -28,6 +28,7 @@ message TimeSeries { // Sorted by time, oldest sample first. repeated Sample samples = 2 [(gogoproto.nullable) = false]; repeated Exemplar exemplars = 3 [(gogoproto.nullable) = false]; + repeated Histogram histograms = 4 [(gogoproto.nullable) = false]; } message LabelPair { @@ -68,3 +69,69 @@ message Exemplar { double value = 2; int64 timestamp_ms = 3; } + +// A native histogram, also known as a sparse histogram. +// Original design doc: +// https://docs.google.com/document/d/1cLNv3aufPZb3fNfaJgdaRBZsInZKKIHo9E6HinJVbpM/edit +// The appendix of this design doc also explains the concept of float +// histograms. This Histogram message can represent both, the usual +// integer histogram as well as a float histogram. +message Histogram { + enum ResetHint { + option (gogoproto.goproto_enum_prefix) = true; + UNKNOWN = 0; // Need to test for a counter reset explicitly. + YES = 1; // This is the 1st histogram after a counter reset. + NO = 2; // There was no counter reset between this and the previous Histogram. + GAUGE = 3; // This is a gauge histogram where counter resets don't happen. + } + + oneof count { // Count of observations in the histogram. + uint64 count_int = 1; + double count_float = 2; + } + double sum = 3; // Sum of observations in the histogram. + // The schema defines the bucket schema. Currently, valid numbers + // are -4 <= n <= 8. They are all for base-2 bucket schemas, where 1 + // 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 + // bucket boundary is the previous boundary times 2^(2^-n). In the + // future, more bucket schemas may be added using numbers < -4 or > + // 8. + sint32 schema = 4; + double zero_threshold = 5; // Breadth of the zero bucket. + oneof zero_count { // Count in zero bucket. + uint64 zero_count_int = 6; + double zero_count_float = 7; + } + + // Negative Buckets. + repeated BucketSpan negative_spans = 8 [(gogoproto.nullable) = false]; + // Use either "negative_deltas" or "negative_counts", the former for + // regular histograms with integer counts, the latter for float + // histograms. + 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. + + // Positive Buckets. + repeated BucketSpan positive_spans = 11 [(gogoproto.nullable) = false]; + // Use either "positive_deltas" or "positive_counts", the former for + // regular histograms with integer counts, the latter for float + // histograms. + 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. + + ResetHint reset_hint = 14; + // timestamp is in ms format, see model/timestamp/timestamp.go for + // conversion from time.Time to Prometheus timestamp. + int64 timestamp_ms = 15; +} + +// A BucketSpan defines a number of consecutive buckets with their +// offset. Logically, it would be more straightforward to include the +// bucket counts in the Span. However, the protobuf representation is +// more compact in the way the data is structured here (with all the +// buckets in a single array separate from the Spans). +message BucketSpan { + sint32 offset = 1; // Gap to previous span, or starting point for 1st span (which can be negative). + uint32 length = 2; // Length of consecutive buckets. +} \ No newline at end of file diff --git a/pkg/cortexpb/timeseries.go b/pkg/cortexpb/timeseries.go index 5a2fcaf85b..da1eff65df 100644 --- a/pkg/cortexpb/timeseries.go +++ b/pkg/cortexpb/timeseries.go @@ -340,6 +340,12 @@ func ReuseTimeseries(ts *TimeSeries) { ts.Exemplars[i].Labels[j].Value = "" } } + + for i := range ts.Histograms { + ts.Histograms[i].Reset() + } + ts.Exemplars = ts.Exemplars[:0] + ts.Histograms = ts.Histograms[:0] timeSeriesPool.Put(ts) } diff --git a/pkg/distributor/distributor_test.go b/pkg/distributor/distributor_test.go index 3df8459071..7788239b86 100644 --- a/pkg/distributor/distributor_test.go +++ b/pkg/distributor/distributor_test.go @@ -1931,7 +1931,7 @@ func BenchmarkDistributor_Push(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { - _, err := distributor.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API)) + _, err := distributor.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API)) if testData.expectedErr == "" && err != nil { b.Fatalf("no error expected but got %v", err) @@ -2264,7 +2264,7 @@ func BenchmarkDistributor_MetricsForLabelMatchers(b *testing.B) { // Prepare the series to remote write before starting the benchmark. metrics, samples := testData.prepareSeries() - if _, err := ds[0].Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API)); err != nil { + if _, err := ds[0].Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API)); err != nil { b.Fatalf("error pushing to distributor %v", err) } @@ -2373,7 +2373,7 @@ func mockWriteRequest(lbls []labels.Labels, value float64, timestampMs int64) *c } } - return cortexpb.ToWriteRequest(lbls, samples, nil, cortexpb.API) + return cortexpb.ToWriteRequest(lbls, samples, nil, nil, cortexpb.API) } type prepConfig struct { @@ -3097,7 +3097,7 @@ func TestDistributorValidation(t *testing.T) { limits: &limits, }) - _, err := ds[0].Push(ctx, cortexpb.ToWriteRequest(tc.labels, tc.samples, tc.metadata, cortexpb.API)) + _, err := ds[0].Push(ctx, cortexpb.ToWriteRequest(tc.labels, tc.samples, tc.metadata, nil, cortexpb.API)) require.Equal(t, tc.err, err) }) } diff --git a/pkg/ingester/ingester.go b/pkg/ingester/ingester.go index 8417bcd019..263e5c4cc5 100644 --- a/pkg/ingester/ingester.go +++ b/pkg/ingester/ingester.go @@ -1001,6 +1001,7 @@ func (i *Ingester) Push(ctx context.Context, req *cortexpb.WriteRequest) (*corte newValueForTimestampCount = 0 perUserSeriesLimitCount = 0 perMetricSeriesLimitCount = 0 + nativeHistogramCount = 0 updateFirstPartial = func(errFn func() error) { if firstPartialErr == nil { @@ -1023,6 +1024,8 @@ func (i *Ingester) Push(ctx context.Context, req *cortexpb.WriteRequest) (*corte // To find out if any sample was added to this series, we keep old value. oldSucceededSamplesCount := succeededSamplesCount + nativeHistogramCount += len(ts.Histograms) + for _, s := range ts.Samples { var err error @@ -1174,6 +1177,10 @@ func (i *Ingester) Push(ctx context.Context, req *cortexpb.WriteRequest) (*corte validation.DiscardedSamples.WithLabelValues(perMetricSeriesLimit, userID).Add(float64(perMetricSeriesLimitCount)) } + if nativeHistogramCount > 0 { + validation.DiscardedSamples.WithLabelValues(nativeHistogramSample, userID).Add(float64(nativeHistogramCount)) + } + // Distributor counts both samples and metadata, so for consistency ingester does the same. i.ingestionRate.Add(int64(succeededSamplesCount + ingestedMetadata)) diff --git a/pkg/ingester/ingester_test.go b/pkg/ingester/ingester_test.go index dd40c49efd..21d7a5f35f 100644 --- a/pkg/ingester/ingester_test.go +++ b/pkg/ingester/ingester_test.go @@ -126,19 +126,19 @@ func TestIngesterUserLimitExceeded(t *testing.T) { // Append only one series and one metadata first, expect no error. ctx := user.InjectOrgID(context.Background(), userID) - _, err := ing.Push(ctx, cortexpb.ToWriteRequest([]labels.Labels{labels1}, []cortexpb.Sample{sample1}, []*cortexpb.MetricMetadata{metadata1}, cortexpb.API)) + _, err := ing.Push(ctx, cortexpb.ToWriteRequest([]labels.Labels{labels1}, []cortexpb.Sample{sample1}, []*cortexpb.MetricMetadata{metadata1}, nil, cortexpb.API)) require.NoError(t, err) testLimits := func() { // Append to two series, expect series-exceeded error. - _, err = ing.Push(ctx, cortexpb.ToWriteRequest([]labels.Labels{labels1, labels3}, []cortexpb.Sample{sample2, sample3}, nil, cortexpb.API)) + _, err = ing.Push(ctx, cortexpb.ToWriteRequest([]labels.Labels{labels1, labels3}, []cortexpb.Sample{sample2, sample3}, nil, nil, cortexpb.API)) httpResp, ok := httpgrpc.HTTPResponseFromError(err) require.True(t, ok, "returned error is not an httpgrpc response") assert.Equal(t, http.StatusBadRequest, int(httpResp.Code)) assert.Equal(t, wrapWithUser(makeLimitError(perUserSeriesLimit, ing.limiter.FormatError(userID, errMaxSeriesPerUserLimitExceeded)), userID).Error(), string(httpResp.Body)) // Append two metadata, expect no error since metadata is a best effort approach. - _, err = ing.Push(ctx, cortexpb.ToWriteRequest(nil, nil, []*cortexpb.MetricMetadata{metadata1, metadata2}, cortexpb.API)) + _, err = ing.Push(ctx, cortexpb.ToWriteRequest(nil, nil, []*cortexpb.MetricMetadata{metadata1, metadata2}, nil, cortexpb.API)) require.NoError(t, err) // Read samples back via ingester queries. @@ -248,19 +248,19 @@ func TestIngesterMetricLimitExceeded(t *testing.T) { // Append only one series and one metadata first, expect no error. ctx := user.InjectOrgID(context.Background(), userID) - _, err := ing.Push(ctx, cortexpb.ToWriteRequest([]labels.Labels{labels1}, []cortexpb.Sample{sample1}, []*cortexpb.MetricMetadata{metadata1}, cortexpb.API)) + _, err := ing.Push(ctx, cortexpb.ToWriteRequest([]labels.Labels{labels1}, []cortexpb.Sample{sample1}, []*cortexpb.MetricMetadata{metadata1}, nil, cortexpb.API)) require.NoError(t, err) testLimits := func() { // Append two series, expect series-exceeded error. - _, err = ing.Push(ctx, cortexpb.ToWriteRequest([]labels.Labels{labels1, labels3}, []cortexpb.Sample{sample2, sample3}, nil, cortexpb.API)) + _, err = ing.Push(ctx, cortexpb.ToWriteRequest([]labels.Labels{labels1, labels3}, []cortexpb.Sample{sample2, sample3}, nil, nil, cortexpb.API)) httpResp, ok := httpgrpc.HTTPResponseFromError(err) require.True(t, ok, "returned error is not an httpgrpc response") assert.Equal(t, http.StatusBadRequest, int(httpResp.Code)) assert.Equal(t, wrapWithUser(makeMetricLimitError(perMetricSeriesLimit, labels3, ing.limiter.FormatError(userID, errMaxSeriesPerMetricLimitExceeded)), userID).Error(), string(httpResp.Body)) // Append two metadata for the same metric. Drop the second one, and expect no error since metadata is a best effort approach. - _, err = ing.Push(ctx, cortexpb.ToWriteRequest(nil, nil, []*cortexpb.MetricMetadata{metadata1, metadata2}, cortexpb.API)) + _, err = ing.Push(ctx, cortexpb.ToWriteRequest(nil, nil, []*cortexpb.MetricMetadata{metadata1, metadata2}, nil, cortexpb.API)) require.NoError(t, err) // Read samples back via ingester queries. @@ -343,6 +343,56 @@ func TestIngester_Push(t *testing.T) { maxExemplars int oooTimeWindow time.Duration }{ + "should record native histogram": { + reqs: []*cortexpb.WriteRequest{ + cortexpb.ToWriteRequest( + []labels.Labels{metricLabels}, + []cortexpb.Sample{{Value: 2, TimestampMs: 10}}, + []*cortexpb.MetricMetadata{ + {MetricFamilyName: "metric_name_2", Help: "a help for metric_name_2", Unit: "", Type: cortexpb.GAUGE}, + }, + []cortexpb.Histogram{ + { + TimestampMs: 10, + }, + }, + cortexpb.API), + }, + expectedErr: nil, + expectedIngested: []cortexpb.TimeSeries{ + {Labels: metricLabelAdapters, Samples: []cortexpb.Sample{{Value: 2, TimestampMs: 10}}}, + }, + expectedMetadataIngested: []*cortexpb.MetricMetadata{ + {MetricFamilyName: "metric_name_2", Help: "a help for metric_name_2", Unit: "", Type: cortexpb.GAUGE}, + }, + additionalMetrics: []string{}, + expectedMetrics: ` + # HELP cortex_ingester_ingested_samples_total The total number of samples ingested. + # TYPE cortex_ingester_ingested_samples_total counter + cortex_ingester_ingested_samples_total 1 + # HELP cortex_ingester_ingested_samples_failures_total The total number of samples that errored on ingestion. + # TYPE cortex_ingester_ingested_samples_failures_total counter + cortex_ingester_ingested_samples_failures_total 0 + # HELP cortex_ingester_memory_users The current number of users in memory. + # TYPE cortex_ingester_memory_users gauge + cortex_ingester_memory_users 1 + # HELP cortex_ingester_memory_series The current number of series in memory. + # TYPE cortex_ingester_memory_series gauge + cortex_ingester_memory_series 1 + # HELP cortex_ingester_memory_series_created_total The total number of series that were created per user. + # TYPE cortex_ingester_memory_series_created_total counter + cortex_ingester_memory_series_created_total{user="test"} 1 + # HELP cortex_ingester_memory_series_removed_total The total number of series that were removed per user. + # TYPE cortex_ingester_memory_series_removed_total counter + cortex_ingester_memory_series_removed_total{user="test"} 0 + # HELP cortex_discarded_samples_total The total number of samples that were discarded. + # TYPE cortex_discarded_samples_total counter + cortex_discarded_samples_total{reason="native-histogram-sample",user="test"} 1 + # HELP cortex_ingester_active_series Number of currently active series per user. + # TYPE cortex_ingester_active_series gauge + cortex_ingester_active_series{user="test"} 1 + `, + }, "should succeed on valid series and metadata": { reqs: []*cortexpb.WriteRequest{ cortexpb.ToWriteRequest( @@ -351,6 +401,7 @@ func TestIngester_Push(t *testing.T) { []*cortexpb.MetricMetadata{ {MetricFamilyName: "metric_name_1", Help: "a help for metric_name_1", Unit: "", Type: cortexpb.COUNTER}, }, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{metricLabels}, @@ -358,6 +409,7 @@ func TestIngester_Push(t *testing.T) { []*cortexpb.MetricMetadata{ {MetricFamilyName: "metric_name_2", Help: "a help for metric_name_2", Unit: "", Type: cortexpb.GAUGE}, }, + nil, cortexpb.API), }, expectedErr: nil, @@ -419,6 +471,7 @@ func TestIngester_Push(t *testing.T) { []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 1, TimestampMs: 9}}, nil, + nil, cortexpb.API), { Timeseries: []cortexpb.PreallocTimeseries{ @@ -522,11 +575,13 @@ func TestIngester_Push(t *testing.T) { []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 1, TimestampMs: 9}}, nil, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 2, TimestampMs: 10}}, nil, + nil, cortexpb.API), }, expectedErr: nil, @@ -560,11 +615,13 @@ func TestIngester_Push(t *testing.T) { []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 2, TimestampMs: 10}}, nil, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 1, TimestampMs: 9}}, nil, + nil, cortexpb.API), }, expectedErr: httpgrpc.Errorf(http.StatusBadRequest, wrapWithUser(wrappedTSDBIngestErr(storage.ErrOutOfOrderSample, model.Time(9), cortexpb.FromLabelsToLabelAdapters(metricLabels)), userID).Error()), @@ -604,11 +661,13 @@ func TestIngester_Push(t *testing.T) { []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 2, TimestampMs: 1575043969}}, nil, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 1, TimestampMs: 1575043969 - (86400 * 1000)}}, nil, + nil, cortexpb.API), }, expectedErr: httpgrpc.Errorf(http.StatusBadRequest, wrapWithUser(wrappedTSDBIngestErr(storage.ErrOutOfBounds, model.Time(1575043969-(86400*1000)), cortexpb.FromLabelsToLabelAdapters(metricLabels)), userID).Error()), @@ -648,11 +707,13 @@ func TestIngester_Push(t *testing.T) { []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 2, TimestampMs: 1575043969}}, nil, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 1, TimestampMs: 1575043969 - (600 * 1000)}}, nil, + nil, cortexpb.API), }, oooTimeWindow: 5 * time.Minute, @@ -693,11 +754,13 @@ func TestIngester_Push(t *testing.T) { []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 2, TimestampMs: 1575043969}}, nil, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 1, TimestampMs: 1575043969 - (60 * 1000)}}, nil, + nil, cortexpb.API), }, oooTimeWindow: 5 * time.Minute, @@ -734,11 +797,13 @@ func TestIngester_Push(t *testing.T) { []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 2, TimestampMs: 1575043969}}, nil, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 1, TimestampMs: 1575043969}}, nil, + nil, cortexpb.API), }, expectedErr: httpgrpc.Errorf(http.StatusBadRequest, wrapWithUser(wrappedTSDBIngestErr(storage.ErrDuplicateSampleForTimestamp, model.Time(1575043969), cortexpb.FromLabelsToLabelAdapters(metricLabels)), userID).Error()), @@ -974,11 +1039,13 @@ func TestIngester_Push_ShouldCorrectlyTrackMetricsInMultiTenantScenario(t *testi []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 1, TimestampMs: 9}}, nil, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 2, TimestampMs: 10}}, nil, + nil, cortexpb.API), } @@ -1056,11 +1123,13 @@ func TestIngester_Push_DecreaseInactiveSeries(t *testing.T) { []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 1, TimestampMs: 9}}, nil, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 2, TimestampMs: 10}}, nil, + nil, cortexpb.API), } @@ -1128,6 +1197,7 @@ func benchmarkIngesterPush(b *testing.B, limits validation.Limits, errorsExpecte []labels.Labels{metricLabels}, []cortexpb.Sample{{Value: 1, TimestampMs: startTime}}, nil, + nil, cortexpb.API) _, err = ingester.Push(ctx, currTimeReq) require.NoError(b, err) @@ -1146,7 +1216,7 @@ func benchmarkIngesterPush(b *testing.B, limits validation.Limits, errorsExpecte for i := range allSamples { allSamples[i].TimestampMs = startTime + int64(iter*samples+j+1) } - _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(allLabels, allSamples, nil, cortexpb.API)) + _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(allLabels, allSamples, nil, nil, cortexpb.API)) if !errorsExpected { require.NoError(b, err) } @@ -1205,6 +1275,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { []labels.Labels{{{Name: labels.MetricName, Value: metricName}}}, []cortexpb.Sample{{Value: 1, TimestampMs: util.TimeToMillis(time.Now())}}, nil, + nil, cortexpb.API) _, err := ingester.Push(ctx, currTimeReq) require.NoError(b, err) @@ -1214,7 +1285,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { // Push out of bound samples. for n := 0; n < b.N; n++ { - _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API)) // nolint:errcheck + _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API)) // nolint:errcheck verifyErrorString(b, err, expectedErr) } @@ -1229,6 +1300,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { []labels.Labels{{{Name: labels.MetricName, Value: metricName}, {Name: "cardinality", Value: strconv.Itoa(i)}}}, []cortexpb.Sample{{Value: 1, TimestampMs: sampleTimestamp + 1}}, nil, + nil, cortexpb.API) _, err := ingester.Push(ctx, currTimeReq) @@ -1240,7 +1312,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { // Push out of order samples. for n := 0; n < b.N; n++ { - _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API)) // nolint:errcheck + _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API)) // nolint:errcheck verifyErrorString(b, err, expectedErr) } @@ -1257,6 +1329,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { []labels.Labels{labels.FromStrings(labels.MetricName, "another")}, []cortexpb.Sample{{Value: 1, TimestampMs: sampleTimestamp + 1}}, nil, + nil, cortexpb.API) _, err := ingester.Push(ctx, currTimeReq) require.NoError(b, err) @@ -1264,7 +1337,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { runBenchmark: func(b *testing.B, ingester *Ingester, metrics []labels.Labels, samples []cortexpb.Sample) { // Push series with a different name than the one already pushed. for n := 0; n < b.N; n++ { - _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API)) // nolint:errcheck + _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API)) // nolint:errcheck verifyErrorString(b, err, "per-user series limit") } }, @@ -1280,6 +1353,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { []labels.Labels{labels.FromStrings(labels.MetricName, metricName, "cardinality", "another")}, []cortexpb.Sample{{Value: 1, TimestampMs: sampleTimestamp + 1}}, nil, + nil, cortexpb.API) _, err := ingester.Push(ctx, currTimeReq) require.NoError(b, err) @@ -1287,7 +1361,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { runBenchmark: func(b *testing.B, ingester *Ingester, metrics []labels.Labels, samples []cortexpb.Sample) { // Push series with different labels than the one already pushed. for n := 0; n < b.N; n++ { - _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API)) // nolint:errcheck + _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API)) // nolint:errcheck verifyErrorString(b, err, "per-metric series limit") } }, @@ -1310,7 +1384,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { runBenchmark: func(b *testing.B, ingester *Ingester, metrics []labels.Labels, samples []cortexpb.Sample) { // Push series with different labels than the one already pushed. for n := 0; n < b.N; n++ { - _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API)) + _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API)) verifyErrorString(b, err, "push rate reached") } }, @@ -1332,7 +1406,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { runBenchmark: func(b *testing.B, ingester *Ingester, metrics []labels.Labels, samples []cortexpb.Sample) { // Push series with different labels than the one already pushed. for n := 0; n < b.N; n++ { - _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API)) + _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API)) verifyErrorString(b, err, "max tenants limit reached") } }, @@ -1351,7 +1425,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { }, runBenchmark: func(b *testing.B, ingester *Ingester, metrics []labels.Labels, samples []cortexpb.Sample) { for n := 0; n < b.N; n++ { - _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API)) + _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API)) verifyErrorString(b, err, "max series limit reached") } }, @@ -1369,7 +1443,7 @@ func Benchmark_Ingester_PushOnError(b *testing.B) { }, runBenchmark: func(b *testing.B, ingester *Ingester, metrics []labels.Labels, samples []cortexpb.Sample) { for n := 0; n < b.N; n++ { - _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API)) + _, err := ingester.Push(ctx, cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API)) verifyErrorString(b, err, "too many inflight push requests") } }, @@ -2077,7 +2151,7 @@ func createIngesterWithSeries(t testing.TB, userID string, numSeries, numSamples } // Send metrics to the ingester. - req := cortexpb.ToWriteRequest(metrics, samples, nil, cortexpb.API) + req := cortexpb.ToWriteRequest(metrics, samples, nil, nil, cortexpb.API) _, err := i.Push(ctx, req) require.NoError(t, err) } @@ -2351,7 +2425,7 @@ func mockWriteRequest(t *testing.T, lbls labels.Labels, value float64, timestamp }, } - req := cortexpb.ToWriteRequest([]labels.Labels{lbls}, samples, nil, cortexpb.API) + req := cortexpb.ToWriteRequest([]labels.Labels{lbls}, samples, nil, nil, cortexpb.API) // Generate the expected response expectedQueryRes := &client.QueryResponse{ @@ -3858,6 +3932,7 @@ func TestIngester_PushInstanceLimits(t *testing.T) { []*cortexpb.MetricMetadata{ {MetricFamilyName: "metric_name_1", Help: "a help for metric_name_1", Unit: "", Type: cortexpb.COUNTER}, }, + nil, cortexpb.API), }, }, @@ -3873,12 +3948,14 @@ func TestIngester_PushInstanceLimits(t *testing.T) { []labels.Labels{cortexpb.FromLabelAdaptersToLabels([]cortexpb.LabelAdapter{{Name: labels.MetricName, Value: "test1"}})}, []cortexpb.Sample{{Value: 1, TimestampMs: 9}}, nil, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{cortexpb.FromLabelAdaptersToLabels([]cortexpb.LabelAdapter{{Name: labels.MetricName, Value: "test2"}})}, // another series []cortexpb.Sample{{Value: 1, TimestampMs: 10}}, nil, + nil, cortexpb.API), }, }, @@ -3895,6 +3972,7 @@ func TestIngester_PushInstanceLimits(t *testing.T) { []labels.Labels{cortexpb.FromLabelAdaptersToLabels([]cortexpb.LabelAdapter{{Name: labels.MetricName, Value: "test1"}})}, []cortexpb.Sample{{Value: 1, TimestampMs: 9}}, nil, + nil, cortexpb.API), }, @@ -3903,6 +3981,7 @@ func TestIngester_PushInstanceLimits(t *testing.T) { []labels.Labels{cortexpb.FromLabelAdaptersToLabels([]cortexpb.LabelAdapter{{Name: labels.MetricName, Value: "test2"}})}, // another series []cortexpb.Sample{{Value: 1, TimestampMs: 10}}, nil, + nil, cortexpb.API), }, }, @@ -3918,12 +3997,14 @@ func TestIngester_PushInstanceLimits(t *testing.T) { []labels.Labels{cortexpb.FromLabelAdaptersToLabels([]cortexpb.LabelAdapter{{Name: labels.MetricName, Value: "test1"}})}, []cortexpb.Sample{{Value: 1, TimestampMs: 9}}, nil, + nil, cortexpb.API), cortexpb.ToWriteRequest( []labels.Labels{cortexpb.FromLabelAdaptersToLabels([]cortexpb.LabelAdapter{{Name: labels.MetricName, Value: "test1"}})}, []cortexpb.Sample{{Value: 1, TimestampMs: 10}}, nil, + nil, cortexpb.API), }, }, @@ -4142,5 +4223,5 @@ func generateSamplesForLabel(l labels.Labels, count int) *cortexpb.WriteRequest lbls = append(lbls, l) } - return cortexpb.ToWriteRequest(lbls, samples, nil, cortexpb.API) + return cortexpb.ToWriteRequest(lbls, samples, nil, nil, cortexpb.API) } diff --git a/pkg/ingester/series.go b/pkg/ingester/series.go index 8ebad338d4..f5efb3a835 100644 --- a/pkg/ingester/series.go +++ b/pkg/ingester/series.go @@ -1,8 +1,9 @@ package ingester const ( - sampleOutOfOrder = "sample-out-of-order" - newValueForTimestamp = "new-value-for-timestamp" - sampleOutOfBounds = "sample-out-of-bounds" - sampleTooOld = "sample-too-old" + sampleOutOfOrder = "sample-out-of-order" + newValueForTimestamp = "new-value-for-timestamp" + sampleOutOfBounds = "sample-out-of-bounds" + sampleTooOld = "sample-too-old" + nativeHistogramSample = "native-histogram-sample" ) diff --git a/pkg/querier/tripperware/instantquery/instantquery.pb.go b/pkg/querier/tripperware/instantquery/instantquery.pb.go index ae1ff344ed..cdf0b3ec2c 100644 --- a/pkg/querier/tripperware/instantquery/instantquery.pb.go +++ b/pkg/querier/tripperware/instantquery/instantquery.pb.go @@ -165,7 +165,6 @@ func (m *PrometheusInstantQueryData) GetStats() *tripperware.PrometheusResponseS type PrometheusInstantQueryResult struct { // Types that are valid to be assigned to Result: - // // *PrometheusInstantQueryResult_Vector // *PrometheusInstantQueryResult_RawBytes // *PrometheusInstantQueryResult_Matrix diff --git a/pkg/ruler/compat.go b/pkg/ruler/compat.go index d4ad9ed8fb..70c2164a43 100644 --- a/pkg/ruler/compat.go +++ b/pkg/ruler/compat.go @@ -79,7 +79,7 @@ func (a *PusherAppender) Commit() error { // Since a.pusher is distributor, client.ReuseSlice will be called in a.pusher.Push. // We shouldn't call client.ReuseSlice here. - _, err := a.pusher.Push(user.InjectOrgID(a.ctx, a.userID), cortexpb.ToWriteRequest(a.labels, a.samples, nil, cortexpb.RULE)) + _, err := a.pusher.Push(user.InjectOrgID(a.ctx, a.userID), cortexpb.ToWriteRequest(a.labels, a.samples, nil, nil, cortexpb.RULE)) if err != nil { // Don't report errors that ended with 4xx HTTP status code (series limits, duplicate samples, out of order, etc.)