@ -130,7 +130,7 @@ func TestRemoteWriteHandlerHeadersHandling_V1Message(t *testing.T) {
}
appendable := & mockAppendable { }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false , false )
recorder := httptest . NewRecorder ( )
handler . ServeHTTP ( recorder , req )
@ -237,7 +237,7 @@ func TestRemoteWriteHandlerHeadersHandling_V2Message(t *testing.T) {
}
appendable := & mockAppendable { }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV2 } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV2 } , false , false )
recorder := httptest . NewRecorder ( )
handler . ServeHTTP ( recorder , req )
@ -272,7 +272,7 @@ func TestRemoteWriteHandlerHeadersHandling_V2Message(t *testing.T) {
}
appendable := & mockAppendable { }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV2 } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV2 } , false , false )
recorder := httptest . NewRecorder ( )
handler . ServeHTTP ( recorder , req )
@ -301,7 +301,7 @@ func TestRemoteWriteHandler_V1Message(t *testing.T) {
// in Prometheus, so keeping like this to not break existing 1.0 clients.
appendable := & mockAppendable { }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false , false )
recorder := httptest . NewRecorder ( )
handler . ServeHTTP ( recorder , req )
@ -352,6 +352,7 @@ func TestRemoteWriteHandler_V2Message(t *testing.T) {
for _ , tc := range [ ] struct {
desc string
input [ ] writev2 . TimeSeries
symbols [ ] string // Custom symbol table for tests that need it
expectedCode int
expectedRespBody string
@ -362,7 +363,9 @@ func TestRemoteWriteHandler_V2Message(t *testing.T) {
appendExemplarErr error
updateMetadataErr error
ingestCTZeroSample bool
ingestCTZeroSample bool
enableTypeAndUnitLabels bool
expectedLabels labels . Labels // For verifying type/unit labels
} {
{
desc : "All timeseries accepted/ct_enabled" ,
@ -513,9 +516,147 @@ func TestRemoteWriteHandler_V2Message(t *testing.T) {
expectedCode : http . StatusInternalServerError ,
expectedRespBody : "storage error\n" ,
} ,
// Type and unit labels tests
{
desc : "Type and unit labels enabled with counter and bytes unit" ,
input : func ( ) [ ] writev2 . TimeSeries {
symbolTable := writev2 . NewSymbolTable ( )
labelRefs := symbolTable . SymbolizeLabels ( labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) , nil )
unitRef := symbolTable . Symbolize ( "bytes" )
return [ ] writev2 . TimeSeries {
{
LabelsRefs : labelRefs ,
Metadata : writev2 . Metadata {
Type : writev2 . Metadata_METRIC_TYPE_COUNTER ,
UnitRef : unitRef ,
} ,
Samples : [ ] writev2 . Sample { { Value : 1.0 , Timestamp : 1000 } } ,
} ,
}
} ( ) ,
symbols : func ( ) [ ] string {
symbolTable := writev2 . NewSymbolTable ( )
symbolTable . SymbolizeLabels ( labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) , nil )
symbolTable . Symbolize ( "bytes" )
return symbolTable . Symbols ( )
} ( ) ,
expectedCode : http . StatusNoContent ,
enableTypeAndUnitLabels : true ,
expectedLabels : labels . FromStrings ( "__name__" , "test_metric" , "__type__" , "counter" , "__unit__" , "bytes" , "foo" , "bar" ) ,
} ,
{
desc : "Type and unit labels enabled with gauge and seconds unit" ,
input : func ( ) [ ] writev2 . TimeSeries {
symbolTable := writev2 . NewSymbolTable ( )
labelRefs := symbolTable . SymbolizeLabels ( labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) , nil )
unitRef := symbolTable . Symbolize ( "seconds" )
return [ ] writev2 . TimeSeries {
{
LabelsRefs : labelRefs ,
Metadata : writev2 . Metadata {
Type : writev2 . Metadata_METRIC_TYPE_GAUGE ,
UnitRef : unitRef ,
} ,
Samples : [ ] writev2 . Sample { { Value : 1.0 , Timestamp : 1000 } } ,
} ,
}
} ( ) ,
symbols : func ( ) [ ] string {
symbolTable := writev2 . NewSymbolTable ( )
symbolTable . SymbolizeLabels ( labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) , nil )
symbolTable . Symbolize ( "seconds" )
return symbolTable . Symbols ( )
} ( ) ,
expectedCode : http . StatusNoContent ,
enableTypeAndUnitLabels : true ,
expectedLabels : labels . FromStrings ( "__name__" , "test_metric" , "__type__" , "gauge" , "__unit__" , "seconds" , "foo" , "bar" ) ,
} ,
{
desc : "Type and unit labels disabled - no metadata labels" ,
input : func ( ) [ ] writev2 . TimeSeries {
symbolTable := writev2 . NewSymbolTable ( )
labelRefs := symbolTable . SymbolizeLabels ( labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) , nil )
unitRef := symbolTable . Symbolize ( "bytes" )
return [ ] writev2 . TimeSeries {
{
LabelsRefs : labelRefs ,
Metadata : writev2 . Metadata {
Type : writev2 . Metadata_METRIC_TYPE_COUNTER ,
UnitRef : unitRef ,
} ,
Samples : [ ] writev2 . Sample { { Value : 1.0 , Timestamp : 1000 } } ,
} ,
}
} ( ) ,
symbols : func ( ) [ ] string {
symbolTable := writev2 . NewSymbolTable ( )
symbolTable . SymbolizeLabels ( labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) , nil )
symbolTable . Symbolize ( "bytes" )
return symbolTable . Symbols ( )
} ( ) ,
expectedCode : http . StatusNoContent ,
enableTypeAndUnitLabels : false ,
expectedLabels : labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) ,
} ,
{
desc : "Type and unit labels enabled but no metadata" ,
input : func ( ) [ ] writev2 . TimeSeries {
symbolTable := writev2 . NewSymbolTable ( )
labelRefs := symbolTable . SymbolizeLabels ( labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) , nil )
return [ ] writev2 . TimeSeries {
{
LabelsRefs : labelRefs ,
Metadata : writev2 . Metadata {
Type : writev2 . Metadata_METRIC_TYPE_UNSPECIFIED ,
UnitRef : 0 ,
} ,
Samples : [ ] writev2 . Sample { { Value : 1.0 , Timestamp : 1000 } } ,
} ,
}
} ( ) ,
symbols : func ( ) [ ] string {
symbolTable := writev2 . NewSymbolTable ( )
symbolTable . SymbolizeLabels ( labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) , nil )
return symbolTable . Symbols ( )
} ( ) ,
expectedCode : http . StatusNoContent ,
enableTypeAndUnitLabels : true ,
expectedLabels : labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) ,
} ,
{
desc : "Type and unit labels enabled with only unit (no type)" ,
input : func ( ) [ ] writev2 . TimeSeries {
symbolTable := writev2 . NewSymbolTable ( )
labelRefs := symbolTable . SymbolizeLabels ( labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) , nil )
unitRef := symbolTable . Symbolize ( "milliseconds" )
return [ ] writev2 . TimeSeries {
{
LabelsRefs : labelRefs ,
Metadata : writev2 . Metadata {
Type : writev2 . Metadata_METRIC_TYPE_UNSPECIFIED ,
UnitRef : unitRef ,
} ,
Samples : [ ] writev2 . Sample { { Value : 1.0 , Timestamp : 1000 } } ,
} ,
}
} ( ) ,
symbols : func ( ) [ ] string {
symbolTable := writev2 . NewSymbolTable ( )
symbolTable . SymbolizeLabels ( labels . FromStrings ( "__name__" , "test_metric" , "foo" , "bar" ) , nil )
symbolTable . Symbolize ( "milliseconds" )
return symbolTable . Symbols ( )
} ( ) ,
expectedCode : http . StatusNoContent ,
enableTypeAndUnitLabels : true ,
expectedLabels : labels . FromStrings ( "__name__" , "test_metric" , "__unit__" , "milliseconds" , "foo" , "bar" ) ,
} ,
} {
t . Run ( tc . desc , func ( t * testing . T ) {
payload , _ , _ , err := buildV2WriteRequest ( promslog . NewNopLogger ( ) , tc . input , writeV2RequestFixture . Symbols , nil , nil , nil , "snappy" )
symbols := writeV2RequestFixture . Symbols
if tc . symbols != nil {
symbols = tc . symbols
}
payload , _ , _ , err := buildV2WriteRequest ( promslog . NewNopLogger ( ) , tc . input , symbols , nil , nil , nil , "snappy" )
require . NoError ( t , err )
req , err := http . NewRequest ( "" , "" , bytes . NewReader ( payload ) )
@ -533,7 +674,7 @@ func TestRemoteWriteHandler_V2Message(t *testing.T) {
appendExemplarErr : tc . appendExemplarErr ,
updateMetadataErr : tc . updateMetadataErr ,
}
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV2 } , tc . ingestCTZeroSample )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV2 } , tc . ingestCTZeroSample , tc . enableTypeAndUnitLabels )
recorder := httptest . NewRecorder ( )
handler . ServeHTTP ( recorder , req )
@ -557,6 +698,12 @@ func TestRemoteWriteHandler_V2Message(t *testing.T) {
return
}
if ! tc . expectedLabels . IsEmpty ( ) {
require . Len ( t , appendable . samples , 1 )
testutil . RequireEqual ( t , tc . expectedLabels , appendable . samples [ 0 ] . l )
return
}
// Double check mandatory 2.0 stats.
// writeV2RequestFixture has 2 series with 1 sample, 2 histograms, 1 exemplar each.
expectHeaderValue ( t , 2 , resp . Header . Get ( rw20WrittenSamplesHeader ) )
@ -655,7 +802,7 @@ func TestOutOfOrderSample_V1Message(t *testing.T) {
require . NoError ( t , err )
appendable := & mockAppendable { latestSample : map [ uint64 ] int64 { labels . FromStrings ( "__name__" , "test_metric" ) . Hash ( ) : 100 } }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false , false )
recorder := httptest . NewRecorder ( )
handler . ServeHTTP ( recorder , req )
@ -697,7 +844,7 @@ func TestOutOfOrderExemplar_V1Message(t *testing.T) {
require . NoError ( t , err )
appendable := & mockAppendable { latestSample : map [ uint64 ] int64 { labels . FromStrings ( "__name__" , "test_metric" ) . Hash ( ) : 100 } }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false , false )
recorder := httptest . NewRecorder ( )
handler . ServeHTTP ( recorder , req )
@ -735,7 +882,7 @@ func TestOutOfOrderHistogram_V1Message(t *testing.T) {
require . NoError ( t , err )
appendable := & mockAppendable { latestSample : map [ uint64 ] int64 { labels . FromStrings ( "__name__" , "test_metric" ) . Hash ( ) : 100 } }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false , false )
recorder := httptest . NewRecorder ( )
handler . ServeHTTP ( recorder , req )
@ -785,7 +932,7 @@ func BenchmarkRemoteWriteHandler(b *testing.B) {
for _ , tc := range testCases {
b . Run ( tc . name , func ( b * testing . B ) {
appendable := & mockAppendable { }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { tc . protoFormat } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { tc . protoFormat } , false , false )
b . ResetTimer ( )
for i := 0 ; i < b . N ; i ++ {
b . StopTimer ( )
@ -810,7 +957,7 @@ func TestCommitErr_V1Message(t *testing.T) {
require . NoError ( t , err )
appendable := & mockAppendable { commitErr : errors . New ( "commit error" ) }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false , false )
recorder := httptest . NewRecorder ( )
handler . ServeHTTP ( recorder , req )
@ -876,7 +1023,7 @@ func TestHistogramValidationErrorHandling(t *testing.T) {
require . NoError ( t , err )
t . Cleanup ( func ( ) { require . NoError ( t , db . Close ( ) ) } )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , db . Head ( ) , [ ] config . RemoteWriteProtoMsg { protoMsg } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , db . Head ( ) , [ ] config . RemoteWriteProtoMsg { protoMsg } , false , false )
recorder := httptest . NewRecorder ( )
var buf [ ] byte
@ -921,7 +1068,7 @@ func TestCommitErr_V2Message(t *testing.T) {
req . Header . Set ( RemoteWriteVersionHeader , RemoteWriteVersion20HeaderValue )
appendable := & mockAppendable { commitErr : errors . New ( "commit error" ) }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV2 } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV2 } , false , false )
recorder := httptest . NewRecorder ( )
handler . ServeHTTP ( recorder , req )
@ -948,7 +1095,7 @@ func BenchmarkRemoteWriteOOOSamples(b *testing.B) {
require . NoError ( b , db . Close ( ) )
} )
// TODO: test with other proto format(s)
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , db . Head ( ) , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , db . Head ( ) , [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 } , false , false )
buf , _ , _ , err := buildWriteRequest ( nil , genSeriesWithSample ( 1000 , 200 * time . Minute . Milliseconds ( ) ) , nil , nil , nil , nil , "snappy" )
require . NoError ( b , err )
@ -1279,7 +1426,7 @@ func TestHistogramsReduction(t *testing.T) {
for _ , protoMsg := range [ ] config . RemoteWriteProtoMsg { config . RemoteWriteProtoMsgV1 , config . RemoteWriteProtoMsgV2 } {
t . Run ( string ( protoMsg ) , func ( t * testing . T ) {
appendable := & mockAppendable { }
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { protoMsg } , false )
handler := NewWriteHandler ( promslog . NewNopLogger ( ) , nil , appendable , [ ] config . RemoteWriteProtoMsg { protoMsg } , false , false )
var (
err error