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

receiver/prometheus/internal: add createNodeAndResourcePdata for Prometheus->OTLP Pdata #3139

Merged
Show file tree
Hide file tree
Changes from all commits
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
39 changes: 39 additions & 0 deletions receiver/prometheusreceiver/internal/prom_to_otlp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
"net"

"go.opentelemetry.io/collector/consumer/pdata"
"go.opentelemetry.io/collector/translator/conventions"
)

func createNodeAndResourcePdata(job, instance, scheme string) pdata.Resource {
host, port, err := net.SplitHostPort(instance)
if err != nil {
host = instance
}
resource := pdata.NewResource()
attrs := resource.Attributes()
attrs.UpsertString(conventions.AttributeServiceName, job)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alolita Does anyone own the spec for prometheus mapping of the standard conventions? These seem somewhat arbitrary. If they can be excluded, I'd only add the prometheus specific attributes for now

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anuraaga this is a straight up translation of what already exists in the current converter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know - it doesn't block this PR but someone needs to be working on that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need to open an issue to track this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need to open an issue to track this.

Why upsert the job to service.name? Shouldn't it be better to check if service.name has been set?

attrs.UpsertString(conventions.AttributeHostName, host)
attrs.UpsertString(jobAttr, job)
attrs.UpsertString(instanceAttr, instance)
attrs.UpsertString(portAttr, port)
attrs.UpsertString(schemeAttr, scheme)

return resource
}
120 changes: 120 additions & 0 deletions receiver/prometheusreceiver/internal/prom_to_otlp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package internal

import (
"testing"

metricspb "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1"
"github.com/stretchr/testify/require"

"go.opentelemetry.io/collector/consumer/pdata"
"go.opentelemetry.io/collector/translator/internaldata"
)

// Parity test to ensure that createNodeAndResource produces identical results to createNodeAndResourcePdata.
func TestCreateNodeAndResourceEquivalence(t *testing.T) {
job, instance, scheme := "converter", "ocmetrics", "http"
ocNode, ocResource := createNodeAndResource(job, instance, scheme)
mdFromOC := internaldata.OCToMetrics(ocNode, ocResource,
// We need to pass in a dummy set of metrics
// just to populate and allow for full conversion.
[]*metricspb.Metric{
{
MetricDescriptor: &metricspb.MetricDescriptor{
Name: "m1",
Description: "d1",
Unit: "By",
},
},
},
)

fromOCResource := mdFromOC.ResourceMetrics().At(0).Resource().Attributes().Sort()
byDirectOTLPResource := createNodeAndResourcePdata(job, instance, scheme).Attributes().Sort()

require.Equal(t, byDirectOTLPResource, fromOCResource)
}

type jobInstanceDefinition struct {
job, instance, host, scheme, port string
}

func makeResourceWithJobInstanceScheme(def *jobInstanceDefinition) pdata.Resource {
resource := pdata.NewResource()
attrs := resource.Attributes()
// Using hardcoded values to assert on outward expectations so that
// when variables change, these tests will fail and we'll have reports.
attrs.UpsertString("service.name", def.job)
attrs.UpsertString("host.name", def.host)
attrs.UpsertString("job", def.job)
attrs.UpsertString("instance", def.instance)
attrs.UpsertString("port", def.port)
attrs.UpsertString("scheme", def.scheme)
return resource
}

func TestCreateNodeAndResourcePromToOTLP(t *testing.T) {
tests := []struct {
name, job string
instance string
scheme string
want pdata.Resource
}{
{
name: "all attributes proper",
job: "job", instance: "localhost:8888", scheme: "http",
want: makeResourceWithJobInstanceScheme(&jobInstanceDefinition{
"job", "localhost:8888", "localhost", "http", "8888",
}),
},
{
name: "missing port",
job: "job", instance: "myinstance", scheme: "https",
want: makeResourceWithJobInstanceScheme(&jobInstanceDefinition{
"job", "myinstance", "myinstance", "https", "",
}),
},
{
name: "blank scheme",
job: "job", instance: "myinstance:443", scheme: "",
want: makeResourceWithJobInstanceScheme(&jobInstanceDefinition{
"job", "myinstance:443", "myinstance", "", "443",
}),
},
{
name: "blank instance, blank scheme",
job: "job", instance: "", scheme: "",
want: makeResourceWithJobInstanceScheme(&jobInstanceDefinition{
"job", "", "", "", "",
}),
},
{
name: "blank instance, non-blank scheme",
job: "job", instance: "", scheme: "http",
want: makeResourceWithJobInstanceScheme(&jobInstanceDefinition{
"job", "", "", "http", "",
}),
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
got := createNodeAndResourcePdata(tt.job, tt.instance, tt.scheme)
require.Equal(t, got, tt.want)
})
}
}