Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[exporter/loadbalancing] allow metrics routing #26378

Merged
merged 20 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
default metrics exporter to service
  • Loading branch information
claudiobastos committed Sep 7, 2023
commit 58ce078df262900ac33dd53461ef51b6e658bd26
9 changes: 5 additions & 4 deletions exporter/loadbalancingexporter/metrics_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,15 @@ func newMetricsExporter(params exporter.CreateSettings, cfg component.Config) (*
metricExporter := metricExporterImp{loadBalancer: lb, routingKey: svcRouting}

switch cfg.(*Config).RoutingKey {
case "service", "":
case "service", "traceID", "":
// default case
metricExporter.routingKey = svcRouting
case "resource":
metricExporter.routingKey = resourceRouting
case "metric":
metricExporter.routingKey = metricNameRouting
default:
return nil, fmt.Errorf("unsupported routing_key: %s", cfg.(*Config).RoutingKey)
return nil, fmt.Errorf("unsupported routing_key: '%s'", cfg.(*Config).RoutingKey)
claudiobastos marked this conversation as resolved.
Show resolved Hide resolved
}
return &metricExporter, nil

Expand Down Expand Up @@ -120,8 +121,8 @@ func (e *metricExporterImp) consumeMetric(ctx context.Context, md pmetric.Metric
mBackendLatency.M(duration.Milliseconds()))
}
}
return err

return err
}

