Skip to content
This repository was archived by the owner on Sep 17, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 47 additions & 52 deletions opencensus/common/monitored_resource_util/monitored_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,75 +12,70 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import os

from opencensus.common.monitored_resource_util.gcp_metadata_config \
import GcpMetadataConfig
from opencensus.common.monitored_resource_util.aws_identity_doc_utils \
import AwsIdentityDocumentUtils
from opencensus.common import resource
from opencensus.common.monitored_resource_util import aws_identity_doc_utils
from opencensus.common.monitored_resource_util import gcp_metadata_config

# supported environments (resource types)

# Supported environments (resource types)
_GCE_INSTANCE = "gce_instance"
_GKE_CONTAINER = "gke_container"
_AWS_EC2_INSTANCE = "aws_ec2_instance"

# Kubenertes environment variables
_KUBERNETES_SERVICE_HOST = 'KUBERNETES_SERVICE_HOST'

class MonitoredResource(object):
"""MonitoredResource returns the resource type and resource labels.
"""

@property
def resource_type(self):
"""Returns the resource type this MonitoredResource.
:return:
"""
raise NotImplementedError # pragma: NO COVER
def is_gke_environment():
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The is_x_environment methods were moved from utils.

"""Whether the environment is a GKE container instance.

def get_resource_labels(self):
"""Returns the resource labels for this MonitoredResource.
:return:
"""
raise NotImplementedError # pragma: NO COVER
The KUBERNETES_SERVICE_HOST environment variable must be set.
"""
return _KUBERNETES_SERVICE_HOST in os.environ


class GcpGceMonitoredResource(MonitoredResource):
"""GceMonitoredResource represents gce_instance type monitored resource.
For definition refer to
https://cloud.google.com/monitoring/api/resources#tag_gce_instance
"""
def is_gce_environment():
"""Whether the environment is a virtual machine on GCE."""
return gcp_metadata_config.GcpMetadataConfig.is_running_on_gcp()

@property
def resource_type(self):
return _GCE_INSTANCE

def get_resource_labels(self):
gcp_config = GcpMetadataConfig()
return gcp_config.get_gce_metadata()
def is_aws_environment():
"""Whether the environment is a virtual machine instance on EC2."""
return aws_identity_doc_utils.AwsIdentityDocumentUtils.is_running_on_aws()


class GcpGkeMonitoredResource(MonitoredResource):
"""GkeMonitoredResource represents gke_container type monitored resource.
For definition refer to
https://cloud.google.com/monitoring/api/resources#tag_gke_container
"""
def get_instance():
"""Get a resource based on the application environment.

@property
def resource_type(self):
return _GKE_CONTAINER
Returns a `Resource` configured for the current environment, or None if the
environment is unknown or unsupported.

def get_resource_labels(self):
gcp_config = GcpMetadataConfig()
return gcp_config.get_gke_metadata()
Supported environments include:

1. 'gke_container'
- https://cloud.google.com/monitoring/api/resources#tag_gke_container
2. 'gce_instance'
- https://cloud.google.com/monitoring/api/resources#tag_gce_instance
3. 'aws_ec2_instance'
- https://cloud.google.com/monitoring/api/resources#tag_aws_ec2_instance

class AwsMonitoredResource(MonitoredResource):
"""AwsMonitoredResource represents aws_ec2_instance type monitored resource.
For definition refer to
https://cloud.google.com/monitoring/api/resources#tag_aws_ec2_instance
:rtype: :class:`opencensus.common.resource.Resource` or None
:return: A `Resource` configured for the current environment.
"""
@property
def resource_type(self):
return _AWS_EC2_INSTANCE

def get_resource_labels(self):
aws_util = AwsIdentityDocumentUtils()
return aws_util.get_aws_metadata()
if is_gke_environment():
return resource.Resource(
_GKE_CONTAINER,
gcp_metadata_config.GcpMetadataConfig().get_gke_metadata())
if is_gce_environment():
return resource.Resource(
_GCE_INSTANCE,
gcp_metadata_config.GcpMetadataConfig().get_gce_metadata())
if is_aws_environment():
return resource.Resource(
_AWS_EC2_INSTANCE,
(aws_identity_doc_utils.AwsIdentityDocumentUtils()
.get_aws_metadata()))

return None

This file was deleted.

126 changes: 126 additions & 0 deletions opencensus/common/resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Copyright 2019 Google Inc.
#
# 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.


from copy import copy
import re


# Matches anything outside ASCII 32-126 inclusive
NON_PRINTABLE_ASCII = re.compile(
r'[^ !"#$%&\'()*+,\-./:;<=>?@\[\\\]^_`{|}~0-9a-zA-Z]')


def merge_resources(r1, r2):
"""Merge two resources to get a new resource.

