diff --git a/go.mod b/go.mod index b8d405d..ef1ef43 100644 --- a/go.mod +++ b/go.mod @@ -2,14 +2,14 @@ module contrib.go.opencensus.io/exporter/stackdriver require ( cloud.google.com/go v0.38.0 - contrib.go.opencensus.io/resource v0.0.0-20190131005048-21591786a5e0 + contrib.go.opencensus.io/resource v0.1.0 github.com/aws/aws-sdk-go v1.19.18 github.com/census-instrumentation/opencensus-proto v0.2.0 github.com/golang/protobuf v1.3.1 - github.com/google/go-cmp v0.2.0 + github.com/google/go-cmp v0.3.0 github.com/stretchr/testify v1.3.0 // indirect - go.opencensus.io v0.21.0 - golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 + go.opencensus.io v0.22.0 + golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a google.golang.org/api v0.5.0 google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb diff --git a/go.sum b/go.sum index 09a06ec..ac6dc8d 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,7 @@ cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -contrib.go.opencensus.io/resource v0.0.0-20190131005048-21591786a5e0 h1:ICrSnXeuT4427bpR8X9I7GxiyT4X5qgLtFT7m1IjK2c= -contrib.go.opencensus.io/resource v0.0.0-20190131005048-21591786a5e0/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= +contrib.go.opencensus.io/resource v0.1.0/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/aws/aws-sdk-go v1.19.18 h1:Hb3+b9HCqrOrbAtFstUWg7H5TQ+/EcklJtE8VShVs8o= github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -24,12 +23,16 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -38,8 +41,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -54,6 +58,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJV golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 h1:FP8hkuE6yUEaJnK7O2eTuejKWwW+Rhfj80dQ2JcKxCU= golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 h1:KaQtG+aDELoNmXYas3TVkGNYRuq8JQ1aa7LJt8EXVyo= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -69,11 +75,15 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= diff --git a/resource.go b/resource.go index 6ddcc7e..fbd8971 100644 --- a/resource.go +++ b/resource.go @@ -15,8 +15,10 @@ package stackdriver // import "contrib.go.opencensus.io/exporter/stackdriver" import ( - "contrib.go.opencensus.io/resource/resourcekeys" + "fmt" + "go.opencensus.io/resource" + "go.opencensus.io/resource/resourcekeys" monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" ) @@ -39,71 +41,69 @@ const ( ) // Mappings for the well-known OpenCensus resources to applicable Stackdriver resources. -var resourceMappings = []resourceMap{ - { - srcType: resourcekeys.K8STypeContainer, - dstType: "k8s_container", - labels: map[string]string{ - "project_id": stackdriverProjectID, - "location": stackdriverLocation, - "cluster_name": resourcekeys.K8SKeyClusterName, - "namespace_name": resourcekeys.K8SKeyNamespaceName, - "pod_name": resourcekeys.K8SKeyPodName, - "container_name": resourcekeys.K8SKeyContainerName, - }, - }, - { - srcType: resourcekeys.GCPTypeGCEInstance, - dstType: "gce_instance", - labels: map[string]string{ - "project_id": resourcekeys.GCPKeyGCEProjectID, - "instance_id": resourcekeys.GCPKeyGCEInstanceID, - "zone": resourcekeys.GCPKeyGCEZone, - }, - }, - { - srcType: resourcekeys.AWSTypeEC2Instance, - dstType: "aws_ec2_instance", - labels: map[string]string{ - "project_id": stackdriverProjectID, - "instance_id": resourcekeys.AWSKeyEC2InstanceID, - "region": resourcekeys.AWSKeyEC2Region, - "aws_account": resourcekeys.AWSKeyEC2AccountID, - }, - }, - // Fallback to generic task resource. - { - srcType: "", - dstType: "generic_task", - labels: map[string]string{ - "project_id": stackdriverProjectID, - "location": stackdriverLocation, - "namespace": stackdriverGenericTaskNamespace, - "job": stackdriverGenericTaskJob, - "task_id": stackdriverGenericTaskID, - }, - }, +var k8sResourceMap = map[string]string{ + "project_id": stackdriverProjectID, + "location": resourcekeys.CloudKeyZone, + "cluster_name": resourcekeys.K8SKeyClusterName, + "namespace_name": resourcekeys.K8SKeyNamespaceName, + "pod_name": resourcekeys.K8SKeyPodName, + "container_name": resourcekeys.ContainerKeyName, } -func defaultMapResource(res *resource.Resource) *monitoredrespb.MonitoredResource { -Outer: - for _, rm := range resourceMappings { - if res.Type != rm.srcType { - continue +var gcpResourceMap = map[string]string{ + "project_id": stackdriverProjectID, + "instance_id": resourcekeys.HostKeyID, + "zone": resourcekeys.CloudKeyZone, +} + +var awsResourceMap = map[string]string{ + "project_id": stackdriverProjectID, + "instance_id": resourcekeys.HostKeyID, + "region": resourcekeys.CloudKeyRegion, + "aws_account": resourcekeys.CloudKeyAccountID, +} + +// Generic task resource. +var genericResourceMap = map[string]string{ + "project_id": stackdriverProjectID, + "location": stackdriverLocation, + "namespace": stackdriverGenericTaskNamespace, + "job": stackdriverGenericTaskJob, + "task_id": stackdriverGenericTaskID, +} + +func transformResource(match, input map[string]string) (map[string]string, bool) { + output := make(map[string]string, len(input)) + for dst, src := range match { + if v, ok := input[src]; ok { + output[dst] = v } - result := &monitoredrespb.MonitoredResource{ - Type: rm.dstType, - Labels: make(map[string]string, len(rm.labels)), + } + return output, true +} + +func defaultMapResource(res *resource.Resource) *monitoredrespb.MonitoredResource { + match := genericResourceMap + result := &monitoredrespb.MonitoredResource{ + Type: "generic_task", + } + if res.Type == resourcekeys.K8SType { + result.Type = "k8s_container" + match = k8sResourceMap + } else if v, ok := res.Labels[resourcekeys.CloudKeyProvider]; ok { + if v == resourcekeys.CloudProviderGCP { + result.Type = "gce_instance" + match = gcpResourceMap + } else if v == resourcekeys.CloudProviderAWS { + result.Type = "aws_ec2_instance" + match = awsResourceMap } - for dst, src := range rm.labels { - if v, ok := res.Labels[src]; ok { - result.Labels[dst] = v - } else { - // A required label wasn't filled at all. Try subsequent mappings. - continue Outer - } + } + result.Labels, _ = transformResource(match, res.Labels) + if result.Type == "aws_ec2_instance" { + if v, ok := result.Labels["region"]; ok { + result.Labels["region"] = fmt.Sprintf("aws:%s", v) } - return result } - return nil + return result } diff --git a/resource_test.go b/resource_test.go index 01fdce7..efb1228 100644 --- a/resource_test.go +++ b/resource_test.go @@ -18,9 +18,9 @@ import ( "fmt" "testing" - "contrib.go.opencensus.io/resource/resourcekeys" "github.com/google/go-cmp/cmp" "go.opencensus.io/resource" + "go.opencensus.io/resource/resourcekeys" monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" ) @@ -33,14 +33,42 @@ func TestDefaultMapResource(t *testing.T) { // first mapping that doesn't apply. { input: &resource.Resource{ - Type: resourcekeys.GCPTypeGCEInstance, + Type: resourcekeys.K8SType, Labels: map[string]string{ - resourcekeys.GCPKeyGCEProjectID: "proj1", - resourcekeys.GCPKeyGCEInstanceID: "inst1", - resourcekeys.GCPKeyGCEZone: "zone1", + stackdriverProjectID: "proj1", + resourcekeys.K8SKeyClusterName: "cluster1", + resourcekeys.K8SKeyPodName: "pod1", + resourcekeys.K8SKeyNamespaceName: "namespace1", + resourcekeys.ContainerKeyName: "container-name1", + resourcekeys.CloudKeyAccountID: "proj1", + resourcekeys.CloudKeyZone: "zone1", + resourcekeys.CloudKeyRegion: "", "extra_key": "must be ignored", }, }, + want: &monitoredrespb.MonitoredResource{ + Type: "k8s_container", + Labels: map[string]string{ + "project_id": "proj1", + "location": "zone1", + "cluster_name": "cluster1", + "namespace_name": "namespace1", + "pod_name": "pod1", + "container_name": "container-name1", + }, + }, + }, + { + input: &resource.Resource{ + Type: resourcekeys.CloudType, + Labels: map[string]string{ + stackdriverProjectID: "proj1", + resourcekeys.CloudKeyProvider: resourcekeys.CloudProviderGCP, + resourcekeys.HostKeyID: "inst1", + resourcekeys.CloudKeyZone: "zone1", + "extra_key": "must be ignored", + }, + }, want: &monitoredrespb.MonitoredResource{ Type: "gce_instance", Labels: map[string]string{ @@ -50,16 +78,45 @@ func TestDefaultMapResource(t *testing.T) { }, }, }, - // No match due to missing key. { input: &resource.Resource{ - Type: resourcekeys.GCPTypeGCEInstance, + Type: resourcekeys.CloudType, Labels: map[string]string{ - resourcekeys.GCPKeyGCEProjectID: "proj1", - resourcekeys.GCPKeyGCEInstanceID: "inst1", + stackdriverProjectID: "proj1", + resourcekeys.CloudKeyProvider: resourcekeys.CloudProviderAWS, + resourcekeys.HostKeyID: "inst1", + resourcekeys.CloudKeyRegion: "region1", + resourcekeys.CloudKeyAccountID: "account1", + "extra_key": "must be ignored", + }, + }, + want: &monitoredrespb.MonitoredResource{ + Type: "aws_ec2_instance", + Labels: map[string]string{ + "project_id": "proj1", + "instance_id": "inst1", + "region": "aws:region1", + "aws_account": "account1", + }, + }, + }, + // Partial Match + { + input: &resource.Resource{ + Type: resourcekeys.CloudType, + Labels: map[string]string{ + stackdriverProjectID: "proj1", + resourcekeys.CloudKeyProvider: resourcekeys.CloudProviderGCP, + resourcekeys.HostKeyID: "inst1", + }, + }, + want: &monitoredrespb.MonitoredResource{ + Type: "gce_instance", + Labels: map[string]string{ + "project_id": "proj1", + "instance_id": "inst1", }, }, - want: nil, }, } for i, c := range cases {