@ -6,7 +6,9 @@ import (
"compress/gzip"
"context"
"fmt"
"io"
"log"
"net/http"
"net/http/httptest"
"strings"
"testing"
@ -16,6 +18,10 @@ import (
"github.com/prometheus/prometheus/model/labels"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/plog"
"github.com/grafana/dskit/flagext"
util_log "github.com/grafana/loki/v3/pkg/util/log"
)
@ -256,7 +262,7 @@ func TestParseRequest(t *testing.T) {
}
tracker := NewMockTracker ( )
data , err := ParseRequest ( util_log . Logger , "fake" , request , nil , & fakeLimits { test . enableServiceDiscovery } , ParseLokiRequest , tracker )
data , err := ParseRequest ( util_log . Logger , "fake" , request , nil , & fakeLimits { enabled : test . enableServiceDiscovery } , ParseLokiRequest , tracker )
structuredMetadataBytesReceived := int ( structuredMetadataBytesReceivedStats . Value ( ) [ "total" ] . ( int64 ) ) - previousStructuredMetadataBytesReceived
previousStructuredMetadataBytesReceived += structuredMetadataBytesReceived
@ -314,19 +320,124 @@ func TestParseRequest(t *testing.T) {
}
}
func Test_ServiceDetection ( t * testing . T ) {
tracker := NewMockTracker ( )
createOtlpLogs := func ( labels ... string ) [ ] byte {
now := time . Unix ( 0 , time . Now ( ) . UnixNano ( ) )
ld := plog . NewLogs ( )
for i := 0 ; i < len ( labels ) ; i += 2 {
ld . ResourceLogs ( ) . AppendEmpty ( ) . Resource ( ) . Attributes ( ) . PutStr ( labels [ i ] , labels [ i + 1 ] )
}
ld . ResourceLogs ( ) . At ( 0 ) . ScopeLogs ( ) . AppendEmpty ( ) . LogRecords ( ) . AppendEmpty ( ) . Body ( ) . SetStr ( "test body" )
ld . ResourceLogs ( ) . At ( 0 ) . ScopeLogs ( ) . At ( 0 ) . LogRecords ( ) . At ( 0 ) . SetTimestamp ( pcommon . Timestamp ( now . UnixNano ( ) ) )
jsonMarshaller := plog . JSONMarshaler { }
body , err := jsonMarshaller . MarshalLogs ( ld )
require . NoError ( t , err )
return body
}
createRequest := func ( path string , body io . Reader ) * http . Request {
request := httptest . NewRequest (
"POST" ,
path ,
body ,
)
request . Header . Add ( "Content-Type" , "application/json" )
return request
}
t . Run ( "detects servce from loki push requests" , func ( t * testing . T ) {
body := ` { "streams": [ { "stream": { "foo": "bar" }, "values": [ [ "1570818238000000000", "fizzbuzz" ] ] }]} `
request := createRequest ( "/loki/api/v1/push" , strings . NewReader ( body ) )
limits := & fakeLimits { enabled : true , labels : [ ] string { "foo" } }
data , err := ParseRequest ( util_log . Logger , "fake" , request , nil , limits , ParseLokiRequest , tracker )
require . NoError ( t , err )
require . Equal ( t , labels . FromStrings ( "foo" , "bar" , LabelServiceName , "bar" ) . String ( ) , data . Streams [ 0 ] . Labels )
} )
t . Run ( "detects servce from OTLP push requests using default indexing" , func ( t * testing . T ) {
body := createOtlpLogs ( "k8s.job.name" , "bar" )
request := createRequest ( "/otlp/v1/push" , bytes . NewReader ( body ) )
limits := & fakeLimits { enabled : true }
data , err := ParseRequest ( util_log . Logger , "fake" , request , limits , limits , ParseOTLPRequest , tracker )
require . NoError ( t , err )
require . Equal ( t , labels . FromStrings ( "k8s_job_name" , "bar" , LabelServiceName , "bar" ) . String ( ) , data . Streams [ 0 ] . Labels )
} )
t . Run ( "detects servce from OTLP push requests using custom indexing" , func ( t * testing . T ) {
body := createOtlpLogs ( "special" , "sauce" )
request := createRequest ( "/otlp/v1/push" , bytes . NewReader ( body ) )
limits := & fakeLimits {
enabled : true ,
labels : [ ] string { "special" } ,
indexAttributes : [ ] string { "special" } ,
}
data , err := ParseRequest ( util_log . Logger , "fake" , request , limits , limits , ParseOTLPRequest , tracker )
require . NoError ( t , err )
require . Equal ( t , labels . FromStrings ( "special" , "sauce" , LabelServiceName , "sauce" ) . String ( ) , data . Streams [ 0 ] . Labels )
} )
t . Run ( "only detects custom service label from indexed labels" , func ( t * testing . T ) {
body := createOtlpLogs ( "special" , "sauce" )
request := createRequest ( "/otlp/v1/push" , bytes . NewReader ( body ) )
limits := & fakeLimits {
enabled : true ,
labels : [ ] string { "special" } ,
indexAttributes : [ ] string { } ,
}
data , err := ParseRequest ( util_log . Logger , "fake" , request , limits , limits , ParseOTLPRequest , tracker )
require . NoError ( t , err )
require . Equal ( t , labels . FromStrings ( LabelServiceName , ServiceUnknown ) . String ( ) , data . Streams [ 0 ] . Labels )
} )
}
type fakeLimits struct {
enabled bool
enabled bool
labels [ ] string
indexAttributes [ ] string
}
func ( l * fakeLimits ) OTLPConfig ( _ string ) OTLPConfig {
return OTLPConfig { }
func ( f * fakeLimits ) RetentionPeriodFor ( _ string , _ labels . Labels ) time . Duration {
return time . Hour
}
func ( l * fakeLimits ) DiscoverServiceName ( _ string ) [ ] string {
if ! l . enabled {
func ( f * fakeLimits ) OTLPConfig ( _ string ) OTLPConfig {
if len ( f . indexAttributes ) > 0 {
return OTLPConfig {
ResourceAttributes : ResourceAttributesConfig {
AttributesConfig : [ ] AttributesConfig {
{
Action : IndexLabel ,
Attributes : f . indexAttributes ,
} ,
} ,
} ,
}
}
defaultGlobalOTLPConfig := GlobalOTLPConfig { }
flagext . DefaultValues ( & defaultGlobalOTLPConfig )
return DefaultOTLPConfig ( defaultGlobalOTLPConfig )
}
func ( f * fakeLimits ) DiscoverServiceName ( _ string ) [ ] string {
if ! f . enabled {
return nil
}
if len ( f . labels ) > 0 {
return f . labels
}
return [ ] string {
"service" ,
"app" ,
@ -335,9 +446,11 @@ func (l *fakeLimits) DiscoverServiceName(_ string) []string {
"app_kubernetes_io_name" ,
"container" ,
"container_name" ,
"k8s_container_name" ,
"component" ,
"workload" ,
"job" ,
"k8s_job_name" ,
}
}