Skip to content

Commit

Permalink
Map faas.* attributes to generic task after service.name, but ignore …
Browse files Browse the repository at this point in the history
…unknown_service (#764)

* update to v1.21.0 of semconv, and use FaasInstance instead of FaaSID

* only use unknown_service as a fallback for job label

* add comment
  • Loading branch information
dashpole authored Nov 3, 2023
1 parent f8a04f0 commit 0b578e8
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 53 deletions.
2 changes: 1 addition & 1 deletion example/metric/sdk/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"go.opentelemetry.io/otel/metric"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
)

type observedFloat struct {
Expand Down
2 changes: 1 addition & 1 deletion example/trace/http/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
"go.opentelemetry.io/otel/trace"

texporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace"
Expand Down
27 changes: 24 additions & 3 deletions exporter/collector/googlemanagedprometheus/monitoredresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package googlemanagedprometheus

import (
"strings"

"go.opentelemetry.io/collector/pdata/pcommon"
semconv "go.opentelemetry.io/collector/semconv/v1.18.0"
monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
Expand All @@ -32,6 +34,7 @@ const (
jobLabel = "job"
serviceNamespaceLabel = "service_namespace"
instanceLabel = "instance"
unknownServicePrefix = "unknown_service"
)

// promTargetKeys are attribute keys which are used in the prometheus_target monitored resource.
Expand All @@ -40,9 +43,9 @@ var promTargetKeys = map[string][]string{
locationLabel: {locationLabel, semconv.AttributeCloudAvailabilityZone, semconv.AttributeCloudRegion},
clusterLabel: {clusterLabel, semconv.AttributeK8SClusterName},
namespaceLabel: {namespaceLabel, semconv.AttributeK8SNamespaceName},
jobLabel: {jobLabel, semconv.AttributeFaaSName, semconv.AttributeServiceName},
jobLabel: {jobLabel, semconv.AttributeServiceName, semconv.AttributeFaaSName},
serviceNamespaceLabel: {semconv.AttributeServiceNamespace},
instanceLabel: {instanceLabel, semconv.AttributeFaaSInstance, semconv.AttributeServiceInstanceID},
instanceLabel: {instanceLabel, semconv.AttributeServiceInstanceID, semconv.AttributeFaaSInstance},
}

func (c Config) MapToPrometheusTarget(res pcommon.Resource) *monitoredrespb.MonitoredResource {
Expand All @@ -69,9 +72,27 @@ func (c Config) MapToPrometheusTarget(res pcommon.Resource) *monitoredrespb.Moni
// getStringOrEmpty returns the value of the first key found, or the empty string.
func getStringOrEmpty(attributes pcommon.Map, keys ...string) string {
for _, k := range keys {
if val, ok := attributes.Get(k); ok {
// skip the attribute if it starts with unknown_service, since the SDK
// sets this by default. It is used as a fallback below if no other
// values are found.
if val, ok := attributes.Get(k); ok && !strings.HasPrefix(val.Str(), unknownServicePrefix) {
return val.Str()
}
}
if contains(keys, string(semconv.AttributeServiceName)) {
// the service name started with unknown_service, and was ignored above
if val, ok := attributes.Get(semconv.AttributeServiceName); ok {
return val.Str()
}
}
return ""
}

func contains(list []string, element string) bool {
for _, item := range list {
if item == element {
return true
}
}
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func TestMapToPrometheusTarget(t *testing.T) {
desc: "Attributes from cloud run",
resourceLabels: map[string]string{
"cloud.region": "us-central1",
"service.name": "service:unknown",
"service.name": "unknown_service:go",
"faas.name": "my-cloud-run-service",
"faas.instance": "1234759430923053489543203",
},
Expand Down
68 changes: 66 additions & 2 deletions exporter/collector/monitoredresource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ func TestResourceMetricsToMonitoringMonitoredResource(t *testing.T) {
"cloud.provider": "gcp",
"cloud.platform": "gcp_app_engine",
"cloud.availability_zone": "my-zone",
"faas.id": "myinstanceid",
"faas.instance": "myinstanceid",
"faas.name": "myhostname",
"faas.version": "v1",
},
Expand All @@ -517,6 +517,70 @@ func TestResourceMetricsToMonitoringMonitoredResource(t *testing.T) {
},
},
},
{
name: "Cloud Run Instance",
resourceLabels: map[string]string{
"cloud.provider": "gcp",
"cloud.platform": "gcp_cloud_run",
"cloud.region": "my-region",
"faas.instance": "myinstanceid",
"faas.name": "myfaasname",
"faas.version": "v1",
},
expectMr: &monitoredrespb.MonitoredResource{
Type: "generic_task",
Labels: map[string]string{
"job": "myfaasname",
"location": "my-region",
"namespace": "",
"task_id": "myinstanceid",
},
},
},
{
name: "Cloud Run Instance with default service",
resourceLabels: map[string]string{
"cloud.provider": "gcp",
"cloud.platform": "gcp_cloud_run",
"cloud.region": "my-region",
"service.name": "unknown_service:go",
"faas.instance": "myinstanceid",
"faas.name": "myfaasname",
"faas.version": "v1",
},
expectMr: &monitoredrespb.MonitoredResource{
Type: "generic_task",
Labels: map[string]string{
"job": "myfaasname",
"location": "my-region",
"namespace": "",
"task_id": "myinstanceid",
},
},
},
{
name: "Cloud Run Instance with custom service",
resourceLabels: map[string]string{
"cloud.provider": "gcp",
"cloud.platform": "gcp_cloud_run",
"cloud.region": "my-region",
"service.name": "customservice",
"service.namespace": "customnamespace",
"service.instance.id": "customserviceid",
"faas.instance": "myinstanceid",
"faas.name": "myfaasname",
"faas.version": "v1",
},
expectMr: &monitoredrespb.MonitoredResource{
Type: "generic_task",
Labels: map[string]string{
"job": "customservice",
"location": "my-region",
"namespace": "customnamespace",
"task_id": "customserviceid",
},
},
},
}

for _, test := range tests {
Expand All @@ -543,7 +607,7 @@ func TestResourceMetricsToLoggingMonitoredResource(t *testing.T) {
"cloud.provider": "gcp",
"cloud.platform": "gcp_app_engine",
"cloud.availability_zone": "my-zone",
"faas.id": "myhostid",
"faas.instance": "myhostid",
"faas.name": "myhostname",
"faas.version": "v1",
},
Expand Down
11 changes: 6 additions & 5 deletions exporter/metric/metric_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"

"cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -569,15 +569,16 @@ func TestResourceToMonitoredResourcepb(t *testing.T) {
},
},
{
desc: "Cloud Run From Detector",
desc: "Cloud Run From Detector with default service",
resource: resource.NewWithAttributes(
semconv.SchemaURL,
attribute.String("cloud.provider", "gcp"),
attribute.String("cloud.platform", "gcp_cloud_run"),
attribute.String("cloud.region", "utopia"),
attribute.String("faas.id", "bar"),
attribute.String("faas.instance", "bar"),
attribute.String("faas.name", "x-service"),
attribute.String("faas.version", "v1"),
attribute.String("service.name", "unknown_service:go"),
),
expectedType: "generic_task",
expectedLabels: map[string]string{
Expand All @@ -594,7 +595,7 @@ func TestResourceToMonitoredResourcepb(t *testing.T) {
attribute.String("cloud.provider", "gcp"),
attribute.String("cloud.platform", "gcp_cloud_functions"),
attribute.String("cloud.region", "utopia"),
attribute.String("faas.id", "bar"),
attribute.String("faas.instance", "bar"),
attribute.String("faas.name", "x-service"),
attribute.String("faas.version", "v1"),
),
Expand All @@ -613,7 +614,7 @@ func TestResourceToMonitoredResourcepb(t *testing.T) {
attribute.String("cloud.provider", "gcp"),
attribute.String("cloud.platform", "gcp_app_engine"),
attribute.String("cloud.availability_zone", "utopia"),
attribute.String("faas.id", "bar"),
attribute.String("faas.instance", "bar"),
attribute.String("faas.name", "x-service"),
attribute.String("faas.version", "v1"),
),
Expand Down
2 changes: 1 addition & 1 deletion exporter/metric/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"

apioption "google.golang.org/api/option"
)
Expand Down
92 changes: 53 additions & 39 deletions internal/resourcemapping/resourcemapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,47 @@ package resourcemapping
import (
"strings"

semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
)

const (
ProjectIDAttributeKey = "gcp.project.id"

awsAccount = "aws_account"
awsEc2Instance = "aws_ec2_instance"
clusterName = "cluster_name"
containerName = "container_name"
gceInstance = "gce_instance"
genericNode = "generic_node"
genericTask = "generic_task"
instanceID = "instance_id"
job = "job"
k8sCluster = "k8s_cluster"
k8sContainer = "k8s_container"
k8sNode = "k8s_node"
k8sPod = "k8s_pod"
location = "location"
namespace = "namespace"
namespaceName = "namespace_name"
nodeID = "node_id"
nodeName = "node_name"
podName = "pod_name"
region = "region"
taskID = "task_id"
zone = "zone"
gaeInstance = "gae_instance"
gaeApp = "gae_app"
gaeModuleID = "module_id"
gaeVersionID = "version_id"
cloudRunRevision = "cloud_run_revision"
cloudFunction = "cloud_function"
cloudFunctionName = "function_name"
serviceName = "service_name"
configurationName = "configuration_name"
revisionName = "revision_name"
bmsInstance = "baremetalsolution.googleapis.com/Instance"
awsAccount = "aws_account"
awsEc2Instance = "aws_ec2_instance"
clusterName = "cluster_name"
containerName = "container_name"
gceInstance = "gce_instance"
genericNode = "generic_node"
genericTask = "generic_task"
instanceID = "instance_id"
job = "job"
k8sCluster = "k8s_cluster"
k8sContainer = "k8s_container"
k8sNode = "k8s_node"
k8sPod = "k8s_pod"
location = "location"
namespace = "namespace"
namespaceName = "namespace_name"
nodeID = "node_id"
nodeName = "node_name"
podName = "pod_name"
region = "region"
taskID = "task_id"
zone = "zone"
gaeInstance = "gae_instance"
gaeApp = "gae_app"
gaeModuleID = "module_id"
gaeVersionID = "version_id"
cloudRunRevision = "cloud_run_revision"
cloudFunction = "cloud_function"
cloudFunctionName = "function_name"
serviceName = "service_name"
configurationName = "configuration_name"
revisionName = "revision_name"
bmsInstance = "baremetalsolution.googleapis.com/Instance"
unknownServicePrefix = "unknown_service"
)

var (
Expand Down Expand Up @@ -115,7 +116,7 @@ var (
}},
gaeModuleID: {otelKeys: []string{string(semconv.FaaSNameKey)}},
gaeVersionID: {otelKeys: []string{string(semconv.FaaSVersionKey)}},
instanceID: {otelKeys: []string{string(semconv.FaaSIDKey)}},
instanceID: {otelKeys: []string{string(semconv.FaaSInstanceKey)}},
},
gaeApp: {
location: {otelKeys: []string{
Expand Down Expand Up @@ -149,7 +150,7 @@ var (
},
namespace: {otelKeys: []string{string(semconv.ServiceNamespaceKey)}},
job: {otelKeys: []string{string(semconv.ServiceNameKey), string(semconv.FaaSNameKey)}},
taskID: {otelKeys: []string{string(semconv.ServiceInstanceIDKey), string(semconv.FaaSIDKey)}},
taskID: {otelKeys: []string{string(semconv.ServiceInstanceIDKey), string(semconv.FaaSInstanceKey)}},
},
genericNode: {
location: {
Expand Down Expand Up @@ -229,8 +230,8 @@ func commonResourceAttributesToMonitoredResource(cloudPlatform string, attrs Rea
_, hasServiceName := attrs.GetString(string(semconv.ServiceNameKey))
_, hasFaaSName := attrs.GetString(string(semconv.FaaSNameKey))
_, hasServiceInstanceID := attrs.GetString(string(semconv.ServiceInstanceIDKey))
_, hasFaaSID := attrs.GetString(string(semconv.FaaSIDKey))
if (hasServiceName && hasServiceInstanceID) || (hasFaaSID && hasFaaSName) {
_, hasFaaSInstance := attrs.GetString(string(semconv.FaaSInstanceKey))
if (hasServiceName && hasServiceInstanceID) || (hasFaaSInstance && hasFaaSName) {
return createMonitoredResource(genericTask, attrs)
}

Expand All @@ -252,10 +253,14 @@ func createMonitoredResource(
// Coalesce the possible keys in order
for _, otelKey := range mappingConfig.otelKeys {
mrValue, ok = resourceAttrs.GetString(otelKey)
if mrValue != "" {
if mrValue != "" && !strings.HasPrefix(mrValue, unknownServicePrefix) {
break
}
}
if mrValue == "" && contains(mappingConfig.otelKeys, string(semconv.ServiceNameKey)) {
// the service name started with unknown_service, and was ignored above
mrValue, ok = resourceAttrs.GetString(string(semconv.ServiceNameKey))
}
if !ok || mrValue == "" {
mrValue = mappingConfig.fallbackLiteral
}
Expand All @@ -267,6 +272,15 @@ func createMonitoredResource(
}
}

func contains(list []string, element string) bool {
for _, item := range list {
if item == element {
return true
}
}
return false
}

func sanitizeUTF8(s string) string {
return strings.ToValidUTF8(s, "�")
}

0 comments on commit 0b578e8

Please sign in to comment.