:type r1: :class:`Resource`
:param r1: The first resource to merge, takes priority in conflicts.

:type r2: :class:`Resource`
:param r2: The second resource to merge.

:rtype: :class:`Resource`
:return: The new combined resource.
"""
type_ = r1.type or r2.type
labels = copy(r2.labels)
labels.update(r1.labels)
return Resource(type_, labels)


def check_ascii_256(string):
"""Check that `string` is printable ASCII and at most 256 chars.

Raise a `ValueError` if this check fails. Note that `string` itself doesn't
have to be ASCII-encoded.

:type string: str
:param string: The string to check.
"""
if string is None:
return
if len(string) > 256:
raise ValueError("Value is longer than 256 characters")
bad_char = NON_PRINTABLE_ASCII.search(string)
if bad_char:
raise ValueError(u'Character "{}" at position {} is not printable '
'ASCII'
.format(
string[bad_char.start():bad_char.end()],
bad_char.start()))


class Resource(object):
"""A description of the entity for which signals are reported.
Comment thread
c24t marked this conversation as resolved.

`type_` and `labels`' keys and values should contain only printable ASCII
and should be at most 256 characters.

See:
https://github.com/census-instrumentation/opencensus-specs/blob/master/resource/Resource.md

:type type_: str
:param type_: The resource type identifier.

:type labels: dict
:param labels: Key-value pairs that describe the entity.
""" # noqa

def __init__(self, type_=None, labels=None):
if type_ is not None and not type_:
raise ValueError("Resource type must not be empty")
check_ascii_256(type_)
if labels is None:
labels = {}
for key, value in labels.items():
if not key:
raise ValueError("Resource key must not be null or empty")
if value is None:
raise ValueError("Resource value must not be null")
check_ascii_256(key)
check_ascii_256(value)

self.type = type_
self.labels = copy(labels)

def get_type(self):
"""Get this resource's type.

:rtype: str
:return: The resource's type.
"""
return self.type

def get_labels(self):
"""Get this resource's labels.

:rtype: dict
:return: The resource's label dict.
"""
return copy(self.labels)

def merge(self, other):
"""Get a copy of this resource combined with another resource.

The combined resource will have the union of both resources' labels,
keeping this resource's label values if they conflict.

:type other: :class:`Resource`
:param other: The other resource to merge.

:rtype: :class:`Resource`
:return: The new combined resource.
"""
return merge_resources(self, other)
19 changes: 9 additions & 10 deletions opencensus/stats/exporters/stackdriver_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@
from google.cloud import monitoring_v3

from opencensus.common import utils
from opencensus.common.monitored_resource_util.monitored_resource_util \
import MonitoredResourceUtil
from opencensus.common.monitored_resource_util import monitored_resource
from opencensus.common.transports import async_
from opencensus.common.version import __version__
from opencensus.stats import aggregation
Expand Down Expand Up @@ -345,11 +344,11 @@ def set_monitored_resource(series, option_resource_type):
resource_type = GLOBAL_RESOURCE_TYPE

if option_resource_type == "":
monitored_resource = MonitoredResourceUtil.get_instance()
if monitored_resource is not None:
resource_labels = monitored_resource.get_resource_labels()
resource = monitored_resource.get_instance()
if resource is not None:
resource_labels = resource.get_labels()

if monitored_resource.resource_type == 'gke_container':
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')
Expand All @@ -361,14 +360,14 @@ def set_monitored_resource(series, option_resource_type):
set_attribute_label(series, resource_labels, 'zone',
'location')

elif monitored_resource.resource_type == 'gce_instance':
resource_type = monitored_resource.resource_type
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 monitored_resource.resource_type == 'aws_ec2_instance':
resource_type = monitored_resource.resource_type
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',
Expand Down
11 changes: 5 additions & 6 deletions opencensus/trace/exporters/stackdriver_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@

from google.cloud.trace.client import Client

from opencensus.common.monitored_resource_util.monitored_resource_util \
import MonitoredResourceUtil
from opencensus.common.monitored_resource_util import monitored_resource
from opencensus.common.transports import sync
from opencensus.common.version import __version__
from opencensus.trace import attributes_helper
Expand Down Expand Up @@ -79,10 +78,10 @@ def set_monitored_resource_attributes(span):
"""Set labels to span that can be used for tracing.
:param span: Span object
"""
monitored_resource = MonitoredResourceUtil.get_instance()
if monitored_resource is not None:
resource_type = monitored_resource.resource_type
resource_labels = monitored_resource.get_resource_labels()
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'
Expand Down
Loading