-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
* Integrate with core resource and known detectors Signed-off-by: Fabian Reinartz <[email protected]> * Fix typo Signed-off-by: Fabian Reinartz <[email protected]>
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// 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 stackdriver // import "contrib.go.opencensus.io/exporter/stackdriver" | ||
|
||
import ( | ||
"contrib.go.opencensus.io/resource/resourcekeys" | ||
"go.opencensus.io/resource" | ||
monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" | ||
) | ||
|
||
type resourceMap struct { | ||
// Mapping from the input resource type to the monitored resource type in Stackdriver. | ||
srcType, dstType string | ||
// Mapping from Stackdriver monitored resource label to an OpenCensus resource label. | ||
labels map[string]string | ||
} | ||
|
||
// Resource labels that are generally internal to the exporter. | ||
// Consider exposing these labels and a type identifier in the future to allow | ||
// for customization. | ||
const ( | ||
stackdriverLocation = "contrib.opencensus.io/exporter/stackdriver/location" | ||
stackdriverProjectID = "contrib.opencensus.io/exporter/stackdriver/project_id" | ||
stackdriverGenericTaskNamespace = "contrib.opencensus.io/exporter/stackdriver/generic_task/namespace" | ||
stackdriverGenericTaskJob = "contrib.opencensus.io/exporter/stackdriver/generic_task/job" | ||
stackdriverGenericTaskID = "contrib.opencensus.io/exporter/stackdriver/generic_task/task_id" | ||
) | ||
|
||
// 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, | ||
}, | ||
}, | ||
} | ||
|
||
func DefaultMapResource(res *resource.Resource) *monitoredrespb.MonitoredResource { | ||
Outer: | ||
for _, rm := range resourceMappings { | ||
if res.Type != rm.srcType { | ||
continue | ||
} | ||
result := &monitoredrespb.MonitoredResource{ | ||
Type: rm.dstType, | ||
Labels: make(map[string]string, len(rm.labels)), | ||
} | ||
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 | ||
} | ||
} | ||
return result | ||
} | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// 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 stackdriver // import "contrib.go.opencensus.io/exporter/stackdriver" | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"contrib.go.opencensus.io/resource/resourcekeys" | ||
"github.com/google/go-cmp/cmp" | ||
"go.opencensus.io/resource" | ||
monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" | ||
) | ||
|
||
func TestDefaultMapResource(t *testing.T) { | ||
cases := []struct { | ||
input *resource.Resource | ||
want *monitoredrespb.MonitoredResource | ||
}{ | ||
// Verify that the mapping works and that we skip over the | ||
// first mapping that doesn't apply. | ||
{ | ||
input: &resource.Resource{ | ||
Type: resourcekeys.GCPTypeGCEInstance, | ||
Labels: map[string]string{ | ||
resourcekeys.GCPKeyGCEProjectID: "proj1", | ||
resourcekeys.GCPKeyGCEInstanceID: "inst1", | ||
resourcekeys.GCPKeyGCEZone: "zone1", | ||
"extra_key": "must be ignored", | ||
}, | ||
}, | ||
want: &monitoredrespb.MonitoredResource{ | ||
Type: "gce_instance", | ||
Labels: map[string]string{ | ||
"project_id": "proj1", | ||
"instance_id": "inst1", | ||
"zone": "zone1", | ||
}, | ||
}, | ||
}, | ||
// No match due to missing key. | ||
{ | ||
input: &resource.Resource{ | ||
Type: resourcekeys.GCPTypeGCEInstance, | ||
Labels: map[string]string{ | ||
resourcekeys.GCPKeyGCEProjectID: "proj1", | ||
resourcekeys.GCPKeyGCEInstanceID: "inst1", | ||
}, | ||
}, | ||
want: nil, | ||
}, | ||
} | ||
for i, c := range cases { | ||
t.Run(fmt.Sprintf("case-%d", i), func(t *testing.T) { | ||
got := DefaultMapResource(c.input) | ||
if diff := cmp.Diff(got, c.want); diff != "" { | ||
t.Errorf("Values differ -got +want: %s", diff) | ||
} | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,10 +52,14 @@ import ( | |
"errors" | ||
"fmt" | ||
"log" | ||
"os" | ||
"path" | ||
"time" | ||
|
||
metadataapi "cloud.google.com/go/compute/metadata" | ||
traceapi "cloud.google.com/go/trace/apiv2" | ||
"contrib.go.opencensus.io/exporter/stackdriver/monitoredresource" | ||
"go.opencensus.io/resource" | ||
"go.opencensus.io/stats/view" | ||
"go.opencensus.io/tag" | ||
"go.opencensus.io/trace" | ||
|
@@ -73,9 +77,22 @@ type Options struct { | |
// ProjectID is the identifier of the Stackdriver | ||
// project the user is uploading the stats data to. | ||
// If not set, this will default to your "Application Default Credentials". | ||
// For details see: https://developers.google.com/accounts/docs/application-default-credentials | ||
// For details see: https://developers.google.com/accounts/docs/application-default-credentials. | ||
// | ||
// It will be used in the project_id label of a Stackdriver monitored | ||
// resource if the resource does not inherently belong to a specific | ||
// project, e.g. on-premise resource like k8s_container or generic_task. | ||
ProjectID string | ||
|
||
// Location is the identifier of the GCP or AWS cloud region/zone in which | ||
// the data for a resource is stored. | ||
// If not set, it will default to the location provided by the metadata server. | ||
// | ||
// It will be used in the location label of a Stackdriver monitored resource | ||
// if the resource does not inherently belong to a specific project, e.g. | ||
// on-premise resource like k8s_container or generic_task. | ||
Location string | ||
|
||
// OnError is the hook to be called when there is | ||
// an error uploading the stats or tracing data. | ||
// If no custom hook is set, errors are logged. | ||
|
@@ -153,6 +170,21 @@ type Options struct { | |
// Optional, but encouraged. | ||
MonitoredResource monitoredresource.Interface | ||
|
||
// ResourceDetector provides a hook to discover arbitrary resource information. | ||
// | ||
// The translation function provided in MapResource must be able to conver the | ||
// the resource information to a Stackdriver monitored resource. | ||
// | ||
// If this field is unset, resource type and tags will automatically be discovered through | ||
// the OC_RESOURCE_TYPE and OC_RESOURCE_LABELS environment variables. | ||
ResourceDetector resource.Detector | ||
|
||
// MapResource converts a OpenCensus resource to a Stackdriver monitored resource. | ||
// | ||
// If this field is unset, DefaultMapResource will be used which encodes a set of default | ||
// conversions from auto-detected resources to well-known Stackdriver monitored resources. | ||
MapResource func(*resource.Resource) *monitoredrespb.MonitoredResource | ||
|
||
// MetricPrefix overrides the prefix of a Stackdriver metric display names. | ||
// Optional. If unset defaults to "OpenCensus/". | ||
// Deprecated: Provide GetMetricDisplayName to change the display name of | ||
|
@@ -253,10 +285,45 @@ func NewExporter(o Options) (*Exporter, error) { | |
} | ||
o.ProjectID = creds.ProjectID | ||
} | ||
if o.Location == "" { | ||
ctx := o.Context | ||
if ctx == nil { | ||
ctx = context.Background() | ||
} | ||
zone, err := metadataapi.Zone() | ||
if err != nil { | ||
log.Printf("Setting Stackdriver default location failed: %s", err) | ||
} else { | ||
log.Printf("Setting Stackdriver default location to %q", zone) | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
rghetia
Contributor
|
||
o.Location = zone | ||
} | ||
} | ||
|
||
if o.MonitoredResource != nil { | ||
o.Resource = convertMonitoredResourceToPB(o.MonitoredResource) | ||
} | ||
if o.MapResource == nil { | ||
o.MapResource = DefaultMapResource | ||
} | ||
if o.ResourceDetector != nil { | ||
// For backwards-compatibility we still respect the deprecated resource field. | ||
if o.Resource != nil { | ||
return nil, errors.New("stackdriver: ResourceDetector must not be used in combination with deprecated resource fields") | ||
} | ||
res, err := o.ResourceDetector(o.Context) | ||
if err != nil { | ||
return nil, fmt.Errorf("stackdriver: detect resource: %s", err) | ||
} | ||
// Populate internal resource labels for defaulting project_id, location, and | ||
// generic resource labels of applicable monitored resources. | ||
res.Labels[stackdriverProjectID] = o.ProjectID | ||
res.Labels[stackdriverLocation] = o.Location | ||
res.Labels[stackdriverGenericTaskNamespace] = "default" | ||
res.Labels[stackdriverGenericTaskJob] = path.Base(os.Args[0]) | ||
res.Labels[stackdriverGenericTaskID] = getTaskValue() | ||
|
||
o.Resource = o.MapResource(res) | ||
} | ||
|
||
se, err := newStatsExporter(o) | ||
if err != nil { | ||
|
Error or not, a line is dumped in the logs.
Was this intentional? How can we tell good logs from bad?
Should the error had been returned in the first case and perhaps no log written in the good case?