diff --git a/go.mod b/go.mod index 4853f77..fde39d6 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module contrib.go.opencensus.io/exporter/ocagent require ( github.com/census-instrumentation/opencensus-proto v0.2.0 // this is to match the version used in census-instrumentation/opencensus-service github.com/golang/protobuf v1.3.1 + github.com/google/go-cmp v0.3.0 github.com/grpc-ecosystem/grpc-gateway v1.8.5 // indirect go.opencensus.io v0.22.0 google.golang.org/api v0.5.0 diff --git a/ocagent.go b/ocagent.go index b3a1388..8c43eb9 100644 --- a/ocagent.go +++ b/ocagent.go @@ -70,6 +70,7 @@ type Exporter struct { nodeInfo *commonpb.Node grpcClientConn *grpc.ClientConn reconnectionPeriod time.Duration + resourceDetector resource.Detector resource *resourcepb.Resource compressor string headers map[string]string @@ -125,7 +126,17 @@ func NewUnstartedExporter(opts ...ExporterOption) (*Exporter, error) { viewDataBundler.BundleCountThreshold = 500 // TODO: (@odeke-em) make this configurable. e.viewDataBundler = viewDataBundler e.nodeInfo = NodeWithStartTime(e.serviceName) - e.resource = resourceProtoFromEnv() + if e.resourceDetector != nil { + res, err := e.resourceDetector(context.Background()) + if err != nil { + panic(fmt.Sprintf("Error detecting resource. err:%v\n", err)) + } + if res != nil { + e.resource = resourceToResourcePb(res) + } + } else { + e.resource = resourceProtoFromEnv() + } return e, nil } @@ -512,7 +523,10 @@ func resourceProtoFromEnv() *resourcepb.Resource { if rs == nil { return nil } + return resourceToResourcePb(rs) +} +func resourceToResourcePb(rs *resource.Resource) *resourcepb.Resource { rprs := &resourcepb.Resource{ Type: rs.Type, } diff --git a/options.go b/options.go index edeae65..6820216 100644 --- a/options.go +++ b/options.go @@ -17,6 +17,7 @@ package ocagent import ( "time" + "go.opencensus.io/resource" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) @@ -30,6 +31,22 @@ type ExporterOption interface { withExporter(e *Exporter) } +type resourceDetector resource.Detector + +var _ ExporterOption = (*resourceDetector)(nil) + +func (rd resourceDetector) withExporter(e *Exporter) { + e.resourceDetector = resource.Detector(rd) +} + +// WithResourceDetector allows one to register a resource detector. Resource Detector is used +// to detect resources associated with the application. Detected resource is exported +// along with the metrics. If the detector fails then it panics. +// If a resource detector is not provided then by default it detects from the environment. +func WithResourceDetector(rd resource.Detector) ExporterOption { + return resourceDetector(rd) +} + type insecureGrpcConnection int var _ ExporterOption = (*insecureGrpcConnection)(nil) diff --git a/resource_detector_test.go b/resource_detector_test.go new file mode 100644 index 0000000..eef86ce --- /dev/null +++ b/resource_detector_test.go @@ -0,0 +1,54 @@ +// Copyright 2019, OpenCensus 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 ocagent + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "go.opencensus.io/resource" + + resourcepb "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1" +) + +func TestResourceDetector(t *testing.T) { + ocexp, err := NewExporter( + WithInsecure(), + WithAddress(":0"), + WithResourceDetector(customResourceDetector), + ) + if err != nil { + t.Fatalf("Failed to create the ocagent exporter: %v", err) + } + defer ocexp.Stop() + + got := ocexp.resource + want := &resourcepb.Resource{ + Type: "foo", + Labels: map[string]string{}, + } + if !cmp.Equal(got, want) { + t.Fatalf("Resource detection failed. got %v, want %v\n", got, want) + } +} + +func customResourceDetector(context.Context) (*resource.Resource, error) { + res := &resource.Resource{ + Type: "foo", + Labels: map[string]string{}, + } + return res, nil +}