# Copyright 2016 Google Inc. All rights reserved. # # 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. """Metric Descriptors for the `Google Monitoring API (V3)`_. .. _Google Monitoring API (V3): https://cloud.google.com/monitoring/api/ref_v3/rest/v3/\ projects.metricDescriptors """ import collections from gcloud.monitoring.label import LabelDescriptor class MetricKind(object): """Choices for the `kind of measurement`_. .. _kind of measurement: https://cloud.google.com/monitoring/api/ref_v3/rest/v3/\ projects.metricDescriptors#MetricKind """ METRIC_KIND_UNSPECIFIED = 'METRIC_KIND_UNSPECIFIED' """.. note:: An unspecified kind is not allowed in metric descriptors.""" GAUGE = 'GAUGE' DELTA = 'DELTA' CUMULATIVE = 'CUMULATIVE' class ValueType(object): """Choices for the `metric value type`_. .. _metric value type: https://cloud.google.com/monitoring/api/ref_v3/rest/v3/\ projects.metricDescriptors#ValueType """ VALUE_TYPE_UNSPECIFIED = 'VALUE_TYPE_UNSPECIFIED' """.. note:: An unspecified type is not allowed in metric descriptors.""" BOOL = 'BOOL' INT64 = 'INT64' DOUBLE = 'DOUBLE' STRING = 'STRING' DISTRIBUTION = 'DISTRIBUTION' class MetricDescriptor(object): """Specification of a metric type and its schema. The preferred way to construct a metric descriptor object is using the :meth:`~gcloud.monitoring.client.Client.metric_descriptor` factory method of the :class:`~gcloud.monitoring.client.Client` class. :type client: :class:`gcloud.monitoring.client.Client` :param client: A client for operating on the metric descriptor. :type type_: string :param type_: The metric type including a DNS name prefix. For example: ``"compute.googleapis.com/instance/cpu/utilization"`` :type metric_kind: string :param metric_kind: The kind of measurement. It must be one of :data:`MetricKind.GAUGE`, :data:`MetricKind.DELTA`, or :data:`MetricKind.CUMULATIVE`. See :class:`MetricKind`. :type value_type: string :param value_type: The value type of the metric. It must be one of :data:`ValueType.BOOL`, :data:`ValueType.INT64`, :data:`ValueType.DOUBLE`, :data:`ValueType.STRING`, or :data:`ValueType.DISTRIBUTION`. See :class:`ValueType`. :type labels: list of :class:`~gcloud.monitoring.label.LabelDescriptor` :param labels: A sequence of zero or more label descriptors specifying the labels used to identify a specific instance of this metric. :type unit: string :param unit: An optional unit in which the metric value is reported. :type description: string :param description: An optional detailed description of the metric. :type display_name: string :param display_name: An optional concise name for the metric. :type name: string or None :param name: The "resource name" of the metric descriptor. For example: ``"projects//metricDescriptors/"``. As retrieved from the service, this will always be specified. You can and should omit it when constructing an instance for the purpose of creating a new metric descriptor. """ def __init__(self, client, type_, metric_kind=MetricKind.METRIC_KIND_UNSPECIFIED, value_type=ValueType.VALUE_TYPE_UNSPECIFIED, labels=(), unit='', description='', display_name='', name=None): self.client = client self.name = name self.type = type_ self.labels = labels self.metric_kind = metric_kind self.value_type = value_type self.unit = unit self.description = description self.display_name = display_name def create(self): """Create a new metric descriptor based on this object. Example:: >>> descriptor = client.metric_descriptor( ... 'custom.googleapis.com/my_metric', ... metric_kind=MetricKind.GAUGE, ... value_type=ValueType.DOUBLE, ... description='This is a simple example of a custom metric.') >>> descriptor.create() The metric kind must not be :data:`MetricKind.METRIC_KIND_UNSPECIFIED`, and the value type must not be :data:`ValueType.VALUE_TYPE_UNSPECIFIED`. The ``name`` attribute is ignored in preparing the creation request. All attributes are overwritten by the values received in the response (normally affecting only ``name``). """ path = '/projects/{project}/metricDescriptors/'.format( project=self.client.project) response = self.client.connection.api_request(method='POST', path=path, data=self._to_dict()) self._init_from_dict(response) def delete(self): """Delete the metric descriptor identified by this object. Example:: >>> descriptor = client.metric_descriptor( ... 'custom.googleapis.com/my_metric') >>> descriptor.delete() Only the ``client`` and ``type`` attributes are used. """ path = '/projects/{project}/metricDescriptors/{type}'.format( project=self.client.project, type=self.type) self.client.connection.api_request(method='DELETE', path=path) @classmethod def _fetch(cls, client, metric_type): """Look up a metric descriptor by type. :type client: :class:`gcloud.monitoring.client.Client` :param client: The client to use. :type metric_type: string :param metric_type: The metric type name. :rtype: :class:`MetricDescriptor` :returns: The metric descriptor instance. :raises: :class:`gcloud.exceptions.NotFound` if the metric descriptor is not found. """ path = '/projects/{project}/metricDescriptors/{type}'.format( project=client.project, type=metric_type) info = client.connection.api_request(method='GET', path=path) return cls._from_dict(client, info) @classmethod def _list(cls, client, filter_string=None, type_prefix=None): """List all metric descriptors for the project. :type client: :class:`gcloud.monitoring.client.Client` :param client: The client to use. :type filter_string: string or None :param filter_string: An optional filter expression describing the metric descriptors to be returned. See the `filter documentation`_. :type type_prefix: string or None :param type_prefix: An optional prefix constraining the selected metric types. This adds ``metric.type = starts_with("")`` to the filter. :rtype: list of :class:`MetricDescriptor` :returns: A list of metric descriptor instances. .. _filter documentation: https://cloud.google.com/monitoring/api/v3/filters """ path = '/projects/{project}/metricDescriptors/'.format( project=client.project) filters = [] if filter_string is not None: filters.append(filter_string) if type_prefix is not None: filters.append('metric.type = starts_with("{prefix}")'.format( prefix=type_prefix)) descriptors = [] page_token = None while True: params = {} if filters: params['filter'] = ' AND '.join(filters) if page_token is not None: params['pageToken'] = page_token response = client.connection.api_request( method='GET', path=path, query_params=params) for info in response.get('metricDescriptors', ()): descriptors.append(cls._from_dict(client, info)) page_token = response.get('nextPageToken') if not page_token: break return descriptors @classmethod def _from_dict(cls, client, info): """Construct a metric descriptor from the parsed JSON representation. :type client: :class:`gcloud.monitoring.client.Client` :param client: A client to be included in the returned object. :type info: dict :param info: A ``dict`` parsed from the JSON wire-format representation. :rtype: :class:`MetricDescriptor` :returns: A metric descriptor. """ descriptor = cls(client, None) descriptor._init_from_dict(info) return descriptor def _init_from_dict(self, info): """Initialize attributes from the parsed JSON representation. :type info: dict :param info: A ``dict`` parsed from the JSON wire-format representation. """ self.name = info['name'] self.type = info['type'] self.labels = tuple(LabelDescriptor._from_dict(label) for label in info.get('labels', [])) self.metric_kind = info['metricKind'] self.value_type = info['valueType'] self.unit = info.get('unit', '') self.description = info.get('description', '') self.display_name = info.get('displayName', '') def _to_dict(self): """Build a dictionary ready to be serialized to the JSON wire format. :rtype: dict :returns: A dictionary. """ info = { 'type': self.type, 'metricKind': self.metric_kind, 'valueType': self.value_type, } if self.labels: info['labels'] = [label._to_dict() for label in self.labels] if self.unit: info['unit'] = self.unit if self.description: info['description'] = self.description if self.display_name: info['displayName'] = self.display_name return info def __repr__(self): return ( '' ).format(**self.__dict__) class Metric(collections.namedtuple('Metric', 'type labels')): """A specific metric identified by specifying values for all labels. :type type: string :param type: The metric type name. :type labels: dict :param labels: A mapping from label names to values for all labels enumerated in the associated :class:`MetricDescriptor`. """ __slots__ = () @classmethod def _from_dict(cls, info): """Construct a metric object from the parsed JSON representation. :type info: dict :param info: A ``dict`` parsed from the JSON wire-format representation. :rtype: :class:`Metric` :returns: A metric object. """ return cls( type=info['type'], labels=info.get('labels', {}), )