func routingIdentifiersFromMetrics(mds pmetric.Metrics, key routingKey) (map[string]bool, error) {
Expand Down Expand Up @@ -149,7 +150,7 @@ func routingIdentifiersFromMetrics(mds pmetric.Metrics, key routingKey) (map[str
resource := rs.At(i).Resource()
switch key {
default:
case svcRouting:
case svcRouting, traceIDRouting:
svc, ok := resource.Attributes().Get("service.name")
claudiobastos marked this conversation as resolved.
Show resolved Hide resolved
if !ok {
return nil, errors.New("unable to get service name")
Expand Down
146 changes: 64 additions & 82 deletions exporter/loadbalancingexporter/metrics_exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"net"
"path/filepath"
"strconv"
"strings"
"sync"
"sync/atomic"
"testing"
Expand All @@ -36,9 +35,9 @@ import (
)

const (
serviceRouteKey = "service"
resourceRouteKey = "resource"
attributeRouteKey = "attribute"
serviceRouteKey = "service"
resourceRouteKey = "resource"
metricRouteKey = "metric"

ilsName1 = "library-1"
ilsName2 = "library-2"
Expand Down Expand Up @@ -71,6 +70,21 @@ func TestNewMetricsExporter(t *testing.T) {
simpleConfig(),
nil,
},
{
"service",
serviceBasedRoutingConfig(),
nil,
},
{
"metric",
metricNameBasedRoutingConfig(),
nil,
},
{
"resource",
resourceBasedRoutingConfig(),
nil,
},
{
"empty",
&Config{},
Expand All @@ -96,16 +110,16 @@ func TestMetricsExporterStart(t *testing.T) {
{
"ok",
func() *metricExporterImp {
p, _ := newMetricsExporter(exportertest.NewNopCreateSettings(), simpleConfig())
p, _ := newMetricsExporter(exportertest.NewNopCreateSettings(), serviceBasedRoutingConfig())
return p
}(),
nil,
},
{
"error",
func() *metricExporterImp {
lb, _ := newLoadBalancer(exportertest.NewNopCreateSettings(), simpleConfig(), nil)
p, _ := newMetricsExporter(exportertest.NewNopCreateSettings(), simpleConfig())
lb, _ := newLoadBalancer(exportertest.NewNopCreateSettings(), serviceBasedRoutingConfig(), nil)
p, _ := newMetricsExporter(exportertest.NewNopCreateSettings(), serviceBasedRoutingConfig())

lb.res = &mockResolver{
onStart: func(context.Context) error {
Expand Down Expand Up @@ -157,7 +171,7 @@ func TestConsumeMetrics(t *testing.T) {
p, err := newMetricsExporter(exportertest.NewNopCreateSettings(), simpleConfig())
require.NotNil(t, p)
require.NoError(t, err)
assert.Equal(t, p.routingKey, traceIDRouting)
assert.Equal(t, p.routingKey, svcRouting)

// pre-load an exporter here, so that we don't use the actual OTLP exporter
lb.addMissingExporters(context.Background(), []string{"endpoint-1"})
Expand All @@ -176,10 +190,11 @@ func TestConsumeMetrics(t *testing.T) {
}()

// test
res := p.ConsumeMetrics(context.Background(), simpleMetrics())
res := p.ConsumeMetrics(context.Background(), simpleMetricsWithNoService())

// verify
assert.Nil(t, res)
assert.Error(t, res)

}

func TestConsumeMetricsServiceBased(t *testing.T) {
Expand Down Expand Up @@ -254,18 +269,18 @@ func TestConsumeMetricsResourceBased(t *testing.T) {
assert.Nil(t, res)
}

func TestConsumeMetricsAttributeBased(t *testing.T) {
func TestConsumeMetricsMetricNameBased(t *testing.T) {
componentFactory := func(ctx context.Context, endpoint string) (component.Component, error) {
return newNopMockMetricsExporter(), nil
}
lb, err := newLoadBalancer(exportertest.NewNopCreateSettings(), attributeBasedRoutingConfig(), componentFactory)
lb, err := newLoadBalancer(exportertest.NewNopCreateSettings(), metricNameBasedRoutingConfig(), componentFactory)
require.NotNil(t, lb)
require.NoError(t, err)

p, err := newMetricsExporter(exportertest.NewNopCreateSettings(), attributeBasedRoutingConfig())
p, err := newMetricsExporter(exportertest.NewNopCreateSettings(), metricNameBasedRoutingConfig())
require.NotNil(t, p)
require.NoError(t, err)
assert.Equal(t, p.routingKey, resourceRouting)
assert.Equal(t, p.routingKey, metricNameRouting)

// pre-load an exporter here, so that we don't use the actual OTLP exporter
lb.addMissingExporters(context.Background(), []string{"endpoint-1"})
Expand All @@ -284,7 +299,7 @@ func TestConsumeMetricsAttributeBased(t *testing.T) {
}()

// test
res := p.ConsumeMetrics(context.Background(), simpleMetricsWithAttribute())
res := p.ConsumeMetrics(context.Background(), simpleMetricsWithResource())

// verify
assert.Nil(t, res)
Expand All @@ -308,10 +323,7 @@ func TestServiceBasedRoutingForSameMetricName(t *testing.T) {
"different services - trace id routing",
twoServicesWithSameMetricName(),
traceIDRouting,
map[string]bool{
strings.Join([]string{"service.name", serviceName1, signal1Name}, ""): true,
strings.Join([]string{"service.name", serviceName2, signal1Name}, ""): true,
},
map[string]bool{serviceName1: true, serviceName2: true},
},
} {
t.Run(tt.desc, func(t *testing.T) {
Expand All @@ -330,7 +342,7 @@ func TestConsumeMetricsExporterNoEndpoint(t *testing.T) {
require.NotNil(t, lb)
require.NoError(t, err)

p, err := newMetricsExporter(exportertest.NewNopCreateSettings(), simpleConfig())
p, err := newMetricsExporter(exportertest.NewNopCreateSettings(), endpoint2Config())
require.NotNil(t, p)
require.NoError(t, err)

Expand All @@ -349,7 +361,7 @@ func TestConsumeMetricsExporterNoEndpoint(t *testing.T) {
}()

// test
res := p.ConsumeMetrics(context.Background(), simpleMetrics())
res := p.ConsumeMetrics(context.Background(), simpleMetricsWithServiceName())

// verify
assert.Error(t, res)
Expand Down Expand Up @@ -385,7 +397,7 @@ func TestConsumeMetricsUnexpectedExporterType(t *testing.T) {
}()

// test
res := p.ConsumeMetrics(context.Background(), simpleMetrics())
res := p.ConsumeMetrics(context.Background(), simpleMetricsWithServiceName())

// verify
assert.Error(t, res)
Expand Down Expand Up @@ -439,8 +451,7 @@ func TestBatchWithTwoMetrics(t *testing.T) {

lb.addMissingExporters(context.Background(), []string{"endpoint-1"})

td := simpleMetrics()
appendSimpleMetricWithID(td.ResourceMetrics().AppendEmpty(), "metric-name")
td := twoServicesWithSameMetricName()

// test
err = p.ConsumeMetrics(context.Background(), td)
Expand Down Expand Up @@ -510,53 +521,20 @@ func TestResourceRoutingKey(t *testing.T) {
if got := resourceRoutingKey(md, attrs); got != "k1v1k2v2metric" {
t.Errorf("metricRoutingKey() = %v, want %v", got, "k1v1k2v2metric")
}

}

func TestAttributeRoutingKey(t *testing.T) {
func TestMetricNameRoutingKey(t *testing.T) {

md := pmetric.NewMetric()
md.SetName("metric")
attrs := pcommon.NewMap()
if got := attributesRoutingKey(md, attrs); got != "metric" {
t.Errorf("metricRoutingKey() = %v, want %v", got, "metric")
}

attrs.PutStr("k1", "v1")
if got := attributesRoutingKey(md, attrs); got != "k1v1metric" {
t.Errorf("metricRoutingKey() = %v, want %v", got, "k1v1metric")
md.SetName(signal1Name)
if got := metricRoutingKey(md); got != signal1Name {
t.Errorf("metricRoutingKey() = %v, want %v", got, signal1Name)
}

attrs.PutStr("k2", "v2")
if got := attributesRoutingKey(md, attrs); got != "k1v1k2v2metric" {
t.Errorf("metricRoutingKey() = %v, want %v", got, "k1v1k2v2metric")
}

md.SetEmptySum().DataPoints().AppendEmpty().Attributes().PutStr(signal1Attr1Key, signal1Attr1Value)
expected := strings.Join([]string{signal1Attr1Key, signal1Attr1Value, "k1v1k2v2metric"}, "")
if got := attributesRoutingKey(md, attrs); got != expected {
t.Errorf("metricRoutingKey() = %v, want %v", got, expected)
}

md.Sum().DataPoints().AppendEmpty().Attributes().PutInt(signal1Attr2Key, signal1Attr2Value)
attr2 := fmt.Sprintf("%d", signal1Attr2Value)
expected = strings.Join([]string{signal1Attr1Key, signal1Attr1Value, signal1Attr2Key, attr2, "k1v1k2v2metric"}, "")
if got := attributesRoutingKey(md, attrs); got != expected {
t.Errorf("metricRoutingKey() = %v, want %v", got, expected)
}

md.Sum().DataPoints().AppendEmpty().Attributes().PutBool(signal1Attr3Key, signal1Attr3Value)
attr3 := strconv.FormatBool(signal1Attr3Value)
expected = strings.Join([]string{signal1Attr1Key, signal1Attr1Value, signal1Attr2Key, attr2, signal1Attr3Key, attr3, "k1v1k2v2metric"}, "")
if got := attributesRoutingKey(md, attrs); got != expected {
t.Errorf("metricRoutingKey() = %v, want %v", got, expected)
}

md.Sum().DataPoints().AppendEmpty().Attributes().PutDouble(signal1Attr4Key, signal1Attr4Value)
attr4 := fmt.Sprintf("%v", signal1Attr4Value)
expected = strings.Join([]string{signal1Attr1Key, signal1Attr1Value, signal1Attr2Key, attr2, signal1Attr3Key, attr3, signal1Attr4Key, attr4, "k1v1k2v2metric"}, "")
if got := attributesRoutingKey(md, attrs); got != expected {
t.Errorf("metricRoutingKey() = %v, want %v", got, expected)
md = pmetric.NewMetric()
md.SetName(signal2Name)
if got := metricRoutingKey(md); got != signal2Name {
t.Errorf("metricRoutingKey() = %v, want %v", got, signal2Name)
}

}
Expand Down Expand Up @@ -703,6 +681,22 @@ func TestRollingUpdatesWhenConsumeMetrics(t *testing.T) {
require.Greater(t, counter2.Load(), int64(0))
}

// func endpoint1Config() *Config {
// return &Config{
// Resolver: ResolverSettings{
// Static: &StaticResolver{Hostnames: []string{"endpoint-1"}},
// },
// }
// }

func endpoint2Config() *Config {
return &Config{
Resolver: ResolverSettings{
Static: &StaticResolver{Hostnames: []string{"endpoint-2"}},
},
}
}

func resourceBasedRoutingConfig() *Config {
return &Config{
Resolver: ResolverSettings{
Expand All @@ -712,12 +706,12 @@ func resourceBasedRoutingConfig() *Config {
}
}

func attributeBasedRoutingConfig() *Config {
func metricNameBasedRoutingConfig() *Config {
return &Config{
Resolver: ResolverSettings{
Static: &StaticResolver{Hostnames: []string{"endpoint-1"}},
},
RoutingKey: attributeRouteKey,
RoutingKey: metricRouteKey,
}
}

Expand All @@ -729,7 +723,7 @@ func randomMetrics() pmetric.Metrics {
return metrics
}

func simpleMetrics() pmetric.Metrics {
func simpleMetricsWithNoService() pmetric.Metrics {
metrics := pmetric.NewMetrics()
appendSimpleMetricWithID(metrics.ResourceMetrics().AppendEmpty(), "simple-metric-name")
return metrics
Expand All @@ -739,7 +733,7 @@ func simpleMetricsWithServiceName() pmetric.Metrics {
metrics := pmetric.NewMetrics()
metrics.ResourceMetrics().EnsureCapacity(1)
rmetrics := metrics.ResourceMetrics().AppendEmpty()
rmetrics.Resource().Attributes().PutStr(conventions.AttributeServiceName, "service-name-1")
rmetrics.Resource().Attributes().PutStr(conventions.AttributeServiceName, serviceName1)
rmetrics.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetName(signal1Name)
return metrics
}
Expand All @@ -749,25 +743,13 @@ func simpleMetricsWithResource() pmetric.Metrics {
metrics := pmetric.NewMetrics()
metrics.ResourceMetrics().EnsureCapacity(1)
rmetrics := metrics.ResourceMetrics().AppendEmpty()
rmetrics.Resource().Attributes().PutStr(conventions.AttributeServiceName, "service-name-1")
rmetrics.Resource().Attributes().PutStr(conventions.AttributeServiceName, serviceName1)
rmetrics.Resource().Attributes().PutStr(keyAttr1, valueAttr1)
rmetrics.Resource().Attributes().PutInt(keyAttr2, valueAttr2)
rmetrics.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetName(signal1Name)
return metrics
}

func simpleMetricsWithAttribute() pmetric.Metrics {

metrics := pmetric.NewMetrics()
metrics.ResourceMetrics().EnsureCapacity(1)
rmetrics := metrics.ResourceMetrics().AppendEmpty()
rmetrics.Resource().Attributes().PutStr(conventions.AttributeServiceName, "service-name-1")
rmetrics.Resource().Attributes().PutStr(keyAttr1, valueAttr1)
rmetrics.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetName(signal1Name)

return metrics
}

func twoServicesWithSameMetricName() pmetric.Metrics {
metrics := pmetric.NewMetrics()
metrics.ResourceMetrics().EnsureCapacity(2)
Expand Down