diff --git a/contrib/opencensus-ext-stackdriver/opencensus/ext/stackdriver/stats_exporter/__init__.py b/contrib/opencensus-ext-stackdriver/opencensus/ext/stackdriver/stats_exporter/__init__.py index 271935190..637202d85 100644 --- a/contrib/opencensus-ext-stackdriver/opencensus/ext/stackdriver/stats_exporter/__init__.py +++ b/contrib/opencensus-ext-stackdriver/opencensus/ext/stackdriver/stats_exporter/__init__.py @@ -25,6 +25,9 @@ import google.auth from opencensus.common import utils +from opencensus.common.monitored_resource import aws_identity_doc_utils +from opencensus.common.monitored_resource import gcp_metadata_config +from opencensus.common.monitored_resource import k8s_utils from opencensus.common.monitored_resource import monitored_resource from opencensus.common.version import __version__ from opencensus.metrics import label_key @@ -300,62 +303,65 @@ def register_metric_descriptor(self, oc_md): def set_monitored_resource(series, option_resource_type): - """Set a resource(type and labels) that can be used for monitoring. + """Set this series' monitored resource and labels. + :param series: TimeSeries object based on view data :param option_resource_type: Resource is an optional field that represents the Stackdriver MonitoredResource type. """ - resource_type = GLOBAL_RESOURCE_TYPE - - if option_resource_type == "": - resource = monitored_resource.get_instance() - if resource is not None: - resource_labels = resource.get_labels() - - if resource.get_type() == 'gke_container': - resource_type = 'k8s_container' - set_attribute_label(series, resource_labels, 'project_id') - set_attribute_label(series, resource_labels, 'cluster_name') - set_attribute_label(series, resource_labels, 'container_name') - set_attribute_label(series, resource_labels, 'namespace_id', - 'namespace_name') - set_attribute_label(series, resource_labels, 'pod_id', - 'pod_name') - set_attribute_label(series, resource_labels, 'zone', - 'location') - - elif resource.get_type() == 'gce_instance': - resource_type = 'gce_instance' - set_attribute_label(series, resource_labels, 'project_id') - set_attribute_label(series, resource_labels, 'instance_id') - set_attribute_label(series, resource_labels, 'zone') - - elif resource.get_type() == 'aws_ec2_instance': - resource_type = 'aws_ec2_instance' - set_attribute_label(series, resource_labels, 'aws_account') - set_attribute_label(series, resource_labels, 'instance_id') - set_attribute_label(series, resource_labels, 'region', - label_value_prefix='aws:') - else: - resource_type = option_resource_type - series.resource.type = resource_type + if option_resource_type != "": + series.resource.type = option_resource_type + return + + resource = monitored_resource.get_instance() + if resource is None: + series.resource.type = GLOBAL_RESOURCE_TYPE + return + + resource_type = resource.get_type() + resource_labels = resource.get_labels() + + def set_attribute_label(attribute_key, label_key, label_value_prefix=''): + """Set a label to timeseries that can be used for monitoring. + + :param series: TimeSeries object based on view data + :param resource_labels: collection of labels + :param attribute_key: actual label key + :param label_key: optional exporter-specific label key + :param label_value_prefix: optional exporter-specific prefix + """ + if attribute_key not in resource_labels: + return + + series.resource.labels[label_key] = (label_value_prefix + + resource_labels[attribute_key]) + + if resource_type == 'k8s_container': + series.resource.type = 'k8s_container' + set_attribute_label(gcp_metadata_config.PROJECT_ID_KEY, 'project_id') + set_attribute_label(k8s_utils.CLUSTER_NAME_KEY, 'cluster_name') + set_attribute_label(k8s_utils.CONTAINER_NAME_KEY, 'container_name') + set_attribute_label(k8s_utils.NAMESPACE_NAME_KEY, 'namespace_name') + set_attribute_label(k8s_utils.POD_NAME_KEY, 'pod_name') + set_attribute_label(gcp_metadata_config.ZONE_KEY, 'location') + + elif resource_type == 'gce_instance': + series.resource.type = 'gce_instance' + set_attribute_label(gcp_metadata_config.PROJECT_ID_KEY, 'project_id') + set_attribute_label(gcp_metadata_config.INSTANCE_ID_KEY, 'instance_id') + set_attribute_label(gcp_metadata_config.ZONE_KEY, 'zone') + + elif resource_type == 'aws_ec2_instance': + series.resource.type = 'aws_ec2_instance' + set_attribute_label(aws_identity_doc_utils.ACCOUNT_ID_KEY, + 'aws_account') + set_attribute_label(aws_identity_doc_utils.INSTANCE_ID_KEY, + 'instance_id') + set_attribute_label(aws_identity_doc_utils.REGION_KEY, 'region', + label_value_prefix='aws:') - -def set_attribute_label(series, resource_labels, attribute_key, - canonical_key=None, label_value_prefix=''): - """Set a label to timeseries that can be used for monitoring - :param series: TimeSeries object based on view data - :param resource_labels: collection of labels - :param attribute_key: actual label key - :param canonical_key: exporter specific label key, Optional - :param label_value_prefix: exporter specific label value prefix, Optional - """ - if attribute_key in resource_labels: - if canonical_key is None: - canonical_key = attribute_key - - series.resource.labels[canonical_key] = \ - label_value_prefix + resource_labels[attribute_key] + else: + series.resource.type = GLOBAL_RESOURCE_TYPE def get_user_agent_slug(): diff --git a/contrib/opencensus-ext-stackdriver/opencensus/ext/stackdriver/trace_exporter/__init__.py b/contrib/opencensus-ext-stackdriver/opencensus/ext/stackdriver/trace_exporter/__init__.py index 3788e2366..d83d63ba4 100644 --- a/contrib/opencensus-ext-stackdriver/opencensus/ext/stackdriver/trace_exporter/__init__.py +++ b/contrib/opencensus-ext-stackdriver/opencensus/ext/stackdriver/trace_exporter/__init__.py @@ -17,6 +17,9 @@ from google.cloud.trace.client import Client +from opencensus.common.monitored_resource import aws_identity_doc_utils +from opencensus.common.monitored_resource import gcp_metadata_config +from opencensus.common.monitored_resource import k8s_utils from opencensus.common.monitored_resource import monitored_resource from opencensus.common.transports import sync from opencensus.common.version import __version__ @@ -79,58 +82,23 @@ def set_monitored_resource_attributes(span): :param span: Span object """ resource = monitored_resource.get_instance() - if resource is not None: - resource_type = resource.get_type() - resource_labels = resource.get_labels() - - if resource_type == 'gke_container': - resource_type = 'k8s_container' - set_attribute_label(span, resource_type, resource_labels, - 'project_id') - set_attribute_label(span, resource_type, resource_labels, - 'cluster_name') - set_attribute_label(span, resource_type, resource_labels, - 'container_name') - set_attribute_label(span, resource_type, resource_labels, - 'namespace_id', 'namespace_name') - set_attribute_label(span, resource_type, resource_labels, - 'pod_id', 'pod_name') - set_attribute_label(span, resource_type, resource_labels, - 'zone', 'location') - - elif resource_type == 'gce_instance': - set_attribute_label(span, resource_type, resource_labels, - 'project_id') - set_attribute_label(span, resource_type, resource_labels, - 'instance_id') - set_attribute_label(span, resource_type, resource_labels, - 'zone') - - elif resource_type == 'aws_ec2_instance': - set_attribute_label(span, resource_type, resource_labels, - 'aws_account') - set_attribute_label(span, resource_type, resource_labels, - 'instance_id') - set_attribute_label(span, resource_type, resource_labels, - 'region', label_value_prefix='aws:') - - -def set_attribute_label(span, resource_type, resource_labels, attribute_key, - canonical_key=None, label_value_prefix=''): - """Set a label to span that can be used for tracing. - :param span: Span object - :param resource_type: resource type - :param resource_labels: collection of labels - :param attribute_key: actual label key - :param canonical_key: exporter specific label key, Optional - :param label_value_prefix: exporter specific label value prefix, Optional - """ + if resource is None: + return + + resource_type = resource.get_type() + resource_labels = resource.get_labels() - if attribute_key in resource_labels: - if canonical_key is None: - canonical_key = attribute_key + def set_attribute_label(attribute_key, label_key, + label_value_prefix=''): + """Add the attribute to the span attribute map. - pair = {RESOURCE_LABEL % (resource_type, canonical_key): + Update the span attribute map (`span['attributes']['attributeMap']`) to + include a given resource label. + """ + if attribute_key not in resource_labels: + return + + pair = {RESOURCE_LABEL % (resource_type, label_key): label_value_prefix + resource_labels[attribute_key] } pair_attrs = Attributes(pair).format_attributes_json()\ @@ -138,6 +106,27 @@ def set_attribute_label(span, resource_type, resource_labels, attribute_key, _update_attr_map(span, pair_attrs) + if resource_type == 'k8s_container': + set_attribute_label(gcp_metadata_config.PROJECT_ID_KEY, 'project_id') + set_attribute_label(k8s_utils.CLUSTER_NAME_KEY, 'cluster_name') + set_attribute_label(k8s_utils.CONTAINER_NAME_KEY, 'container_name') + set_attribute_label(k8s_utils.NAMESPACE_NAME_KEY, 'namespace_name') + set_attribute_label(k8s_utils.POD_NAME_KEY, 'pod_name') + set_attribute_label(gcp_metadata_config.ZONE_KEY, 'location') + + elif resource_type == 'gce_instance': + set_attribute_label(gcp_metadata_config.PROJECT_ID_KEY, 'project_id') + set_attribute_label(gcp_metadata_config.INSTANCE_ID_KEY, 'instance_id') + set_attribute_label(gcp_metadata_config.ZONE_KEY, 'zone') + + elif resource_type == 'aws_ec2_instance': + set_attribute_label(aws_identity_doc_utils.ACCOUNT_ID_KEY, + 'aws_account') + set_attribute_label(aws_identity_doc_utils.INSTANCE_ID_KEY, + 'instance_id') + set_attribute_label(aws_identity_doc_utils.REGION_KEY, 'region', + label_value_prefix='aws:') + def set_common_attributes(span): """Set the common attributes.""" diff --git a/contrib/opencensus-ext-stackdriver/tests/test_stackdriver_exporter.py b/contrib/opencensus-ext-stackdriver/tests/test_stackdriver_exporter.py index f892afd40..c64806825 100644 --- a/contrib/opencensus-ext-stackdriver/tests/test_stackdriver_exporter.py +++ b/contrib/opencensus-ext-stackdriver/tests/test_stackdriver_exporter.py @@ -678,14 +678,13 @@ def test_monitored_resource_attributes_gke(self, gmr_mock): } mock_resource = mock.Mock() - mock_resource.get_type.return_value = 'gke_container' + mock_resource.get_type.return_value = 'k8s_container' mock_resource.get_labels.return_value = { - 'pod_id': 'pod', - 'cluster_name': 'cluster', - 'namespace_id': 'namespace', - 'container_name': 'c1', + 'k8s.io/pod/name': 'pod', + 'k8s.io/cluster/name': 'cluster', + 'k8s.io/namespace/name': 'namespace', + 'k8s.io/container/name': 'c1', 'project_id': 'my_project', - 'instance_id': 'instance', 'zone': 'zone1' } gmr_mock.return_value = mock_resource diff --git a/contrib/opencensus-ext-stackdriver/tests/test_stackdriver_stats.py b/contrib/opencensus-ext-stackdriver/tests/test_stackdriver_stats.py index f176283cf..f57532acf 100644 --- a/contrib/opencensus-ext-stackdriver/tests/test_stackdriver_stats.py +++ b/contrib/opencensus-ext-stackdriver/tests/test_stackdriver_stats.py @@ -93,8 +93,8 @@ def test_options_parameters(self): def test_default_monitoring_labels(self): options = stackdriver.Options(default_monitoring_labels={ - label_key.LabelKey('lk_key', 'lk_desc'): - label_value.LabelValue('lk_value') + label_key.LabelKey('lk_key', 'lk_desc'): + label_value.LabelValue('lk_value') }) self.assertEqual(len(options.default_monitoring_labels), 1) @@ -876,8 +876,8 @@ def test_create_timeseries_with_resource(self, monitor_resource_mock): 'instance_id': 'my-instance', 'project_id': 'my-project', 'zone': 'us-east1', - 'pod_id': 'localhost', - 'namespace_id': 'namespace' + 'k8s.io/pod/name': 'localhost', + 'k8s.io/namespace/name': 'namespace', } mock_resource = mock.Mock() @@ -908,18 +908,18 @@ def test_create_timeseries_with_resource(self, monitor_resource_mock): time_series.metric.type, "custom.googleapis.com/opencensus/my.org/views/video_size_test2") - # check for gke_container monitored resource + # check for k8s_container monitored resource mocked_labels = { 'instance_id': 'my-instance', 'project_id': 'my-project', 'zone': 'us-east1', - 'pod_id': 'localhost', - 'cluster_name': 'cluster', - 'namespace_id': 'namespace' + 'k8s.io/pod/name': 'localhost', + 'k8s.io/cluster/name': 'cluster', + 'k8s.io/namespace/name': 'namespace', } mock_resource = mock.Mock() - mock_resource.get_type.return_value = 'gke_container' + mock_resource.get_type.return_value = 'k8s_container' mock_resource.get_labels.return_value = mocked_labels monitor_resource_mock.return_value = mock_resource diff --git a/opencensus/common/monitored_resource/aws_identity_doc_utils.py b/opencensus/common/monitored_resource/aws_identity_doc_utils.py index 5049d4bd1..0b2b7ab98 100644 --- a/opencensus/common/monitored_resource/aws_identity_doc_utils.py +++ b/opencensus/common/monitored_resource/aws_identity_doc_utils.py @@ -15,6 +15,10 @@ from opencensus.common.http_handler import get_request import json +REGION_KEY = 'region' +ACCOUNT_ID_KEY = 'aws_account' +INSTANCE_ID_KEY = 'instance_id' + # AWS provides Instance Metadata via below url _AWS_INSTANCE_IDENTITY_DOCUMENT_URI = \ "http://169.254.169.254/latest/dynamic/instance-identity/document" @@ -23,13 +27,13 @@ # Region is the AWS region for the VM. The format of this field is # "aws:{region}", where supported values for {region} are listed at # http://docs.aws.amazon.com/general/latest/gr/rande.html. - 'region': 'region', + 'region': REGION_KEY, # accountId is the AWS account number for the VM. - 'accountId': 'aws_account', + 'accountId': ACCOUNT_ID_KEY, # instanceId is the instance id of the instance. - 'instanceId': 'instance_id' + 'instanceId': INSTANCE_ID_KEY } # inited is used to make sure AWS initialize executes only once. diff --git a/tests/unit/common/monitored_resource_util/test_monitored_resource.py b/tests/unit/common/monitored_resource_util/test_monitored_resource.py index 7274dd5ba..4cbe537d2 100644 --- a/tests/unit/common/monitored_resource_util/test_monitored_resource.py +++ b/tests/unit/common/monitored_resource_util/test_monitored_resource.py @@ -112,12 +112,12 @@ def test_gcp_k8s_monitored_resource(self, gcp_md_mock): mocked_labels = { 'instance_id': 'my-instance', - 'cluster_name': 'cluster', 'project_id': 'my-project', 'zone': 'us-east1', - 'pod_id': 'localhost', - 'namespace_id': 'namespace', - 'container_name': 'container' + 'k8s.io/cluster/name': 'cluster', + 'k8s.io/pod/name': 'localhost', + 'k8s.io/namespace/name': 'namespace', + 'k8s.io/container/name': 'container' } cluster_name_key = 'instance/attributes/cluster-name' cluster_name_val = 'cluster'